Kampis Elektroecke

Kamerakalibrierung

Raspberry Pi

In diesem Artikel möchte ich auf das Thema Kamerakalibrierung eingehen und zeigen, wie eine Kalibrierung der Raspberry Pi Kamera durchgeführt werden kann.

Was versteht man unter „Kamerakalibrierung“?:

Kameralinsen arbeiten nicht ideal, sondern verzerren das aufgenommene Bild. Die Verzerrung hängt in erster Linie von der Brennweite der Linse ab und wird besonders bei Fischaugenobjektiven gut sichtbar.

Gerade wenn die Kamera zur Objekterkennung oder im Bereich der Bildverarbeitung genutzt wird, ist solch eine Verzerrung, egal wie stark sie ausgeprägt ist, störend und sollte korrigiert werden. Durch die Verwendung von verzerrungsfreien Bildern können z. B. Abstände und Größen von Objekten alleine mit einer Kamera bestimmt werden.

Die mathematischen Grundlagen zur Kamerakalibrierung möchte ich hier nicht durchsprechen, sondern auf die Erklärung von Mathworks verweisen. Dort wird sehr gut beschrieben, wie die Verzerrung bestimmt werden kann und wie das entsprechende mathematische Modell aussieht.

Erzeugung des Schachbrettmusters:

Für eine Kamerakalibrierung wird ein Schachbrettmuster benötigt, wobei die Genauigkeit und die Qualität des Kalibrierungsergebnisses direkt von der Qualität des verwendeten Musters abhängen.

Der beste Weg ist es, das Muster mittels Computer zu erzeugen und dann auf eine stabile Platte drucken zu lassen. Für die Erzeugung des Schachbrettmusters habe ich mir ein Windows-Programm geschrieben, welches eine Bilddatei mit einem Schachbrett erzeugt. 

Für die Kompilierung des Programms wird OpenCV für Windows benötigt und der Pfade muss als Umgebungsvariable OPENCV_Lib angelegt werden.

In dem Downloadverzeichnis befindet sich aber auch eine Release-Version des Programms zur direkten Ausführung. Das Programm erwartet folgende Kommandozeilenparameter:

  1. Anzahl der schwarzen Kanten (vertikal)
  2. Anzahl der schwarzen Kanten (horizontal)
  3. Größe der Rechtecke in Pixel
  4. Ausgabepfad
$ ChessboardCreator 7 9 900 ../Board.png

Als Druckservice habe ich diesen hier in Anspruch genommen. Wichtig ist es, dass das vorgegebene Muster nur unter Berücksichtigung des Seitenverhältnisses vergrößert wird, da die Felder quadratisch sein müssen. Dies sollte unbedingt bei der Bestellung angegeben werden, da es sonst passieren kann, dass der Hersteller das Muster auf die Größe der Platte vergrößert und dann funktioniert die Kalibration nicht.

Linsenverzerrung korrigieren:

Im Vorfeld habe ich mittels Shell-Skript über die Kamera 20 Bilder des Schachbretts aus verschiedenen Perspektiven aufgenommen. Die komplette Kalibrierung der Kamera findet in einer eigenen Klasse statt. Zuerst wird die Kalibrierung initialisiert und die Anzahl der horizontalen und vertikalen Ecken des Schachbretts übergeben:

Calibration.InitCalibration(8, 6);

Im nächsten Schritt wird der Pfad mit den Kalibrierungsfotos übergeben.

Status = Calibration.LoadImages("//home//pi//Desktop//Calibration");

Die Methode ließt alle Bilder aus dem Verzeichnis ein und verarbeitet sie entsprechend. Dies kann, je nach Fotogröße und Fotomenge ein paar Minuten dauern. Bei einem Raspberry Pi 3B+ mit 20 Bildern á 1920×1080 Pixeln hat das Laden und Vorverarbeiten gute 10 Minuten gedauert.

Über den Status können Fehlermeldungen abgefangen werden. Wenn alles geklappt hat, wird der Status 0 zurückgegeben und dann kann die Kalibrierung angestoßen werden.

if (Status == 0)
{
	Calibration.PerformCalibration();
}

Das Ergebnis der Kalibrierung sind zwei Matrizen:

  • Intrinsische Parameter
    • Brennweite,
    • Der optischen Mittelpunkt
    • Die Schräglage der Pixel des Kamerasensors
  • Extrinsische Parameter
    • Die erkannten Bildpunkte des Schachbrettmusters

Nach einer erfolgreichen Kalibrierung können die Daten gespeichert, bzw. geladen werden:

Status = Calibration.Save("//home//pi//Desktop//Calibration//CalibrationData.xml")
Calibration.Load("//home//pi//Desktop//Calibration//CalibrationData.xml")

Die berechneten Kalibrationsdaten sind überaus nützlich. So können über die intrinsischen Parameter verschiedene Daten zur Kamera, wie z. B. die Brennweite abgefragt werden:

cv::Point FocalLenth = Calibration.GetFocalLength();

Hierbei ist zu beachten, dass die Brennweite in Pixel angegeben wird, da der Kalibrationsalgorithmus keinerlei Informationen über die Daten des Kamerasensors besitzt! Wenn die Pixelgröße bekannt ist, kann die Brennweite in Millimeter umgerechnet werden.

Brennweite_{mm} = Brennweite _{Pixel}\cdot Breite

Für die Raspberry Pi Kamera v1 gilt:

  Breite Höhe
Pixel 1,4 µm 1,4 µm
  x y
Brennweite 2.545e+03 Pixel 2.546e+03 Pixel
  35,63 mm 35,64 mm

Aus den Kalibrationsdaten kann auch der optische Bildmittelpunkt ausgelesen werden. Durch Toleranzen etc. liegt der optische Bildmittelpunkt nicht in der Mitte des Bildes, sondern ist immer etwas verschoben.

  Aus Kalibrierung Aus Sensordaten
Bildmittelpunkt (1288, 987) (1296, 972)

Mit Hilfe der Kalibrationsdaten kann das Bild dann entzerrt werden. Die dafür notwendigen Parameter befinden sich u. a. in der Distortion-Matrix von OpenCV. Der Zugriff erfolgt über die Methode UndistortImage():

Calibration.UndistortImage(&Image, &UndistortedImage);

Das komplette Projekt, inklusive des Schachbrett-Generators und ein paar Beispielbilder, gibt es in meinem Git-Repository zum Download.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert