Light-plane triangulation

Replace one of the two stereo cameras with a light source whose geometry is known: a laser that projects a thin plane of light. Every bright pixel in the camera image lies on that plane, so its depth follows from one ray–plane intersection, with no search for correspondences. Sweep the plane over the scene to build up the surface, and see what happens when several stripes are projected at once to save time.

Camera, projector and the light planes of this frame drag to orbit, scroll to zoom light plane reconstructed point wrong stripe
Camera image, frame click a stripe to select a point detected peak assigned to the wrong plane
Depth of all points so far bright = near depth off by more than 2 cm

Active instead of passive

Stereo with two cameras is passive: it works with whatever light the scene reflects, and the hard part is correspondence, finding the same point in both images. On a white wall there is nothing to match. Active methods add light of known geometry. A projector is an inverse camera: instead of receiving a ray through each pixel, it sends one out. If we know which projector pixel lit a camera pixel, the two rays can be intersected exactly as in stereo, and the projector supplies the texture.

The light plane

A laser line, or one column of a projector, lights a plane through the projector center. After calibration, its equation in camera coordinates is known:

Ax+By+Cz+D=0A x + B y + C z + D = 0

A bright pixel at (x′,y′)(x', y'), measured from the principal point, sees the camera ray x=x′z/fx = x' z / f, y=y′z/fy = y' z / f. Substituting it into the plane equation gives

Ax′zf+By′zf+Cz+D=0⇒z=−DfAx′+By′+CfA \frac{x' z}{f} + B \frac{y' z}{f} + C z + D = 0 \quad\Rightarrow\quad z = \frac{-D f}{A x' + B y' + C f}

and the 3D point is (x′z/f, y′z/f, z)(x' z / f,\ y' z / f,\ z). One frame gives one profile: the curve where the plane cuts the surface. Moving the plane across the scene, by turning a mirror or moving the object on a turntable, gives the whole surface, one profile per frame.

Finding the stripe

The laser has to be found in every row. Subtracting an image taken with the laser off removes the scene's own shading; then each local maximum above a threshold is a stripe. A parabola through the maximum and its two neighbors places the peak to a fraction of a pixel: for values a,c,ba, c, b the center is shifted by δ=(a−b)/(2(a−2c+b))\delta = (a - b) / (2(a - 2c + b)). Where the projector cannot reach, in the shadows to the left of the sphere and the box, there is no stripe, and no depth.

Speed vs robustness

One stripe per frame is slow: NN profiles need NN frames, and the scene must not move in between. Projecting KK stripes at once needs only N/KN/K frames, but now each peak must be matched to one of the KK planes. The obvious rule is to count from the left: the projector is to the right of the camera, and on a surface without occlusions the stripes keep their order. Where a stripe is missing, in a shadow or behind an object, every stripe to its right is assigned to the wrong plane, and its points end up far from the surface.

There are two ways out. Multi-frame patterns give every projector column a code that is spread over a few frames, such as binary and Gray codes: nn frames tell 2n2^n columns apart. Single-frame patterns make every part of one image unique, with stripes in a color sequence that never repeats or with a random dot pattern; they work on moving scenes, but a local patch has to be decoded correctly, which fails more easily on colored or strongly slanted surfaces.

Try this