3D visionExplainer

Stereo depth height overestimation from disparity quantization

Why background-minus-object height reads a few mm tall at close range: the Z²·Δd/(f·B) quantization rule, a worked example, and the fixes that hold tolerance.

LumaSpec Vision10 min read Share on LinkedIn

On this page 8 sections
  1. 01Where the extra millimetres come from
  2. 02Two snapped surfaces, one height
  3. 03Diagnose it on your bench
  4. 04The fixes, in order of effort
  5. 05What accuracy to expect
  6. 06When stereo is the wrong sensor class
  7. 07The decision, case by case
  8. 08Questions

A stack that measures 144.5 mm with calipers reads 152.0 mm from the depth image. The camera is calibrated, the part sits square to the sensor, and the number still lands seven millimetres tall. That is the signature of disparity quantization: a stereo depth camera resolves depth in steps, and at half a metre those steps are several millimetres wide. This page gives you the error formula, a worked example with the arithmetic shown, a three-check bench diagnosis, and the fixes in order of effort — plus the point at which stereo is the wrong sensor class for the job.

You meet this bias wherever a height is computed as a difference of two absolute depths: stack height before labeling, fill level in a tray, part presence on a pallet. The example that anchors this article is a stack series from 10 to 155 mm read against a background at roughly 522 mm. The short stacks come out close to truth; the tall ones drift up to about 7 mm high, and the error jumps up and down between levels instead of growing smoothly. Nothing is broken. The measurement method is hitting the camera's depth resolution.

Where the extra millimetres come from

A stereo camera triangulates depth from the shift between its two images: Z = f·B/d, where f is the focal length in pixels, B is the baseline, d is the disparity in pixels, and Z is distance along the optical axis. The matching engine reports d only as well as it can. Many engines snap disparity to whole or half pixels, and even a good sub-pixel estimator scatters around the true value rather than hitting it.

Differentiate Z = f·B/d and the depth error falls straight out:

Z = f·B/d ΔZ ≈ Z²·Δd/(f·B) s(Z) = Z²/(f·B) depth change per one pixel of disparity

The Z² term is the whole story: double the working distance and each disparity pixel becomes four times as much depth. Take a compact wide-angle rig with f = 400 px and B = 75 mm, so f·B = 30,000 mm·px — example inputs for the arithmetic, not a product specification. One disparity pixel at 522 mm is then worth about 9 mm of depth, and a half-pixel snap moves a surface roughly 4.5 mm. The depth value versus true distance guide covers the same conversion geometry from the pixel side.

Two snapped surfaces, one height

Height from a depth image is a difference: h = Z_bg − Z_obj, background depth minus part-top depth. Each depth carries its own snapping error of up to half a pixel, so the height error is bounded by the two half-steps summed:

|Δh| ≤ s(Z_bg)/2 + s(Z_obj)/2

Worked example, with the rig above:

  • Background at Z_bg = 522 mm: s = 522²/30,000 = 272,484/30,000 ≈ 9.1 mm per pixel, so one snapped surface moves ±4.5 mm.
  • A true stack of 144.5 mm puts the top at 522 − 144.5 = 377.5 mm: s = 377.5²/30,000 = 142,506/30,000 ≈ 4.8 mm per pixel, ±2.4 mm per surface.
  • Bound on the height: 4.5 + 2.4 ≈ ±6.9 mm. A reading of 152.0 mm against a true 144.5 mm is +7.5 mm, which sits at that bound once the few millimetres of uncertainty in the exact background distance are included. Quantization explains it; nothing else needs to be wrong.
  • The short stack reads low for the same reason. A 10.05 mm stack tops out at 512 mm: s = 512²/30,000 = 262,144/30,000 ≈ 8.7 mm per pixel, so the difference can wander anywhere within about ±8.9 mm, and −1.0 mm is comfortably inside.
  • The stack itself spans 30,000 × 144.5/(522 × 377.5) ≈ 22 px of disparity. Snapping re-places each end by up to half a pixel, and which side of the pixel each true disparity falls on decides the sign. That is why the bias jumps between stack levels instead of tracking them.

