Sign in or create a free account to continue.

ROB-330 · Lesson 6 of 12 · 29 min

Epipolar geometry and stereo vision

One image loses depth; two images taken from different positions can recover it. Humans do this with two eyes a few centimetres apart, and robots do it with stereo cameras, which remain one of the most widely used depth sensors in mobile robotics, agriculture, automotive driver assistance and planetary exploration. Stereo works passively, in sunlight where many active depth sensors struggle, and its range scales with the baseline between the cameras. This lesson first develops epipolar geometry, the constraint that links any two views of a scene, and then specializes it to the rectified stereo pair, where depth comes from a single number per pixel, the disparity.

The epipolar constraint

Consider two cameras viewing the same point \( \mathbf{X} \). The two optical centres and the point define a plane, the epipolar plane. That plane cuts each image along a line, the epipolar line. The geometric consequence is powerful: if a point appears at \( \mathbf{u} \) in the first image, its match in the second image must lie somewhere on one known line. The search for a correspondence collapses from the whole image to a one-dimensional line.

All epipolar lines in an image pass through one point, the epipole, which is the image of the other camera's optical centre (it may lie far outside the image). When a camera moves straight forward, the epipole is the focus of expansion, the point from which the scene appears to stream outwards.

Two camera centres C and C prime on the left and right, each with an image plane drawn as a tilted rectangle in front of it. A scene point X above connects to both centres. The triangle formed by C, C prime and X is shaded as the epipolar plane. The baseline joins C and C prime and crosses each image plane at an epipole marked e and e prime. In each image, the line where the epipolar plane cuts the image is drawn as the epipolar line, and the projections u and u prime of X lie on those lines.
Epipolar geometry: the two centres and the scene point define a plane whose intersections with the images are the epipolar lines

For calibrated cameras, write the motion from camera 1 to camera 2 as rotation R and translation t, and use normalized image coordinates \( \hat{\mathbf{x}} = K^{-1}\tilde{\mathbf{u}} \). The coplanarity of the two rays and the baseline gives the epipolar constraint

\[\hat{\mathbf{x}}_2^{\mathsf{T}}\, E\, \hat{\mathbf{x}}_1 = 0, \qquad E = [\mathbf{t}]_{\times} R\]

where \( [\mathbf{t}]_{\times} \) is the skew-symmetric cross-product matrix of t. E is the essential matrix, introduced by Longuet-Higgins in 1981. It has five degrees of freedom: three for rotation and two for the direction of translation, because the overall scale of t cannot be recovered from images alone. For uncalibrated pixel coordinates the same constraint holds with the fundamental matrix \( F = K_2^{-\mathsf{T}} E K_1^{-1} \), which has seven degrees of freedom. The epipolar line in image 2 for a point \( \tilde{\mathbf{u}}_1 \) is the vector \( \mathbf{l}_2 = F \tilde{\mathbf{u}}_1 \), with the line written as \( l_a u + l_b v + l_c = 0 \).

Worked problem

Checking the epipolar constraint

Camera 2 is displaced 0.1 m to the right of camera 1 with no rotation, so t = (−0.1, 0, 0) in camera 2's frame. A point has normalized coordinates (0.20, 0.10) in camera 1 and (0.15, 0.10) in camera 2. Does it satisfy the epipolar constraint?

Show solution
  1. With R = I, \( E = [\mathbf{t}]_{\times} = \begin{bmatrix} 0 & 0 & 0 \\ 0 & 0 & 0.1 \\ 0 & -0.1 & 0 \end{bmatrix} \).
  2. \( E\hat{\mathbf{x}}_1 = (0,\; 0.1 \times 1,\; -0.1 \times 0.10) = (0, 0.1, -0.01) \).
  3. \( \hat{\mathbf{x}}_2^{\mathsf{T}} E \hat{\mathbf{x}}_1 = 0.15(0) + 0.10(0.1) + 1(-0.01) = 0.01 - 0.01 = 0 \).

Answer: Yes. For a pure sideways baseline, the constraint says the two image points share the same y coordinate: the epipolar lines are horizontal rows, which is exactly the rectified stereo case.

Estimating and decomposing the essential matrix

E can be estimated from point matches. Each match gives one linear equation in E's nine entries, so eight matches give a linear solution, the eight-point algorithm of Longuet-Higgins, made reliable by Hartley's 1997 normalization of coordinates. Nistér's five-point algorithm (2004) uses the minimal five matches and is the standard choice inside RANSAC for calibrated cameras. Once E is known, it can be decomposed into R and the direction of t; the decomposition gives four candidate solutions, and the correct one is the only one that places the triangulated points in front of both cameras. Lesson 7 uses exactly this to compute camera motion.

The rectified stereo pair

A stereo camera makes the geometry as simple as possible. Its two cameras are mounted side by side with parallel optical axes, separated by a baseline B, and after calibration both images are rectified: warped so that their image planes are coplanar and their rows aligned. Then every epipolar line is a horizontal row, and a point at row v in the left image appears on row v in the right image too. The only difference is a horizontal shift, the disparity

