Tiefe und 3D
Wie aus zwei Bildern eine Entfernung wird: Stereo, Disparität, Punktwolken und die Frage, wann eine Kamera einen Laserscanner ersetzt.
Die Idee
Halten Sie einen Finger vor die Nase und schließen Sie abwechselnd ein Auge. Der Finger springt weit, ein Gegenstand am anderen Ende des Raumes kaum. Dieses Springen heißt Disparität, und es ist umgekehrt proportional zur Entfernung.
Zwei Kameras in bekanntem Abstand machen genau das systematisch.
Wozu es gut ist
- Volumen einer Palette bestimmen.
- Roboterarme greifen lassen.
- Prüfen, ob ein Bauteil richtig sitzt.
- Räume vermessen, ohne Maßband.
Kalibrierung und Tiefenkarte
import cv2, numpy as np
# 1. Kalibrierung mit einem Schachbrett - einmal je Kameraaufbau.
# Mindestens 20 Aufnahmen aus verschiedenen Winkeln und Entfernungen.
muster = (9, 6)
objp = np.zeros((muster[0] * muster[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:muster[0], 0:muster[1]].T.reshape(-1, 2) * 25.0 # 25 mm
# 2. Tiefenkarte aus einem kalibrierten Stereopaar.
links = cv2.imread("links.png", cv2.IMREAD_GRAYSCALE)
rechts = cv2.imread("rechts.png", cv2.IMREAD_GRAYSCALE)
stereo = cv2.StereoSGBM_create(
minDisparity=0, numDisparities=128, # muss durch 16 teilbar sein
blockSize=5, P1=8 * 5 ** 2, P2=32 * 5 ** 2,
uniquenessRatio=10, speckleWindowSize=100, speckleRange=2)
# SGBM liefert Disparitaet in 1/16 Pixel als int16.
disp = stereo.compute(links, rechts).astype(np.float32) / 16.0
f, B = 700.0, 120.0 # Brennweite in px, Basis in mm
with np.errstate(divide="ignore"):
tiefe_mm = np.where(disp > 0, f * B / disp, 0)- Die Kalibrierung gilt nur für diesen Aufbau. Jede Verschiebung einer Kamera macht sie ungültig.
- Beide Kameras müssen synchron auslösen; bei bewegten Szenen sonst systematisch falsch.
- Die Anzahl der Disparitätsstufen bestimmt den messbaren Nahbereich und die Rechenzeit.
- Ergebnisse ohne gültige Disparität sind null, nicht unendlich. Diese Punkte gehören maskiert.
Die Grundgleichung
Durchgerechnet
Mit f = 700 Pixel, B = 120 mm und Δd = 0,5 Pixel:
| Entfernung Z | Disparität d | Tiefenfehler ΔZ | relativ |
|---|---|---|---|
| 1 m | 84,0 px | 6 mm | 0,6 % |
| 2 m | 42,0 px | 24 mm | 1,2 % |
| 5 m | 16,8 px | 149 mm | 3,0 % |
| 10 m | 8,4 px | 595 mm | 6,0 % |
| 20 m | 4,2 px | 2.381 mm | 11,9 % |
Daraus folgt die Auslegungsregel: Wer auf zehn Metern zehn Zentimeter genau
messen will, braucht B von rund 700 mm oder eine deutlich längere Brennweite.
Eine Stereokamera mit 12 cm Basisabstand ist jenseits von etwa fünf Metern für
Messaufgaben ungeeignet, unabhängig vom Algorithmus.
Die Alternativen
| Verfahren | Reichweite | Genauigkeit | Schwäche |
|---|---|---|---|
| Passives Stereo | 0,3 bis 10 m | quadratisch fallend | Strukturarme Flächen |
| Aktives Stereo mit Muster | 0,2 bis 5 m | hoch | Sonnenlicht |
| Time of Flight | 0,5 bis 8 m | konstant, mittel | Spiegelnde Flächen |
| LiDAR | 1 bis 200 m | hoch, konstant | Preis, geringe Punktdichte |
| Monokular gelernt | beliebig | nur relativ | Kein absoluter Maßstab |
Monokulare Tiefenschätzung
Ein Netz kann aus einem einzelnen Bild eine plausible Tiefenkarte erzeugen, weil es gelernt hat, welche Objekte typischerweise wie groß sind. Das Ergebnis ist bis auf eine unbekannte Skala und einen unbekannten Versatz korrekt:
Für Messaufgaben ist das nur brauchbar, wenn mindestens ein Objekt bekannter
Größe im Bild ist, aus dem s und t bestimmt werden. Ohne diesen Anker sind
Aussagen in Metern nicht belegbar.