Tutorial · Mittelstufe · 22 Min. Lesezeit
Kamerakalibrierung und ArUco-Pose mit OpenCV
Kalibriere eine Roboterkamera mit OpenCV, miss den Reprojektionsfehler, erkenne ArUco-Marker und schätze die Markerpose mit korrekten Einheiten und Koordinaten.
Ein Kamerabild meldet Pixel, ein Roboter braucht Strahlen und Koordinaten. Kamerakalibrierung schätzt die Intrinsik, die 3D-Punkte im Kamerasystem auf Pixel abbildet, sowie die Verzeichnung des Objektivs. Sind diese Werte bekannt, liefert ein Marker bekannter Geometrie seine Position und Orientierung relativ zur Kamera.
ArUco-Marker sind quadratische binäre Messmarken mit ID. Das Erkennen der vier Ecken identifiziert den Marker im Bild; die Posenschätzung verbindet diese Pixelecken, die reale Markergröße und kalibrierte Kameraparameter.
Die Kalibrierergebnisse verstehen
Die Kameramatrix enthält Brennweiten und das optische Zentrum:
[ fx 0 cx ]
[ 0 fy cy ]
[ 0 0 1 ]
fx und fy stehen in Pixeln. cx und cy lokalisieren den Hauptpunkt. Verzeichnungskoeffizienten modellieren Effekte wie radiale Tonnen-/Kissenverzeichnung und tangentiale Dezentrierung.
Diese Werte gehören zu einer Kamera, einem Objektiv, einer Fokuseinstellung und einer Bildgeometrie. Eine Auflösungsänderung per Zuschnitt oder Skalierung kann Anpassung der Intrinsik verlangen; Fokusänderung oder Objektivtausch verlangen Neukalibrierung.
Kalibriertarget drucken und vermessen
Ein Schachbrett ist ein praktisches erstes Target, weil sich innere Ecken leicht definieren lassen. Miss die Quadratgröße genau. Der Posenmaßstab erbt diese Einheit: Objektpunkte in Metern ergeben Translationen in Metern; Objektpunkte in Millimetern ergeben Millimeter.
Halte das Target flach. Ein gewelltes Blatt verletzt die planare Geometrie, die die Objektpunkte annehmen. Montiere es auf starrem Material, wenn Genauigkeit zählt.
Definiere die Zahl innerer Ecken, nicht gedruckter Quadrate. Ein Brett mit 10 mal 7 Quadraten hat 9 mal 6 innere Ecken. Diese Zählungen zu verwechseln lässt die Erkennung scheitern, selbst wenn das Bild klar aussieht.
Einen nützlichen Bildsatz aufnehmen
Sammle als Start mindestens zehn gelungene Ansichten, dann füge Vielfalt statt Duplikate hinzu. Bewege das Brett über das ganze Bild, neige es in beiden Achsen, variiere die Distanz und nimm Ecken nahe den Bildrändern auf, wo die Verzeichnung am stärksten ist. Halte das Muster scharf und vollständig sichtbar.
Zwanzig fast identische frontale Bilder liefern weniger Information als weniger gut verteilte Posen. Verwerfe Bewegungsunschärfe und Bilder mit unsicherer Eckenerkennung. Nutze dieselbe Auflösung und Kameraeinstellungen wie für den Betrieb geplant.
Speichere für jedes akzeptierte Bild die erkannten Bildecken und die zugehörigen planaren Objektpunkte (Spalte × Quadratgröße, Zeile × Quadratgröße, 0).
Mit OpenCV kalibrieren
Der wesentliche Python-Ablauf ist:
import cv2
import numpy as np
pattern = (9, 6) # internal corners: columns, rows
square_size = 0.024 # metres
object_template = np.zeros((pattern[0] * pattern[1], 3), np.float32)
object_template[:, :2] = np.mgrid[0:pattern[0], 0:pattern[1]].T.reshape(-1, 2)
object_template *= square_size
object_points, image_points = [], []
for gray in calibration_images:
found, corners = cv2.findChessboardCorners(gray, pattern)
if not found:
continue
refined = cv2.cornerSubPix(
gray, corners, (11, 11), (-1, -1),
(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001),
)
object_points.append(object_template.copy())
image_points.append(refined)
rms, camera_matrix, distortion, rvecs, tvecs = cv2.calibrateCamera(
object_points, image_points, gray.shape[::-1], None, None
)
Schütze dich vor zu wenigen akzeptierten Bildern vor dem Kalibrieraufruf. Speichere Matrix, Verzeichnungskoeffizienten, Bildbreite/-höhe, Targetdefinition und Kalibrierdatum gemeinsam. Eine nackte Array-Datei ist später leicht missbrauchbar.
Mehr validieren als den RMS-Wert
Der mittlere quadratische (RMS-)Reprojektionsfehler fasst zusammen, wie weit projizierte Kalibrierpunkte von erkannten Bildpunkten entfernt sind. Kleiner ist meist besser, aber eine Zahl kann schlechte Bereiche oder einen schwachen Bildsatz verbergen.
Berechne den Reprojektionsfehler pro Bild und inspiziere die schlechtesten Ansichten. Zeichne reprojizierte Punkte über die Bilder. Prüfe gerade Architekturkanten nach Entzerrung, besonders nahe Ecken. Schätze dann die Pose eines Targets in bekannter Distanz und vergleiche die Translation mit einer physischen Messung.
Dominiert ein Bild den Fehler, inspiziere und entferne es nur aus vertretbarem Grund wie Unschärfe oder falscher Eckenreihenfolge. Wiederholtes Löschen von Bildern mit hohem Fehler, bis die Zahl gut aussieht, kann ein schlechtes Modell oder Target verbergen.
Einen ArUco-Marker erkennen
Wähle ein vordefiniertes Wörterbuch und erzeuge Marker aus demselben Wörterbuch. Größere Bitraster bieten mehr IDs, aber jedes Bit bekommt bei fester Bildgröße weniger Pixel. Drucke den Marker mit ruhigem weißem Rand und miss die schwarze Seitenlänge, die das Posenmodell nutzt.
dictionary = cv2.aruco.getPredefinedDictionary(cv2.aruco.DICT_4X4_50)
parameters = cv2.aruco.DetectorParameters()
detector = cv2.aruco.ArucoDetector(dictionary, parameters)
corners, ids, rejected = detector.detectMarkers(frame)
Die API-Konstruktion unterscheidet sich über ältere OpenCV-Versionen, passe den Code also an die offizielle Dokumentation der installierten Version an. Die Ausgaben sollten weiterhin vier geordnete Bildecken pro erkanntem Marker liefern.
Pose mit bekannter Markergröße schätzen
Definiere Markerecken im eigenen Koordinatensystem und löse das Perspektiv-n-Punkt-Problem. Für eine Markerseite s erwartet OpenCVs quadratspezifischer Löser eine konsistente Eckenreihenfolge:
s = 0.080 # metres
object_corners = np.array([
[-s/2, s/2, 0],
[ s/2, s/2, 0],
[ s/2, -s/2, 0],
[-s/2, -s/2, 0],
], dtype=np.float32)
ok, rvec, tvec = cv2.solvePnP(
object_corners,
corners[0].reshape(4, 2),
camera_matrix,
distortion,
flags=cv2.SOLVEPNP_IPPE_SQUARE,
)
tvec ist der Markerursprung im Kamerasystem und nutzt dieselbe Längeneinheit wie s. rvec ist ein Rodrigues-Rotationsvektor, keine Eulerwinkel. Nutze cv2.Rodrigues(), um eine Rotationsmatrix zu erhalten oder ihn durch das Rahmensystem des Roboters zu transformieren.
Zeichne projizierte Koordinatenachsen und verifiziere sie physisch. Eine positive Translation mit glaubwürdiger Größe reicht nicht, wenn Achsen gespiegelt sind oder die falsche Markergröße eingegeben wurde.
Die Pose robotertauglich stabil machen
Die Pose wird verrauscht, wenn der Marker wenige Pixel belegt, steilwinklig liegt, verwackelt ist oder sich dem Bildrand nähert. Verbessere Licht und Belichtung, nutze einen größeren Marker, gehe näher heran oder nutze ein Board aus mehreren Markern, wenn die Anwendung es erlaubt.
Filtere nur gültige Posen und behalte Zeitstempel. Ein Tiefpassfilter senkt Jitter, fügt aber Reglerverzug hinzu. Verwerfe sprunghafte Ergebnisse per Reprojektionsfehler, Distanzgrenzen und Bewegungsgrenzen, statt jede Erkennung blind zu mitteln.
Die Markerpose ist relativ zur Kamera. Um einen Roboterarm oder eine mobile Basis zu kommandieren, transformiere sie durch die kalibrierte Kamerahalterung nach base_link oder zur Armbasis. Eine Millimeter-/Meter-Verwechslung erzeugt hier einen tausendfachen Fehler.
Typische Fehler diagnostizieren
- Entzerrung verbiegt gerade Linien: Kalibrieransichten ohne Abdeckung, Target nicht flach oder Bildgeometrie geändert.
- Distanzmaßstab konstant falsch: Quadrat- oder Markergröße mit falschem Maß oder Einheit.
- Posenachsen zeigen falsch: Objekt-Eckenreihenfolge oder Rahmenkonvention falsch.
- Marker-ID flackert: Marker zu klein, verwackelt, schlecht gedruckt oder aus anderem Wörterbuch.
- Pose springt nahe frontaler Ansicht: Planare Posenmehrdeutigkeit und schwache Pixelgeometrie brauchen bessere Blickwinkel, Tracking oder Mehrmarker-Bedingungen.
- Kalibrierung gilt nur bei einer Auflösung: Intrinsik nach Zuschnitt/Skalierung ohne Anpassung wiederverwendet.
- Roboterbewegung hinkt dem Marker hinterher: Übermäßige Glättung oder alte Zeitstempel verbergen aktuelle Geometrie.
Nutze den Sensor-Simulator, um Rauschen, Bias, Filterung und Latenz zu erkunden. Der Roboterarm-Simulator zeigt, wie eine Zielpose nach korrekter Kamerageometrie trotzdem unerreichbar sein kann.
Den Graphen erkunden
Teil dieser Bauprojekte
Projekte und Lernpfade, die dieses Tutorial enthalten.
Weiterführende Literatur