\[d = u_L - u_R\]

By similar triangles, depth follows directly from disparity:

\[Z = \frac{f\,B}{d}\]

where f is the focal length in pixels. Near objects have large disparities and far objects small ones, approaching zero at infinity. Rectification uses the stereo calibration (the intrinsics of both cameras and the rotation and translation between them, found as in lesson 3 from simultaneous views of a target) to compute a rectifying rotation for each camera; OpenCV's stereoRectify and the ROS stereo_image_proc package do this routinely.

A top-down view of a rectified stereo pair. Two cameras sit side by side, separated by baseline B, with parallel optical axes pointing up the page and image planes at focal distance f. A scene point at depth Z projects into the left image at u L and into the right image at u R. Similar triangles are shaded and the disparity d equal to u L minus u R is marked.
A rectified stereo pair: similar triangles give depth Z = fB/d from the disparity d

Worked problem

Depth from disparity

A stereo camera has a 120 mm baseline and \( f = 700 \) px. A point has disparity 35 px. How far away is it? What disparity would a point at 10 m have?

Show solution
  1. \( Z = 700 \times 0.120/35 = 2.4 \) m.
  2. At 10 m: \( d = fB/Z = 84/10 = 8.4 \) px.

Answer: 2.4 m. At 10 m the disparity shrinks to 8.4 px, so a small disparity error becomes a large depth error, as the next section shows.

How depth error grows with distance

Differentiating \( Z = fB/d \) with respect to d shows how a disparity error \( \delta d \) becomes a depth error:

\[\delta Z = \frac{Z^2}{f\,B}\,\delta d\]

