Kamerakalibrierung in OpenCV



  • Hallo,

    momentan sitze ich an der Kamerakalibrierung in OpenCV und möchte das Beispiel in diesem Video nachprogrammieren:
    http://www.youtube.com/watch?v=DrXIQfQHFv0&p=506AA4FE9FBD8FE0&playnext=1&index=15

    Soweit ich das mit der Kamerakalibrierung verstanden habe, wird eine intrinsiche Matrix berechnet, die die Kamera beschreibt. Diese Matrix enthält die Brennweite der Kamera für x- und y- Richtung, sowie die Offsets, die die optische Achse auf das Zentrum der Projektionsebene, den Imager, bringen.
    Hinzu gesellt sich eine extrinsische Matrix, die eine Rotation und Translation des Kamerakoordinatensystems beschreibt, so dass diese auf dem Weltkoordinatensystem liegt. Damit die Berechnung möglich wird, hält man ein planares Objekt in die Kamera, wie z.b. ein Schachbrett. Die einzelnen Ecken werden gefunden und diesen ordnet der Benutzer dann bestimmte Koordinatenwerte im Weltkoordinatensystem zu. So legt das Schachbrett also das Weltkoordinatensystem fest.
    Bei der Mathematik hinter diesem ganzen Geschehen werden grob gesagt die homogenen Weltkoordinaten in homogene Kamerakoordinaten überführt, die dann wiederum auf die gefundenen Punkte im Imager überführt werden, also dem Frame von der Kamera. Da man die Werte der Weltkoordinaten und die Punkte auf dem Imager schon kennt, können alle anderen Unbekannten, wir Rotationswinkel, Brennweite etc. bei genug Informationen (dies wären die gefundenen Punkte des Schachbretts in jedem Frame) berechnet werden.

    Das erstmal vorweg, damit etwaige Verständnisfehler des Ganzen ersichtlich werden.
    Bei meinem Beispiel lege ich für die linke obere Ecke des Schachbretts den Ursprung des Weltkoordinatensystems fest. Der nächste Punkt liegt dann bei (1/0/0), der zweite dann bei (2/0/0) usw. In einer Initialisierungsphase berechne ich die instrinsiche Matrix. Diesen Codeabschnitt habe ich aus dem Buchbeispiel und gehe davon aus, dass dieses auch richtig ist.

    Danach nehme ich mir in einer Schleife jeden Frame und suche dort die Koordinaten des Schachbretts und speichere diese in einer Matrix, die ich dann dazu verwende, um die extrinsischen Werte zu berechnen:

    cvFindChessboardCorners(image, board_sz, corners, &corner_count, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);
    
    for(int j = 0; j < board_n; j++){
    CV_MAT_ELEM(*image_points, float,j,0) = corners2[j].x;
    CV_MAT_ELEM(*image_points, float,j,1) = corners2[j].y;
    }
    cvFindExtrinsicCameraParams2(object_points, image_points, intrinsic_matrix, distortion_coeffs, rotation, translation);
    

    In der Dokumentation steht, dass der Rotationsvektor eine Achse im 3D-Raum darstellt, um die das Objekt gedreht wurde. Sein Betrag ist der Rotationswinkel gegen den Uhrzeigersinn. Also mache ich nun folgendes:

    float theta = sqrt((CV_MAT_ELEM(*rotation, float, 0, 0)*CV_MAT_ELEM(*rotation, float, 0, 0))+
    (CV_MAT_ELEM(*rotation, float, 1, 0)*CV_MAT_ELEM(*rotation, float, 1, 0))+
    (CV_MAT_ELEM(*rotation, float, 2, 0)*CV_MAT_ELEM(*rotation, float, 2, 0)));
    
    Chessboard->setRot(theta, CV_MAT_ELEM(*rotation, float, 0, 0), CV_MAT_ELEM(*rotation, float, 1, 0), CV_MAT_ELEM(*rotation, float, 2, 0));
    

    Der Mehtodenaufruf meines Schachbretts ruft nichts anderes als die OpenGL-Funktion glRotatef() auf, die den übergebenen Vektor automatisch normiert, wenn es dieser nicht schon ist.
    Diese Operationen mache ich Frame für Frame.

    Das Problem aber nun ist, dass sich rein gar nicht tut! Das Schachbrett will im 3D-Fenster nicht rotieren. Ich habe einfach keine Ahnung warum. 😕



  • Endlich ist es geschafft! Der Fehler lag ganz wo anders.

    Mein Schachbrett enthält 48 Punkte, also habe ich 48 Koordinaten in R³, die mein Weltkoordinatensystem beschreiben, beginnend mit (0/0/0), (1/0/0) usw. (wie im letzten Post beschrieben). Pro Frame werden dann ebenfalls respektive 48 Punkte in R² gefunden. Diese Punkte habe ich meinen Funktionen wie oben beschrieben übergeben, damit sie mir die Translation und Rotation berechnen.
    Das Problem lag darin, dass ich, als ich das Beispiel aus dem Buch kopiert habe, für die Matrixdeklaration Copy und Paste benutzt habe und die größe der beiden Matrizen bei 48*48 Punkten belassen habe, da ich noch nicht genau wusste wie das ganze Geschehen funktioniert. Nunja, dann haben die Funktionen versucht den Rotations- und Translationsvektor mit den 48 übergebenen Punkten zu berechnen, aber eben auch mit den restlichen 47*48 Nulleinträgen in der jeweiligen matrix. :roll:

    Ich könnte mich schwarzärgern, dass es solch ein dummer Fehler war, aber das bringt ja nichts. Ich bin einfach nur froh, dass es funktioniert. 😃

    Hier habe ich noch ein Video davon hochgeladen:
    http://www.youtube.com/watch?v=bV-jAnQ-tvw

    Edit: Sorry für den Doppelpost. Wenn ein Moderator möchte, kann er alle zwei in einen packen. 🙂



  • Sehr beeindruckend!



  • Hey,

    ich hab mal ne Frage zu dem Fenster in dem du das Schachbrett im Raum anzeigst. Und zwar änderst du während deines Videos mal die ViewDirection. Wie machst du das? bzw, wie berechnest du dann die neue perspektive?

    Im Endeffekt ist das doch nur eine Rot und trans der Kamera oder? nur woher weiß ich denn die korrekten Daten dieser in der 3d Welt?

    Grüße
    Senna