Two ordinary USB cameras and OpenCV are enough to measure distance: depth is the focal length in pixels, times the baseline, divided by disparity, and every millimetre of accuracy comes from hardware numbers you fix before writing code. This guide gives the formula, sizes a rig for a 2 m ranging task with the arithmetic shown, walks the sync and calibration steps that set the real error, and states when to stop and buy a factory-built 3D sensor instead. The area scan cameras and cables named here are the parts that hold up on a line.
The decision in one line
Point two identical cameras in parallel on a rigid rail. The same world point lands at two horizontal positions; their difference is the disparity d, in pixels, and the distance is one division:
Z is depth in the unit of the baseline B, f_px is focal length in pixels, f is the lens focal length, p is the sensor pixel pitch, and ΔZ is the depth error caused by disparity noise Δd. For the unit story behind f_px, read why focal length is quoted in pixels.
The two lines give the whole decision. Error falls linearly with baseline and focal length and rises with the square of distance: double the baseline and every range gets twice as accurate; double the distance and the error quadruples. For ranging a part between 0.5 m and 3.5 m with about 2–20 mm of error, build it from two matched USB3 cameras, a 100–200 mm baseline and 6 mm-class lenses, and calibrate with a checkerboard. For sub-millimetre height at a fixed station, or past about 5 m, no webcam rig qualifies — that is laser-profiler or factory-stereo work.
Worked example: ranging a box at 2 m with a 100 mm baseline
The inputs for a typical webcam-class build; swap in your sensor's pixel pitch and lens:
- two identical USB3 cameras, 1600 × 1200 pixels, pixel pitch p = 4.2 µm
- two 6 mm lenses, focus and aperture locked
- baseline B = 100 mm on a rigid rail
- target at Z = 2000 mm
- disparity noise Δd = 0.25 pixel from subpixel matching on a textured surface
The arithmetic:
- f_px = 6 mm / 0.0042 mm = 1429 pixels
- d = f_px × B / Z = 1429 × 100 / 2000 ≈ 71 pixels, a comfortable mid-range disparity
- one disparity pixel at 2 m: ΔZ = Z² / (f_px × B) = 4,000,000 / 142,900 ≈ 28 mm
- at 0.25 pixel of noise: 28 × 0.25 ≈ 7 mm of depth error
- the range where 0.25 pixel costs 20 mm: Z = √(20 × 142,900 / 0.25) ≈ 3.4 m
The decision: this rig is a 1.1–3.4 m rangefinder with about 7 mm of depth noise at 2 m. Past 3.5 m, or below 10 mm of error, widen the baseline or change sensor class — no amount of code fixes the physics. The near limit is the disparity search range: at 128 pixels of search, Z_min = 1429 × 100 / 128 ≈ 1.1 m, and doubling the search to 256 pixels reaches about 0.6 m, so set the range to cover your closest approach.
Choosing the baseline: one table decides it
With the same 6 mm lens and 4.2 µm pixels, depth error per disparity pixel is:
| Baseline | ΔZ at 1 m | ΔZ at 2 m | ΔZ at 3 m |
|---|---|---|---|
| 100 mm | 7.0 mm | 28 mm | 63 mm |
| 200 mm | 3.5 mm | 14 mm | 32 mm |
| 400 mm | 1.8 mm | 7.0 mm | 16 mm |
Divide those by four for 0.25-pixel subpixel matching. Size the baseline from the error target: B = Z² × Δd / (f_px × ΔZ). For ±10 mm at 2 m that gives 2000² × 0.25 / (1429 × 10) = 70 mm — a floor, not a target, because calibration residual and sync skew eat into it; take 100–150 mm and keep margin. Choosing a stereo camera baseline goes deeper into mounting, and long-range stereo with a wide baseline covers what changes past several metres.
Field of view and the near limit
The lens decides how much each camera sees: FOV = 2 × atan(sensor width / (2 × f)). The example sensor is 1600 × 4.2 µm = 6.72 mm wide, so a 6 mm lens gives 2 × atan(6.72 / 12) ≈ 58° across. Both cameras must see the part at once, and the common field narrows to a strip at close range — why sensor size and focal length set the field of view draws the geometry, and minimum distance versus field of view is the same trade on a depth camera.
Work the focal length backwards from the space you have; the calculator below lands on a focal length and opens the shop finder at it.
Two USB cameras: ports, sync and motion
Give each camera its own USB host controller rather than two ports on one hub. What happens to bandwidth and frame timing when several USB cameras run at once is covered in acquiring from multiple USB cameras.
On a static scene, sync is optional: grab both frames, match, done. On a moving part, sync is accuracy. A part at 100 mm/s with 10 ms of shutter skew moves 1 mm between frames; at 2 m with the example lens that is a 0.7-pixel image shift, which reads as about 20 mm of depth error. Trigger both cameras from one hardware line and prefer global-shutter sensors, so every row of both frames shares one instant. Match exposure as well: setting auto exposure per stereo camera keeps the pair balanced.
Two builds cover most requests:
- Sensor format
- 1/1.7"
- Interface
- USB3
- Sensor format
- 1.1"
- Lens mount
- C-mount
The LS-CMR-0166 is a 12 MP USB3 camera with a 4000 × 3000 resolution at 30 fps; buy two, lock focus and aperture, then calibrate. The MV-CH120-11UC is a 12 MP USB3 camera with a global shutter and a C-mount — the pair to wire to a shared trigger line. Filter the camera finder on USB3 and global shutter, or run the camera step of the configurator with your range and error target.
Give each camera its own flex-rated cable if the rig moves:
The LS-CBL-0219 is a 3 m USB3.0 camera cable built for drag-chain use; a pair of equal lengths keeps the wiring symmetric.
Calibration is the accuracy
Calibration converts pixel matches into millimetres, and its residual sets a floor under the whole system. Print a checkerboard, measure the square size with calipers, and capture 15–30 pairs with the board tilted and spread across the working volume — the measurement volume decides stereo calibration accuracy, so fill the volume you will actually use. Calibrate each camera's intrinsics first, then the pair. A practical target is an average reprojection error below 0.5 pixel; below 0.2 pixel is excellent.
Read the result per camera: the stereo depth scale factor and focal length. The printed focal length never goes into the formula — the calibrated value in pixels does. And if the lenses are wider than about 160°, the pinhole model breaks down and the fisheye calibration path takes over.
From disparity to millimetres you can trust
Block matching gives a disparity value per pixel; OpenCV's reprojection turns it into 3D points under one rule: the output unit is the unit of the baseline you entered. Enter B in millimetres and Z comes out in millimetres — mix units once and every distance is wrong by the ratio. How the disparity map is computed explains the matching stage, and stereo disparity to depth conversion covers placing the depth window so your range lands mid-disparity.
Prove the rig against a tape measure: put a flat, textured target at a measured 1.0 m and 2.0 m and read both. Readings outside three times the predicted error — about ±21 mm at 2 m on the example rig — point at calibration or sync, not at the formula. When the numbers must be traceable, know difference between an accuracy certificate and a calibration certificate before you quote them to a customer.
When two webcams are the wrong tool
Stereo needs texture to match, and the error climbs steeply with range. Pass on a webcam rig when the part is glossy or plain, when you need sub-millimetre height at a fixed station, or when the range runs past about 5 m — choosing a 2D or 3D camera for conveyor pick and place walks the same decision on a conveyor. Factory-built 3D sensors keep their calibration and ship with matched optics:
- Type
- Stereo / structured light
The MV-DLS300P-04 is a laser galvanometer stereo camera: single housing, factory calibration, projected structure where texture is missing. For height, gap and flushness on parts that stop under a station, a laser profile sensor is the stronger tool — triangulation on a projected line, no surface pattern required. The projector is a laser product: respect the class marking and the stated viewing-distance rules.
Checklist before you order
- Write the range and error target down (Z and ΔZ), then compute B = Z² × Δd / (f_px × ΔZ) with margin — baseline is the cheapest accuracy you can buy.
- Buy two identical cameras and two identical lenses; global shutter if anything moves.
- Take the pixel pitch from the sensor data sheet — it drives f_px and therefore every number above.
- Put the cameras on a slotted rail, and record the spacing you set.
- One USB host controller per camera, equal cable lengths.
- Wire one hardware trigger line to both cameras.
- Print the checkerboard, measure the squares, plan 15–30 pairs across the working volume.
- Run the tape-measure acceptance test at two known distances before production use.
- Shortlist a 3D sensor now, with the error threshold that would switch you to it.
Run the configurator from the camera step, or send the range and error target through the contact page and we will size the rig with you. More stereo guides sit on the 3D topic page.
Questions
How accurate is distance from two USB cameras at 5 m?
Depth error grows with the square of distance, so 5 m hurts. With the example rig — 6 mm lens, 4.2 µm pixels, 100 mm baseline — one disparity pixel is about 175 mm at 5 m, and 0.25-pixel subpixel matching still leaves about 44 mm. Widening the baseline to 500 mm brings that near 9 mm, at the cost of a bulkier rig and a smaller common field of view. Below roughly 10 mm at 5 m, use a wide-baseline rig on a frame or a dedicated 3D sensor.
Do both cameras need to be the same model?
Yes. Identical models keep the focal length, sensor response and exposure controls matched, so both images of one point have the same brightness and blur. OpenCV calibrates mismatched cameras too, but a different field of view or a different rolling-shutter readout shows up as disparity bias you cannot calibrate out. Buy two of the same camera and lens, lock focus and aperture before calibrating, and set exposure per camera so neither image saturates.
What baseline gives ±10 mm at 2 m?
B = Z² × Δd / (f_px × ΔZ). With a 6 mm lens and 4.2 µm pixels, f_px ≈ 1429 pixels, so the floor is 2000² × 0.25 / (1429 × 10) = 70 mm. That assumes 0.25-pixel disparity noise, which calibration residual and sync skew eat into, so 100 to 150 mm is the practical choice and 200 mm gives margin. If your matcher only achieves 1-pixel noise, the requirement jumps to 280 mm.
How do I synchronize two USB cameras?
For a static scene you do not: grab both frames, match them, proceed. For moving parts sync is accuracy — a 100 mm/s part skewing 10 ms between shutters costs about 20 mm of depth error at 2 m. Use cameras with a hardware trigger input and wire one pulse to both; global-shutter sensors make every row share one instant. Where a trigger is impossible, pair frames by timestamp and reject pairs whose capture times differ by more than a millisecond.
Stereo rig or laser profiler for a fixed measuring station?
Stereo wins where you need a wide field, color images and distances from a few hundred millimetres to several metres at millimetre-to-centimetre error. A laser profile sensor wins on a fixed station that needs repeatable sub-millimetre heights: it measures one line by triangulation instead of matching texture, so surface pattern does not matter. Use stereo for ranging and volume; use a profiler for height, gap and flushness on parts that stop under it.