Depth error grows with the square of distance. This is the single most important fact about stereo: a sensor accurate to a few millimetres at 1 m may be uncertain by tens of centimetres at 10 m. It is also the design rule. A longer baseline or longer focal length reduces error at a given range but increases the minimum range (because near points leave one camera's view or exceed the disparity search range) and narrows the field of view. Disparity can be estimated to a fraction of a pixel with sub-pixel interpolation, typically 0.1 to 0.25 px in good texture.

Worked problem

Choosing a baseline

A field robot needs depth errors under 0.15 m at 8 m. With f = 1000 px and sub-pixel disparity accuracy of 0.25 px, what baseline is needed?

Show solution
  1. Rearrange: \( B = Z^2 \delta d/(f\, \delta Z) \).
  2. \( B = 64 \times 0.25/(1000 \times 0.15) = 16/150 = 0.107 \) m.

Answer: At least about 11 cm. A common 12 cm stereo camera would just meet the requirement; if the robot needed it at 16 m, the baseline would have to quadruple to about 43 cm.

Computing disparity: stereo matching

Finding the disparity for every pixel, dense stereo matching, means finding, for each left-image pixel, the best-matching position along the same row of the right image within a disparity range \( [0, d_{max}] \). Local methods compare small windows using a cost such as the sum of absolute differences (SAD), the sum of squared differences, normalized cross-correlation, or the census transform, which compares bit patterns of local brightness orderings and is robust to exposure differences between the cameras. The disparity with the lowest cost wins.

Local matching fails where windows are ambiguous: textureless walls, repetitive patterns, and occluded regions that one camera sees and the other does not. Global and semi-global methods add a smoothness term that penalizes disparity jumps between neighbours except at strong image edges. Semi-global matching (SGM, Hirschmüller, 2005) approximates this efficiently by aggregating costs along several directions, and it runs in real time on embedded hardware; it is the basis of many commercial stereo cameras. A left-right consistency check (match right to left as well and reject pixels whose disparities disagree) removes most occlusion errors. Learned stereo networks now produce the most accurate disparity maps on benchmarks, at higher computational cost.

Window-based stereo matching with the sum of absolute differences on a synthetic textured scene
import numpy as np
rng = np.random.default_rng(5)

H, W, dmax, win = 40, 120, 24, 5
left = rng.integers(0, 255, (H, W)).astype(float)       # random texture
true_d = np.full((H, W), 6)                              # background at disparity 6
true_d[10:30, 50:90] = 18                                # nearer box at disparity 18
right = np.zeros_like(left)
for v in range(H):
    for u in range(W):
        src = u + true_d[v, u]                           # right pixel u sees left pixel u + d
        right[v, u] = left[v, src] if src < W else rng.integers(0, 255)
right += rng.normal(0, 4, right.shape)                   # sensor noise

# shift-and-compare: right view displaced to line up with the left
hw = win // 2
best_cost = np.full((H, W), np.inf)
disp = np.zeros((H, W), int)
k = np.ones(win) / win
for d in range(dmax + 1):
    shifted = np.full_like(right, 1e6)
    shifted[:, d:] = right[:, :W - d]
    cost = np.abs(left - shifted)
    cost = np.apply_along_axis(lambda r: np.convolve(r, k, 'same'), 1, cost)   # box sum along rows
    cost = np.apply_along_axis(lambda c: np.convolve(c, k, 'same'), 0, cost)   # and columns
    better = cost < best_cost
    best_cost[better] = cost[better]
    disp[better] = d

inner = (slice(hw, H - hw), slice(dmax + hw, W - hw))
acc = (disp[inner] == true_d[inner]).mean()
print("pixels with correct disparity: %.1f %%" % (100 * acc))
print("median disparity on the box: %d (true 18)" % np.median(disp[12:28, 55:85]))
f, B = 700, 0.12
print("box depth: %.2f m, background depth: %.2f m" % (f * B / 18, f * B / 6))
Output
pixels with correct disparity: 82.9 %
median disparity on the box: 18 (true 18)
box depth: 4.67 m, background depth: 14.00 m

Note that the reference image is the left one and the matching pixel in the right image lies at \( u - d \); the code expresses this by shifting the right image d pixels to the right before comparing. Errors concentrate at the box edges, where one camera sees background that the other cannot.

Stereo in practice

Off-the-shelf stereo cameras integrate the cameras, calibration and a matching processor and output a depth image directly (ROB-220 compared them with structured light and time-of-flight sensors). Some add an infrared pattern projector to give texture to blank walls indoors, while still working passively in sunlight. When choosing or using one, check the baseline and focal length against the required range accuracy using \( \delta Z = Z^2 \delta d/(fB) \); check the minimum range; synchronize the two exposures (unsynchronized rolling-shutter cameras give false disparities on moving objects); and expect holes in the depth image on textureless, shiny, transparent and very dark surfaces.

Common mistakes

  • MistakeSearching the whole second image for a match

    InsteadSearch only along the epipolar line, or along the same row after rectification.

  • MistakeAssuming stereo depth error is constant with range

    InsteadUse \( \delta Z = Z^2 \delta d/(fB) \): error grows with the square of distance.

  • MistakeChoosing the widest baseline possible

    InsteadBalance far-range accuracy against minimum range and overlap between the views.

  • MistakeTrusting disparity on blank walls and in occluded regions

    InsteadUse texture projection, left-right checks and confidence masks, and treat holes as unknown.

  • MistakeExpecting the essential matrix to give the true length of the translation

    InsteadRemember that E gives only the direction of t; scale needs another source.

Summary and key terms

  • Two optical centres and a scene point form an epipolar plane, so a match must lie on a known epipolar line.
  • For calibrated cameras the constraint is \( \hat{\mathbf{x}}_2^{\mathsf{T}} E \hat{\mathbf{x}}_1 = 0 \) with \( E = [\mathbf{t}]_{\times} R \); uncalibrated, it uses F.
  • E has five degrees of freedom and is estimated with the five-point or eight-point algorithm inside RANSAC.
  • Rectified stereo aligns epipolar lines with rows, so depth is \( Z = fB/d \) from disparity.
  • Depth error grows as \( Z^2 \), set by baseline, focal length and sub-pixel disparity accuracy.
  • Stereo matching compares windows along rows; semi-global matching adds smoothness for real-time dense results.
  • Textureless, reflective and occluded regions produce holes that robots must treat as unknown.
Epipolar plane
The plane through both optical centres and a scene point.
Epipolar line
The line in one image on which a point's match in the other image must lie.
Epipole
The image of one camera's optical centre in the other camera.
Essential matrix
The matrix relating normalized coordinates of matches in two calibrated views.
Fundamental matrix
The matrix relating pixel coordinates of matches in two uncalibrated views.
Baseline
The distance between the optical centres of two cameras.
Rectification
Warping a stereo pair so epipolar lines become aligned image rows.
Disparity
The horizontal shift of a point between rectified left and right images.
Semi-global matching
A stereo algorithm aggregating matching costs along several directions with smoothness penalties.
Census transform
A matching cost based on local patterns of brighter and darker pixels.

Practice problems

Work each problem on paper first, then reveal the answer to check.

  1. In rectified stereo, along what does the search for a match run?

    Show answer

    The same image row.

  2. f = 800 px, B = 0.1 m, d = 20 px: what is Z?

    Show answer

    4 m.

  3. If distance doubles, by what factor does stereo depth error grow?

    Show answer

    Four.

  4. How many degrees of freedom does E have?

    Show answer

    Five.

  5. Why can't E give the length of the translation?

    Show answer

    Images are unchanged if the scene and translation are scaled together.

  6. How many solutions does decomposing E give, and how is one chosen?

    Show answer

    Four; the one with points in front of both cameras.

  7. What does a left-right consistency check remove?

    Show answer

    Mostly occlusion and mismatch errors.

  8. Which matching cost tolerates exposure differences between cameras?

    Show answer

    The census transform (or normalized cross-correlation).

  9. Where is the epipole for a camera moving straight forward?

    Show answer

    At the focus of expansion.

  10. Name a surface type on which stereo often fails.

    Show answer

    Textureless, shiny, transparent or very dark surfaces.

Lesson quiz · 5 questions

Score 60% or more to complete this lesson.

Take the quiz