Diagnose it on your bench

  1. Compute the step. Take f and B from the camera's calibration, compute s(Z_bg) and s(Z_obj), and compare the observed per-step bias with the bound above. Errors inside ±(s_bg/2 + s_obj/2) are quantization; errors well outside point elsewhere.
  2. Histogram the fractional disparity. Export disparities across the background and the top face, subtract the nearest integer, and plot. A working sub-pixel engine spreads the values across the range; when most of them sit within an eighth of a pixel of zero, the engine is snapping to its grid.
  3. Measure gauge stacks. Repeat the measurement on stacks of known height at the production stand-off. A few millimetres of scatter that collapses when you average a patch confirms quantization. A smooth offset that grows with distance points to calibration instead — the disparity scale and calibration guide shows that fingerprint.

Each failure mode leaves a different trace. Tilt shows as a slope across the surface, a wrong f or B scales depth smoothly with distance, and RGB-alignment errors move the height only in the overlaid image. Quantization alone wanders inside a fixed bound, which is exactly the up-and-down pattern above.

The fixes, in order of effort

1. Turn on sub-pixel disparity output. Most stereo SDKs ship a sub-pixel refinement switch and can output fractional disparity. If your depth arrays arrive as integers or halves, enable it and rerun the histogram. On a textured surface this moves the per-surface error from ±0.5 px toward ±0.125 px — at the example stand-off, from ±6.9 mm to ±0.125 × 13.8 ≈ ±1.7 mm on the height.

2. Average over a flat patch or plane-fit both surfaces. Averaging N pixels whose snapping errors are independent shrinks the contribution toward (half-step)/√N. A 20 × 20 patch gives 4.5/√400 = 0.23 mm per surface, roughly 0.3 mm on the height difference. The requirement is texture across the patch — a bare, fronto-parallel face can snap as one block, making the patch one sample instead of 400. Turn the projector on and pass the histogram test first. The height difference from a point cloud guide walks the plane-to-plane method.

3. Shorten the stand-off. The step scales with Z², so distance pays quadratically. Moving the background from 522 mm to 350 mm cuts the step to 350²/30,000 = 122,500/30,000 ≈ 4.1 mm per pixel; 300 mm gives 3.0 mm. Stay inside the camera's minimum working distance and the disparity search range — the 3D camera working distance guide covers placement.

4. Lengthen the baseline or narrow the field. Doubling B doubles f·B and halves the step. A narrower field of view raises f in pixels with the same effect. The cost is stereo overlap and more occlusion at close range, which the stereo baseline distance guide works through.

5. Prove it on gauges. After each change, rerun the stack test and plot measured minus true. A fix that works pulls the scatter inside the new, smaller bound and keeps it there across shifts.

Two limits sit next to this analysis. Flying pixels at object-to-background edges corrupt the boundary region, so average the flat interior and never the rim. And stereo edges deform with distance — the same Z² pressure acting on boundaries rather than flat faces.

What accuracy to expect

Committed numbers for the example rig at a 522 mm background, 144.5 mm stack:

Disparity error per surface Height error bound Reached by
±0.5 px ±6.9 mm integer snapping, single pixel pair
±0.25 px ±3.5 mm half-pixel output
±0.125 px ±1.7 mm sub-pixel on, textured surface
≈ ±0.02 px effective ≈ ±0.3 mm plane fit over a 400-pixel patch

To hold ±1 mm at this stand-off, both surfaces need disparity within 30,000/(272,484 + 142,506) ≈ 0.07 px. Only patch averaging reaches that; no single reading does. Move the same stack to a 250 mm background and the requirement relaxes: s_bg = 250²/30,000 = 2.1 mm per pixel, the top sits at 105.5 mm where s = 11,130/30,000 ≈ 0.37 mm, and 30,000/(62,500 + 11,130) ≈ 0.41 px of disparity holds ±1 mm — inside what ordinary sub-pixel output delivers on a textured face.

When stereo is the wrong sensor class

When the tolerance is tighter than one depth step, or the top face is too small or too curved to average over, change how height is measured rather than fighting the matching engine. A laser profile sensor triangulates each point from where a projected laser line lands on its sensor, so disparity quantization never enters the measurement, and every profile carries the full cross-section instead of one plane-to-plane number.

3D sensorsHikrobot MIS-DP3850-01P 3D laser profile sensorMIS-DP3850-01P
Type
Laser profiler
$12,379.00 · quotedView and quote

Where the tolerance runs to single millimetres and the surface is wide enough to average, projected structured light keeps stereo's full-field capture in one shot and adds the active texture that keeps sub-pixel matching from snapping to its grid.

3D sensorsHikrobot MV-DPS200P-02 Projected structured-light 3D cameraMV-DPS200P-02
Type
Stereo / structured light
$8,829.00 · quotedView and quote

For long parts, or several heights along a travel path, a laser galvanometer stereo camera steers the line across the part while the stereo pair watches it.

3D sensorsHikrobot MV-DLS300P-04 Laser galvanometer stereo cameraMV-DLS300P-04
Type
Stereo / structured light
$16,579.00 · quotedView and quote

The decision, case by case

  • Tolerance ±5 mm or looser, flat tops, stand-off near 0.5 m: stereo works. Plane-fit both surfaces, projector on, and the quantization contribution drops below half a millimetre.
  • Tolerance ±1 to ±2 mm: keep stereo, but enable sub-pixel output, average the patch, and shorten the stand-off to 350 mm or double the baseline. Prove it on gauge stacks before it runs production.
  • Tolerance tighter than ±1 mm, or small and curved tops: move to a laser profiler or a structured-light scanner; stereo height will not hold.
  • Before promising any tolerance: compute s = Z²/(f·B) at your stand-off. Half the step larger than the tolerance means no parameter tweak rescues a single-pixel reading — average, move closer, or change sensor class.

The 3D sensors category gathers laser profilers, structured-light and stereo cameras side by side, and the camera finder filters them by type and range. If you want the quantization math checked against your own stand-off and baseline, contact the applications team with those two numbers and the tolerance.

Build the whole station

The configurator matches a camera, lens, light, light controller and cables to each other, step by step, and lists only parts that fit what you already picked.

Start with the camera

Questions

How do I compute the depth step for my stereo camera?

Take f and B from the camera's calibration and divide the squared distance by their product: s = Z²/(f·B). With f·B = 30,000 mm·px, a background at 1,000 mm gives s = 1,000,000/30,000 = 33 mm per disparity pixel, so a half-pixel snap is about 17 mm of depth. The same rig at 500 mm steps 8.3 mm per pixel. Distance enters squared, which is why close-range heights are the sensitive ones.

Does patch averaging still work when every pixel snaps to the same integer?

No. The √N reduction assumes the snapping differs from pixel to pixel, which takes texture or projector light on the surface. Histogram the fractional disparity across the patch first: if nearly every value sits within an eighth of a pixel of an integer, the effective sample count is one and the plane fit inherits the full millimetre-scale bias. Add texture, raise the projector output, or enable a finer sub-pixel mode before averaging.

Is RGB-aligned depth less accurate than native depth for height?

Alignment resamples the depth map onto the colour camera's pixel grid and does not change the disparities underneath, so height from the same region agrees within a resampling pixel or two. If your height changes when you switch alignment, suspect the depth-to-RGB extrinsic, not quantization. The bias described here appears identically in both streams because both are built from the same disparity result.

How much does a longer baseline buy for close-range height?

The step scales as Z²/(f·B), so doubling the baseline halves it. The worked rig steps 9.1 mm per disparity pixel with B = 75 mm at a 522 mm background; at B = 150 mm the same geometry steps 4.5 mm. Longer baselines cost overlap and add occlusion at close range, so check the minimum working distance of the wider pair before committing.

When should height measurement move from stereo to a laser profiler?

When the tolerance is tighter than about one depth step s = Z²/(f·B) at your stand-off, or the top face is too small or curved to average over. A profiler triangulates each point from the laser line's position on its sensor, so disparity never enters the chain, and each scan rebuilds the whole cross-section instead of one plane-to-plane distance.