Stereo calibration workflow¶
This is the practical, step-by-step guide from calibration images to a
3-component \((u, v, w)\) velocity field. The theory behind every step —
calibration models, Soloff reconstruction, disparity correction — is on the
stereo theory page. Examples/stereo_tutorial.py
runs this whole pipeline on a public dataset (the 4th PIV Challenge case E,
downloaded automatically on first run by
download_pivchallenge_E(), ~197 MB).
What you need¶
Calibration images of a dual-plane target (TSI or LaVision) from both cameras. A dual-plane target provides two \(Z\) levels per image, which is already the minimum for the reduced (9-term) model; the full 19-term Soloff model needs ≥ 3 distinct \(Z\) planes, so traverse the target and take one image per position. The flat single-plane Quadricle target cannot constrain the out-of-plane parallax: the Soloff maps come out NaN and the GUI reports “Soloff maps: NOT available”.
Flow image pairs from both cameras, simultaneous between cameras.
The PIV parameters you would use for a planar measurement (both cameras share the same
Parameters).
1. Launch the calibration GUI¶
import dpivsoft.stereo_gui as gui
gui.calibration_GUI() # blocks until the window is closed
2. Enter the target geometry¶
In the options panel, set the dot spacings and the camera arrangement:
dx— in-row dot pitch of one level (mm).dy— spacing between adjacent image rows (mm). For LaVision targets the two \(Z\) levels interleave row by row, so this is half the per-level pitch — a LaVision Type #21 plate (15 mm pitch) needsdx = 15,dy = 7.5,dz = 3. Gettingdywrong is undetectable in the fit RMS (the polynomial absorbs a linear stretch) but scales the reconstructed \(Y\) and \(v\) — the one field worth double-checking.dz— the out-of-plane offset between the target’s two dot levels (mm).Camera configuration — Front-Front (both cameras on the same side of the sheet) or Front-Back (opposite sides). This is baked into the fitted maps and saved with the calibration.
3. Per image: detect, sort, save¶
For each calibration image (each camera, each traverse position):
Load the image and adjust the threshold / cleaning until the dots are isolated blobs.
Get centroids — dots clipped by the image border are dropped automatically (their centroids are biased).
Sort points — assigns each dot absolute lattice
(row, col)labels by a predictive lattice walk seeded at the origin fiducial. Missing or undetected dots stay holes instead of shifting the labels of every dot after them; rotations up to ~25° and perspective are handled.Calibration mesh — assigns world coordinates \((X, Y, Z)\) from the lattice labels, the spacings entered in §2, and the plane’s \(Z\) position.
Save the CPT — a plain-text file with one
x y X Y Zline per dot. CPTs are the checkpoint of the workflow: reloading them skips detection and sorting entirely on later runs.
For a multi-plane calibration, save one CPT per plane and load them together with the GUI’s load multi CPT option so the fit sees the full depth range.
4. Fit the calibration (“Soloff Calculation”)¶
The toolbar button opens a popup to choose the model and run
stereo_calibration():
reduced (9-term, default) — needs ≥ 2 distinct \(Z\) planes.
full (19-term classic Soloff) — needs ≥ 3 distinct \(Z\) planes; the GUI refuses to run it with fewer. Worth it when the optics have real lens distortion or \(Z\)-curvature — see when does the full model help?
The results line reports the model, the forward-fit RMS (mm), the Soloff-map
reprojection RMS (px), and whether the Soloff maps are available. Save the
calibration .npz; it carries everything reconstruction needs, including the
camera configuration and the model (auto-detected from the coefficient length
when loaded).
5. PIV on the raw images¶
Process each camera’s pair sequence with the ordinary 2-D pipeline (GPU or
CPU), using the same Parameters for both cameras. Do not dewarp the
images first — the Soloff reconstruction works directly on raw-image
displacements.
6. Reconstruct the three components¶
from dpivsoft.Classes import Parameters
import dpivsoft.stereo_DPIV as Stereo
calibration = Parameters.Stereo_Calibration("stereo_calibration.npz")
X, Y, U, V, W = Stereo.soloff_velocity(
x_l, y_l, u_l, v_l, # left-camera PIV field (raw-image pixels)
x_r, y_r, u_r, v_r, # right-camera PIV field
calibration, img_shape,
delta_z=None) # None = reconstruct at Z=0
Sign convention: positive \(w\) points toward the right camera.
7. Optional: Δz self-calibration¶
Even a good calibration leaves a small offset between the laser sheet and the calibration plane, which biases \(w\). To correct it (theory in §10 of the stereo page):
Build the common world grid (
make_world_grid()) and dewarp a series of same-instant frame pairs from both cameras onto it at \(Z = 0\) (backproject_folder()).Ensemble cross-correlate the two dewarped series (
compute_disparity()) — frame \(i\) of camera 1 against frame \(i\) of camera 2, not the consecutive PIV pairing.Convert the disparity to a \(\Delta z(X, Y)\) field (
disparity_to_delta_z()), withsurface_order=2recommended (fits a quadratic surface: keeps sheet tilt and curvature, rejects per-point noise).Pass the field to
soloff_velocity(..., delta_z=...). Iterating (re-dewarp at the accumulated \(\Delta z\), re-measure) should shrink the residual disparity each pass —disparity_convergence_report()prints the check.
stereo_tutorial.py implements this loop behind the RUN_DISPARITY /
DISP_SURFACE_ORDER / N_DISP_ITER constants.
Status and honest caveats¶
The stereo pipeline is functional but newer than the 2-D core. A synthetic end-to-end validation (known \(w\) field → calibration → PIV → reconstruction) recovers \(w\) to within a few percent, and the disparity self-calibration converges (residual shrinks each iteration), which confirms its sign and self-consistency. Still open: the absolute \(\Delta z\) / \(w\) magnitude has not been checked against an independent experimental ground truth, and the Front-Back \(w\) sign cannot be verified synthetically — it awaits a real known-\(w\) case. Treat quantitative \(w\) from Front-Back arrangements with appropriate care.