stationary_camera_self_calibration
— Selbstkalibrierung einer stationären projektiven Kamera.
stationary_camera_self_calibration( : : NumImages, ImageWidth, ImageHeight, ReferenceImage, MappingSource, MappingDest, HomMatrices2D, Rows1, Cols1, Rows2, Cols2, NumCorrespondences, EstimationMethod, CameraModel, FixedCameraParams : CameraMatrices, Kappa, RotationMatrices, X, Y, Z, Error)
stationary_camera_self_calibration
führt eine
Selbstkalibrierung einer stationären projektiven Kamera durch.
Stationär bedeutet hierbei, dass sich die Kamera nur um das
optische Zentrum drehen und dabei zoomen darf. Das optische Zentrum
darf also nicht verschoben werden. Projektive Kamera bedeutet
hierbei, dass als Kameramodell eine Lochkamera verwendet wird, deren
Abbildung durch eine projektive 3D-2D-Abbildung beschrieben werden
kann. Insbesondere können radiale Verzeichnungen nur modelliert
werden, wenn die Brennweite konstant bleibt. Falls die Kamera
signifikante radiale Verzeichnungen aufweist, sollten diese mit
change_radial_distortion_image
zumindest näherungsweise
beseitigt werden.
Das zugrundeliegende Kameramodell kann wie folgt beschrieben werden:
Hierbei ist x ein homogener 2D-Vektor,
X ein homogener 3D-Vektor und P
eine homogene 3x4 Projektionsmatrix. Die
Projektionsmatrix P lässt sich wie folgt
zerlegen:
Hierbei ist R eine 3x3
Rotationsmatrix und t ein inhomogener 3D-Vektor.
Diese beiden Daten beschreiben die Lage der Kamera im Raum. Diese
Konvention ist analog zu der bei
camera_calibration
verwendeten Konvention, d.h. für
R=I und t=0 zeigt
die x-Achse nach rechts, die y-Achse nach unten und die z-Achse nach
vorne von der Bildebene weg. K ist die
Kalibriermatrix der Kamera (die Kameramatrix), die sich wie folgt
beschreiben lässt:
Hierbei ist f die Brennweite der Kamera in Pixeln, a das
Seitenverhältnis der Pixel, s ein Faktor, der die Schrägstellung
der Bildachsen modelliert und (u,v) der Hauptpunkt der Kamera in
Pixeln. In dieser Konvention entspricht die x-Achse der
Spaltenachse und die y-Achse der Zeilenachse.
Da die Kamera stationär ist, kann man t=0
annehmen. Mit dieser Konvention sieht man leicht, dass die vierte
Koordinate des homogenen 3D-Vektors X keinen
Einfluss auf die Lage des projizierten 3D-Punktes hat. Somit kann
man die vierte Koordinate auch auf 0 setzen und sieht, dass
X als Punkt der unendlich fernen Ebene betrachtet
werden kann, und somit eine Richtung im Raum repräsentiert. Mit
dieser Konvention kann man die vierte Koordinate von
X auch weglassen und X als
inhomogenen 3D-Vektor betrachten, der als Richtungsvektor nur bis
auf Skalierung bestimmt werden kann. Somit kann die obige
Projektionsgleichung auch wie folgt geschrieben werden:
Wenn man zwei Bilder desselben Punktes mit einer stationären Kamera
aufnimmt, gilt folglich
und somit
Wenn sich die Kameraparameter bei den zwei Aufnahmen nicht ändern,
gilt . Die beiden Bilder desselben
3D-Punktes sind folglich über eine projektive 2D-Abbildung
miteinander verknüpft. Diese Abbildung kann mit
proj_match_points_ransac
bestimmt werden. Es ist zu
beachten, dass die Reihenfolge der Koordinaten in den projektive
2D-Abbildungen in HALCON umgekehrt ist als in der obigen Konvention.
Außerdem ist zu beachten, dass proj_match_points_ransac
ein
Koordinatensystem verwendet, bei dem der Ursprung eines Pixels in
seiner linken oberen Ecke liegt, während
stationary_camera_self_calibration
ein Koordinatensystem
verwendet, dass dem Koordinatensystem von camera_calibration
entspricht, bei dem der Ursprung eines Pixels in seiner Mitte liegt.
Für die mit proj_match_points_ransac
bestimmten projektive
2D-Abbildungen müssen noch die Zeilen und Spalten vertauscht werden
und eine Verschiebung um (0.5,0.5) angewendet werden, so dass in
HALCON statt gilt
bzw.
Aus der obigen Gleichung können Bedingungsgleichungen für die
Kameraparameter auf zwei Arten hergeleitet werden. Zum einen kann
durch Elimination der Rotation eine Gleichung hergeleitet werden,
die die Kameramatrizen mit der projektive 2D-Abbildung zwischen zwei
Bildern verknüpft. Sei die projektive
Abbildung von Bild i nach Bild j. Dann gilt
Aus der zweiten Gleichung können lineare Gleichungen zur Bestimmung
der Kameraparameter gewonnen werden. Dieses Verfahren wird von
stationary_camera_self_calibration
für
EstimationMethod
= 'linear' verwendet. Dabei
werden für i alle in MappingSource
verwendeten Bilder
und für j alle in MappingDest
verwendeten Bilder zur
Aufstellung der Gleichungen benutzt. Nachdem die Kameraparameter
bestimmt worden sind, kann die Rotation der Kamera in den einzelnen
Bildern über die Gleichung und Bildung
der Abbildungskette vom Referenzbild ReferenceImage
aus
berechnet werden. Aus der ersten Gleichung kann ein nichtlineares
Verfahren zur Bestimmung der Kameraparameter durch Minimierung des
folgenden Fehlers hergeleitet werden:
Hierbei ist {(s,d)} wie beim linearen Verfahren die
durch MappingSource
und MappingDest
gegebene Menge
von überlappenden Bildern. Dieses Verfahren wird von
stationary_camera_self_calibration
für
EstimationMethod
= 'nonlinear' verwendet. Dabei
werden die Kameraparameter mit den Ergebnissen des linearen
Verfahrens initialisiert. Diese beiden Verfahren sind sehr schnell
und lieferen akzeptable Ergebnisse, wenn die projektiven
2D-Abbildungen hinreichend genau sind.
Dazu ist es unerlässlich, dass die Bilder keine radialen
Verzeichnungen aufweisen. Man sieht aber auch, dass die Bestimmung
der Kameraparameter unabhängig von der Bestimmung der Rotationen
erfolgt, und somit die möglichen Bedingungsgleichungen nicht
vollständig ausgeschöpft werden. Insbesondere kann man sehen, dass
nicht erzwungen wird, dass die Projektionen desselben Punktes nahe
beieinander liegen. Deswegen bietet
stationary_camera_self_calibration
als drittes Verfahren
eine Bündelausgleichung an (EstimationMethod
=
'gold_standard' ). Dabei werden sowohl die Kameraparameter
und Rotationen, als auch Richtungen im 3D (die oben angeführten
Vektoren X), die zur Minimierung des folgenden
Fehlers führen, in einer gemeinsamen Optimierung bestimmt:
Hierbei werden nur Terme berücksichtigt, für die die
rekonstruierte Richtung im Bild i
sichtbar ist. Als Startwerte für die Bündelausgleichung werden
Parameter verwendet, die aus den Ergebnissen des nichtlinearen
Verfahrens berechnet werden. Aufgrund der hohen Komplexität der
Minimierung dauert die Bündelausgleichung erheblich länger als die
beiden einfacheren Verfahren. Sie liefert aber auch signifikant
bessere Ergebnisse, und sollte deshalb bevorzugt werden.
In jedem der drei Verfahren kann festgelegt werden, welche
Kameraparameter bestimmt werden sollen. Die jeweils anderen
Kameraparameter werden auf einem festen Wert gehalten. Die
Festlegung erfolgt mit dem Parameter CameraModel
, der ein
Tupel von Werten enthält. CameraModel
muss immer den Wert
'focus' enthalten, der festlegt, dass die Brennweite f
bestimmt wird. Wenn CameraModel
den Wert
'principal_point' enthält, wird der Hauptpunkt (u,v) der
Kamera bestimmt, ansonsten wird er auf den Wert
(ImageWidth
/2,ImageHeight
/2) gesetzt. Wenn
CameraModel
den Wert 'aspect' enthält, wird das
Seitenverhältnis a der Pixel bestimmt, ansonsten wird es auf 1
gesetzt. Wenn CameraModel
den Wert 'skew'
enthält, wird die Schrägstellung s der Bildachsen bestimmt,
ansonsten wird sie auf 0 gesetzt. Es sind nur bestimmte
Kombinationen dieser Parameter erlaubt: 'focus' ,
['focus', 'principal_point'] , ['focus', 'aspect'] ,
['focus', 'principal_point', 'aspect'] und
['focus', 'principal_point', 'aspect', 'skew'] .
Zusätzlich zu den obigen Parametern ist es bei Verwendung von
EstimationMethod
= 'gold_standard' möglich mit
dem Parameter Kappa
die Verzeichnung der Bilder zu schätzen.
Hierfür kann in diesem Fall CameraModel
um den Parameter
'kappa' erweitert werden. Kappa
entspricht dem
Verzeichnungsparemeter kappa des Divisionsmodells für
Verzeichnungen (siehe camera_calibration
).
Bei der Verwendung von EstimationMethod
=
'gold_standard' zur Bestimmung des Hauptpunkts ist es
möglich, weit vom Bildmittelpunkt entfernt liegende Schätzungen zu
bestrafen. Hierzu kann ein Sigma an den Parameter
'principal_point:0.5' angehängt werden. Wird kein Sigma
angegeben, so entfällt der Strafterm in der obigen Fehlerformel.
Der Parameter FixedCameraParams
legt fest, ob sich die
Kameraparameter pro Bild ändern können oder ob sie für alle Bilder
als konstant angenommen werden sollen. Um eine Kamera zu
kalibrieren und später mit der kalibrierten Kamera zu messen, ist
nur FixedCameraParams
= 'true' sinnvoll. Der
Modus FixedCameraParams
= 'false' ist
hauptsächlich zur Berechnung von Mosaiken mit
gen_spherical_mosaic
sinnvoll, falls die Kamera bei der
Aufnahme des Mosaiks gezoomt hat oder sich die Scharfstellung
signifikant geändert hat. Falls ein Mosaik mit konstanten
Kameraparametern berechnet werden soll, sollte natürlich auch
FixedCameraParams
= 'true' verwendet werden. Es
ist zu beachten, dass für FixedCameraParams
=
'false' in praktischen Anwendungen das Problem, speziell
für Aufnahmen mit langen Brennweiten, sehr schlecht bestimmt ist.
In diesen Fällen kann oft nur die Brennweite bestimmt werden.
Deswegen ist es hier unter Umständen erforderlich,
CameraModel
= 'focus' zu wählen oder die Lage
des Hauptpunktes einzuschränken, indem ein kleines Sigma für den
Strafterm des Hauptpunktes gewählt wird.
Die Anzahl der Bilder, die zur Kalibrierung verwendet werden, wird
in NumImages
übergeben. Aus der Anzahl der Bilder ergeben
sich Einschränkungen für das Kameramodell. So können bei der
Verwendung von nur zwei Bildern selbst bei der Annahme von
konstanten Kameraparametern nicht alle Parameter bestimmt werden.
Hier sollte sinnvollerweise die Schrägstellung der Bildachsen auf 0
gesetzt werden, indem 'skew' nicht in
CameraModel
aufgenommen wird. Falls
FixedCameraParams
= 'false' verwendet wird,
können in keinem Fall alle Kameraparameter bestimmt werden. Hier
sollte ebenfalls mindestens die Schrägstellung der Bildachsen auf 0
gesetzt werden. Weiterhin ist zu beachten, dass das
Seitenverhältnis der Pixel nur korrekt bestimmt werden kann, wenn
mindestens ein Bild um die optische Achse (die z-Achse des
Kamerakoordinatensystems) gegenüber den anderen Bildern verdreht
aufgenommen worden ist. Falls dies nicht der Fall ist, sollte die
Bestimmung des Seitenverhältnisses unterdrückt werden, indem der
Wert 'aspect' nicht in CameraModel
aufgenommen wird.
Wie oben beschrieben, ist es zur Kalibrierung notwendig, dass mit
proj_match_points_ransac
für jedes überlappende Bildpaar
die projektive Abbildung zwischen den zwei beteiligten Bildern
bestimmt wird. So sind z.B. für einen 2x2 Block
von Bildern in folgender Anordnung
1 | 2 |
3 | 4 |
unter der Annahme, dass sich alle Bilder gegenseitig überlappen,
folgende projektive Abbildungen zu bestimmen: 1->2,
1->3, 1->4, 2->3,
2->4 und 3->4. Die Indizes der
Bilder, die die jeweilige Abbildung bestimmen, werden in
MappingSource
und MappingDest
übergeben. Die
Indizes der Bilder beginnen ab 1. In obigem Beispiel ist also
MappingSource
= [1,1,1,2,2,3] und
MappingDest
= [2,3,4,3,4,4] zu verwenden. Die
Gesamtanzahl von Bildern, die zur Kalibrierung verwendet wird, wird
in NumImages
übergeben. Sie wird verwendet, um zu
überprüfen, ob jedes Bild über eine Kette von Abbildungen
erreicht werden kann. Der Index des Referenzbildes wird in
ReferenceImage
übergeben. Dieses Bild erhält in der
Ausgabe als Rotation die Einheitsmatrix.
Die zu den Bildpaaren gehörigen 3x3 projektiven
Transformationsmatrizen werden in HomMatrices2D
übergeben.
Zusätzlich müssen in Rows1
, Cols1
,
Rows2
und Cols2
die Koordinaten der zugeordneten
Punktpaare in den einzelnen Bildpaaren übergeben werden. Sie
können aus der Ausgabe von proj_match_points_ransac
mit
tuple_select
oder mit der HDevelop-Funktion subset
bestimmt werden. Damit stationary_camera_self_calibration
bestimmen kann, zu welcher Abbildung ein Punktpaar gehört, muss in
NumCorrespondences
für jedes Bildpaar die Anzahl der
gefundenen Zuordnungen übergeben werden.
Die berechneten Kameramatrizen werden in
CameraMatrices
als 3x3 Matrizen
zurückgegeben. Für FixedCameraParams
=
'false' werden NumImages
Matrizen zurückgegeben.
Da für FixedCameraParams
= 'true' alle
Kameramatrizen identisch sind, wird in diesem Fall nur eine
Kameramatrix zurückgegeben. Die berechneten Rotationen
werden in RotationMatrices
als
3x3 Matrizen zurückgegeben.
RotationMatrices
enthält NumImages
Matrizen.
Falls EstimationMethod
= 'gold_standard'
verwendet wird, werden in (X
, Y
, Z
) die
rekonstruierten Richtungen zurückgegeben.
Zusätzlich wird in Error
der mittlere Projektionsfehler
der rekonstruierten Richtungen zurückgegeben. Dies kann verwendet
werden, um zu überprüfen, ob die Optimierung zu sinnvollen Werten
konvergiert ist.
Falls die berechneten Kameraparameter zur Projektion von 3D-Punkten
oder 3D-Richtungen in das Bild i verwendet werden sollen, sollte
die jeweilige Kameramatrix mit der Rotationsmatrix multipliziert
werden (mit hom_mat2d_compose
).
NumImages
(input_control) integer →
(integer)
Anzahl der verschiedenen Bilder, die zur Kalibrierung verwendet werden.
Restriktion: NumImages >= 2
ImageWidth
(input_control) extent.x →
(integer)
Breite der Bilder, aus denen die Punkte extrahiert wurden.
Restriktion: ImageWidth > 0
ImageHeight
(input_control) extent.y →
(integer)
Höhe der Bilder, aus denen die Punkte extrahiert wurden.
Restriktion: ImageHeight > 0
ReferenceImage
(input_control) integer →
(integer)
Index des Referenzbildes.
MappingSource
(input_control) integer-array →
(integer)
Indizes der Ausgangsbilder der Transformationen.
MappingDest
(input_control) integer-array →
(integer)
Indizes der Zielbilder der Transformationen.
HomMatrices2D
(input_control) hom_mat2d-array →
(real)
Array von 3x3 projektiven Transformationsmatrizen.
Rows1
(input_control) point.y-array →
(real / integer)
Zeilenkoordinaten korrespondierender Punkte in den jeweiligen Ausgangsbildern.
Cols1
(input_control) point.x-array →
(real / integer)
Spaltenkoordinaten korrespondierender Punkte in den jeweiligen Ausgangsbildern.
Rows2
(input_control) point.y-array →
(real / integer)
Zeilenkoordinaten korrespondierender Punkte in den jeweiligen Zielbildern.
Cols2
(input_control) point.x-array →
(real / integer)
Spaltenkoordinaten korrespondierender Punkte in den jeweiligen Zielbildern.
NumCorrespondences
(input_control) integer-array →
(integer)
Anzahl der Punktkorrespondenzen im jeweiligen Bildpaar.
EstimationMethod
(input_control) string →
(string)
Schätzalgorithmus für die Kalibrierung.
Defaultwert: 'gold_standard'
Werteliste: 'gold_standard' , 'linear' , 'nonlinear'
CameraModel
(input_control) string-array →
(string)
Verwendetes Kameramodell.
Defaultwert: ['focus','principal_point']
Werteliste: 'aspect' , 'focus' , 'kappa' , 'principal_point' , 'skew'
FixedCameraParams
(input_control) string →
(string)
Sind die Kameraparameter für alle Bilder identisch?
Defaultwert: 'true'
Werteliste: 'false' , 'true'
CameraMatrices
(output_control) hom_mat2d-array →
(real)
(Array von) 3x3 projektiven Kameramatrizen, die die internen Kameraparameter bestimmen.
Kappa
(output_control) real(-array) →
(real)
Radiale Verzeichnung der Kamera.
RotationMatrices
(output_control) hom_mat2d-array →
(real)
Array von 3x3 Transformationsmatrizen, die die Rotation der Kamera im jeweiligen Bild bestimmen.
X
(output_control) point3d.x-array →
(real)
Richtungsparameter in X-Richtung aller Punkte,
wenn EstimationMethod
=
'gold_standard' verwendet wird.
Y
(output_control) point3d.y-array →
(real)
Richtungsparameter in Y-Richtung aller Punkte,
wenn EstimationMethod
=
'gold_standard' verwendet wird.
Z
(output_control) point3d.z-array →
(real)
Richtungsparameter in Z-Richtung aller Punkte,
wenn EstimationMethod
=
'gold_standard' verwendet wird.
Error
(output_control) real(-array) →
(real)
Durchschnittlicher Fehler pro rekonstruiertem Punkt,
wenn EstimationMethod
=
'gold_standard' verwendet wird.
* Assume that Images contains four images in the layout given in the * above description. Then the following example performs the camera * self-calibration using these four images. From := [1,1,1,2,2,3] To := [2,3,4,3,4,4] HomMatrices2D := [] Rows1 := [] Cols1 := [] Rows2 := [] Cols2 := [] NumMatches := [] for J := 0 to |From|-1 by 1 select_obj (Images, ImageF, From[J]) select_obj (Images, ImageT, To[J]) points_foerstner (ImageF, 1, 2, 3, 100, 0.1, 'gauss', 'true', \ RowsF, ColsF, _, _, _, _, _, _, _, _) points_foerstner (ImageT, 1, 2, 3, 100, 0.1, 'gauss', 'true', \ RowsT, ColsT, _, _, _, _, _, _, _, _) proj_match_points_ransac (ImageF, ImageT, RowsF, ColsF, RowsT, ColsT, \ 'ncc', 10, 0, 0, 480, 640, 0, 0.5, \ 'gold_standard', 2, 42, HomMat2D, \ Points1, Points2) HomMatrices2D := [HomMatrices2D,HomMat2D] Rows1 := [Rows1,subset(RowsF,Points1)] Cols1 := [Cols1,subset(ColsF,Points1)] Rows2 := [Rows2,subset(RowsT,Points2)] Cols2 := [Cols2,subset(ColsT,Points2)] NumMatches := [NumMatches,|Points1|] endfor stationary_camera_self_calibration (4, 640, 480, 1, From, To, \ HomMatrices2D, Rows1, Cols1, \ Rows2, Cols2, NumMatches, \ 'gold_standard', \ ['focus','principal_point'], \ 'true', CameraMatrix, Kappa, \ RotationMatrices, X, Y, Z, Error)
Sind die Parameterwerte korrekt, dann liefert
stationary_camera_self_calibration
den Wert 2 (H_MSG_TRUE).
Gegebenenfalls wird eine Fehlerbehandlung durchgeführt.
proj_match_points_ransac
,
proj_match_points_ransac_guided
Lourdes Agapito, E. Hayman, I. Reid: „Self-Calibration of Rotating and Zooming Cameras“; International Journal of Computer Vision; vol. 45, no. 2; pp. 107--127; 2001.
Calibration