IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

OpenCV Discussion :

Calibration de caméra, incompréhension des valeurs renvoyées


Sujet :

OpenCV

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Octobre 2010
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 18
    Par défaut Calibration de caméra, incompréhension des valeurs renvoyées
    Bonjour!

    Voici mon problème, j'ai écris un programme, en partie pris sur le livre d'opencv, pour calibrer ma webcam avec un damier, et ensuite déterminer la position de cette webcam par rapport au damier.
    Mon programme se lance de la façon suivante:
    ./calib_tracking_LK nbCoinsDamierLargeur nbCoinsDamierHauteur nbImagesPourCalibrer

    Le programme commence donc à chercher un damier de nbCoinsDamierLargeur x nbCoinsDamierHauteur, c'est à cette étape qu'on place donc le damier sous différents angles devant la caméra.

    Une fois qu'il a repéré nbImagesPourCalibrer damiers, il passe à l'étape suivante qui est le suivi du damier.
    Pour cela, j'utilise le flot optique (cvCalcOpticalFlowPyrLK). Sur ma visualisation, le damier est correctement suivi, mais je ne comrpend pas du tout les valeurs du vecteur translation (que j'affiche dans ma console)
    Les valeurs changent évidemment quand la calibration est faite autrement, mais je n'arrive jamais à obtenir des valeurs correctes et compréhensibles de ma position de la caméra par rapport au damier.

    Je vous mets mon code, ça peut aider

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
     
    //compilation sous linux
    //gcc -L/usr/lib -W -Wall -L/usr/X11R6/lib -I/usr/X11R6/include -I/usr/include/opencv -lX11 -lm -lcv -lhighgui -o calib_tracking_LK calib_tracking_LK.cpp `pkg-config --cflags --libs opencv`
     
    //./calib_tracking_LK 7 7 10
     
    #include <cv.h>
    #include <highgui.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sstream>
    #include <iostream>
    using namespace std;
     
     
    // Maths methods
    #define max(a, b) ((a) > (b) ? (a) : (b))
    #define min(a, b) ((a) < (b) ? (a) : (b))  
    #define abs(x) ((x) > 0 ? (x) : -(x))
    #define sign(x) ((x) > 0 ? 1 : -1)
     
    CvCapture* capture;
    CvMat* image_points;
    CvMat* object_points;
    CvMat* point_counts;
    CvMat* intrinsic_matrix;
    CvMat* distortion_coeffs;
     
    IplImage *image=0;
    IplImage *gray_image=0;
    IplImage *eigImage=0,*tempImage=0;
     
    int board_w;
    int board_h;
    int board_n;
    CvSize board_sz;
    int n_boards = 0; //Will be set by input list
    const int board_dt = 20; //Wait 20 frames per chessboard view
    CvMat* object_points2;
    CvMat* image_points2;
    CvMat* point_counts2;
     
    int frameWidth, frameHeight;
    int corner_count;
    int successes = 0;
    int step, frame = 0;
     
    CvPoint2D32f* corners;
     
     
    int main(int argc, char* argv[]) {
     
      board_w  = atoi(argv[1]); //nombre de coins intérieurs en largeur
      board_h  = atoi(argv[2]); //nombre de coins intérieurs en hauteur
      n_boards = atoi(argv[3]); //nombre d'images pour la calibration
     
      board_n  = board_w * board_h; //nombre de coins total
      board_sz = cvSize( board_w, board_h );
      capture = cvCreateCameraCapture( 0 );
      assert(capture);
     
      frameWidth= 640;
      frameHeight=480;
     
      cvNamedWindow( "Calibration" );
     
      //ALLOCATE STORAGE
      image_points      = cvCreateMat(n_boards*board_n,2,CV_32FC1);
      object_points     = cvCreateMat(n_boards*board_n,3,CV_32FC1);
      point_counts      = cvCreateMat(n_boards,1,CV_32SC1);
      intrinsic_matrix  = cvCreateMat(3,3,CV_32FC1);
      distortion_coeffs = cvCreateMat(4,1,CV_32FC1);
     
      corners = new CvPoint2D32f[ board_n ];
     
      image = cvQueryFrame( capture );
      gray_image = cvCreateImage(cvGetSize(image),8,1);
     
      // capture d'images tant qu'on n'a pas n_boards succès de détection des coins
      while(successes < n_boards) {
     
        if((frame++ % board_dt) == 0) {
          //Find chessboard corners:
          int found = cvFindChessboardCorners(image, board_sz, corners, &corner_count,CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);
     
          //precision subpixelique des coins
          cvCvtColor(image, gray_image, CV_BGR2GRAY);
          cvFindCornerSubPix(gray_image, corners, corner_count,cvSize(11,11),cvSize(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));
     
          cvDrawChessboardCorners(image, board_sz, corners,corner_count, found);
          cvShowImage( "Calibration", image );
     
           // ajout du damier détecté aux données
          if( corner_count == board_n && found) {
    	step = successes*board_n;
    	for( int i=step, j=0; j<board_n; ++i,++j ) {
    	  CV_MAT_ELEM(*image_points, float,i,0) = corners[j].x;
    	  CV_MAT_ELEM(*image_points, float,i,1) = corners[j].y;
    	  CV_MAT_ELEM(*object_points,float,i,0) = j/board_w;
    	  CV_MAT_ELEM(*object_points,float,i,1) = j%board_w;
    	  CV_MAT_ELEM(*object_points,float,i,2) = 0.0f;
    	}
    	CV_MAT_ELEM(*point_counts, int,successes,0) = board_n;   
    	successes++;
    	printf("Collected our %d of %d needed chessboard images\n",successes,n_boards);
          }
        } 
     
        cvWaitKey(15);
        image = cvQueryFrame( capture ); 
      }
     
      //ALLOCATE MATRICES ACCORDING TO HOW MANY CHESSBOARDS FOUND
      object_points2  = cvCreateMat(successes*board_n,3,CV_32FC1);
      image_points2   = cvCreateMat(successes*board_n,2,CV_32FC1);
      point_counts2   = cvCreateMat(successes,1,CV_32SC1);
      //TRANSFER THE POINTS INTO THE CORRECT SIZE MATRICES
      for(int i = 0; i<successes*board_n; ++i){
        CV_MAT_ELEM( *image_points2, float, i, 0) =
          CV_MAT_ELEM( *image_points, float, i, 0);
        CV_MAT_ELEM( *image_points2, float,i,1) =   
          CV_MAT_ELEM( *image_points, float, i, 1);
        CV_MAT_ELEM(*object_points2, float, i, 0) = 
          CV_MAT_ELEM( *object_points, float, i, 0) ;
        CV_MAT_ELEM( *object_points2, float, i, 1) =
          CV_MAT_ELEM( *object_points, float, i, 1) ;
        CV_MAT_ELEM( *object_points2, float, i, 2) =
          CV_MAT_ELEM( *object_points, float, i, 2) ;
      }
      for(int i=0; i<successes; ++i){ //These are all the same number
        CV_MAT_ELEM( *point_counts2, int, i, 0) =
          CV_MAT_ELEM( *point_counts, int, i, 0);
      }
     
      // At this point we have all of the chessboard corners we need.
      // Initialize the intrinsic matrix such that the two focal
      // lengths have a ratio of 1.0
      //
      CV_MAT_ELEM( *intrinsic_matrix, float, 0, 0 ) = 1.0f;
      CV_MAT_ELEM( *intrinsic_matrix, float, 1, 1 ) = 1.0f;
     
      //CALIBRATE THE CAMERA!
      cvCalibrateCamera2(object_points2, image_points2, point_counts2,  cvGetSize( image ), intrinsic_matrix, distortion_coeffs, NULL, NULL, 0 );
     
      // Build the undistort map which we will use for all
      // subsequent frames.
      IplImage* mapx = cvCreateImage( cvGetSize(image), IPL_DEPTH_32F, 1 );
      IplImage* mapy = cvCreateImage( cvGetSize(image), IPL_DEPTH_32F, 1 );
      cvInitUndistortMap(intrinsic_matrix,distortion_coeffs,mapx,mapy);
     
     
     
      /**********************************************/
      //calibration terminée, maintenant on va récupérer la position de la caméra par rapport au damier
     
      CvMat* rotation_vector  = cvCreateMat(3,1,CV_32FC1); //matrice de rotation de la caméra par rapport au damier
      CvMat* translation_vector = cvCreateMat(3,1,CV_32FC1); //matrice de translation de la caméra par rapport au damier
     
      int found;
     
      IplImage *grey = cvCreateImage( cvGetSize(image), 8, 1 ); //image courante en niveau de gris
      IplImage *prev_grey = cvCreateImage( cvGetSize(image), 8, 1 ); //image précédente en niveau de gris
      IplImage *pyramid = cvCreateImage( cvGetSize(image), 8, 1 ); //pyramide courante
      IplImage *prev_pyramid = cvCreateImage( cvGetSize(image), 8, 1 ); //pyramide précédente
      CvPoint2D32f* points[2] = {0,0}, *swap_points;
      points[0] = (CvPoint2D32f*)cvAlloc(board_n*sizeof(points[0][0])); //points précédents du damier
      points[1] = (CvPoint2D32f*)cvAlloc(board_n*sizeof(points[0][0])); //points courants du damier
      char *status = 00;
      status=(char*)cvAlloc(board_n);
      int flags = 0;
      IplImage* swap_temp;
      int win_size = 10;
     
      cvNamedWindow( "Undistort" );
     
      image = cvQueryFrame( capture );
      cvCvtColor( image, prev_grey, CV_BGR2GRAY );
     
      //recherche du damier
      found = cvFindChessboardCorners(image, board_sz, corners, &corner_count,CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FILTER_QUADS);
     
      cvCvtColor(image, gray_image, CV_BGR2GRAY);
     
      //precision subpixelique
      cvFindCornerSubPix(gray_image, corners, corner_count,cvSize(11,11),cvSize(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));
     cvDrawChessboardCorners(image, board_sz, corners,corner_count, found);
      cvShowImage( "Calibration", image );
     
      //cvWaitKey(0);
     
      CV_SWAP( corners, points[0], swap_points );//on met les points calculés juste avant dans points[0]
     
      while(image) {
        //affichage de l'image non distordue
        image = cvQueryFrame( capture );
        IplImage *t = cvCloneImage(image);
        cvShowImage( "Raw Video", image ); // Show raw image
        cvRemap( t, image, mapx, mapy );   // image non distordue
     
        cvReleaseImage(&t);
        cvShowImage("Undistort", image);   // image non distordue
     
     
        //recherche de la nouvelle position du damier par flot optique
        image = cvQueryFrame( capture );
        cvCvtColor( image, grey, CV_BGR2GRAY );
     
        //recherche des points de l'image précédente points[0] dans la nouvelle image par flot optique
        cvCalcOpticalFlowPyrLK( prev_grey, grey, prev_pyramid, pyramid, points[0], points[1], corner_count, cvSize(win_size,win_size), 5, status, 0, cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 20,0.3), flags);
     
        //precision subpixelique
        cvFindCornerSubPix(grey,points[1], corner_count,cvSize(11,11),cvSize(-1,-1), cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));
     
        //on dessine les points
        cvDrawChessboardCorners(image, board_sz, points[1],corner_count, found);
        cvShowImage( "Calibration", image );
     
        // If we got a good board, add it to our data
        //successes=0;
        if( corner_count == board_n ) {
          step = successes*board_n;
          for( int i=0, j=0; j<board_n; ++i,++j ) {
    	CV_MAT_ELEM(*image_points, float,i,0) = points[1][j].x;
    	CV_MAT_ELEM(*image_points, float,i,1) = points[1][j].y;
    	CV_MAT_ELEM(*object_points,float,i,0) = j/board_w;
    	CV_MAT_ELEM(*object_points,float,i,1) = j%board_w;
    	CV_MAT_ELEM(*object_points,float,i,2) = 0.0f;
          }
          //successes++;
     
          cvFindExtrinsicCameraParams2(object_points, image_points,intrinsic_matrix,distortion_coeffs,rotation_vector, translation_vector);
     
          }
     
        //cout<<CV_MAT_ELEM( *translation_vector, float, 0,0)<<" "<<CV_MAT_ELEM( *translation_vector, float, 1,0)<<" "<<CV_MAT_ELEM( *translation_vector, float, 2,0)<<endl;
        printf("%lf  %lf  %lf \n",CV_MAT_ELEM( *translation_vector, float, 0,0),CV_MAT_ELEM( *translation_vector, float, 1,0),CV_MAT_ELEM( *translation_vector, float, 2,0));
     
     
        //les données courantes deviennent les données précédentes
        CV_SWAP( prev_grey, grey, swap_temp ); //CV_SWAP(a,b,tmp) met b dans a et a dans b
        CV_SWAP( prev_pyramid, pyramid, swap_temp );
        CV_SWAP( points[0], points[1], swap_points );
     
     
        cvWaitKey(15);
     
      }
     
      return 0;
    }
    Quelqu'un aurait-il une idée du pourquoi j'ai ces valeurs et comment les corriger ?

  2. #2
    Membre averti
    Inscrit en
    Octobre 2010
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 18
    Par défaut
    Voilà où j'en suis maintenant : j'ai un peu mieux compris les valeurs que j'obtiens, j'arrive à obtenir une assez bonne calibration en ce qui concerne la translation du damier par rapport à la caméra mais j'ai un problème avec la rotation.
    Ce que je fais en fait, c'est déplacer un objet 3D dans opengl comme si c'était mon damier. Il translate donc correctement selon les axes quand je bouge mon damier devant ma caméra mais je n'arrive pas à reproduire les rotations
    Comment faire svp? Calibration particulière? Comment transcrire la rotation renvoyée par opencv en opengl?

    Merci

  3. #3
    Membre averti
    Inscrit en
    Octobre 2010
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Octobre 2010
    Messages : 18
    Par défaut
    Je reviens vers vous car je n'ai toujours pas résolu mon problème. En fait, j'aurais une question pour m'éclaircir les idées, pour comprendre même ma calibration.

    Donc, dans le code opencv pour la calibration comme dans tout ce que j'ai pu trouver sur internet, il y a cette partie :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
    //coordonnées du point dans l'image donc en pixel
    CV_MAT_ELEM(*image_points, float,i,0) = points[1][j].x;
    CV_MAT_ELEM(*image_points, float,i,1) = points[1][j].y;
     
    //coordonnées du point dans le repère du damier 7x7, un côté de case représente une unité donc les coins ont pour coordonnées (0,0) (0,1)...(0,6) ... , (6,0)...(6,6)
    CV_MAT_ELEM(*object_points,float,i,0) = j/board_w; 
    CV_MAT_ELEM(*object_points,float,i,1) = j%board_w;
    Mon problème est qu'une fois la calibration faite, mon objet 3D openGL bouge bien quand je déplace mon damier devant ma caméra, mais je ne comprends pas du tout le lien entre les valeurs de translation renvoyées par opencv et mes valeurs réelles : par exemple, je déplace mon damier de 5cm sur l'axe des x en réalité, et le déplacement opencv est de 0.0017 sur x (je donne une valeur comme ça car ça change d'une calibration à l'autre).
    Ce que je voudrais, c'est connaître la correspondance entre mes valeurs réelles et celles d'opencv. Dans le livre "Learning openCV", il est écrit que le paramètre object_points doit contenir les coordonnées des points dans le repère du damier, soit (0,0)....(6,6) si on prend une case comme unité. J'ai donc essayé en ne considérant pas une case comme unité mais en lui donnant sa dimension réelle (2.2 cm sur mon damier).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    //coordonnées du point dans le repère du damier 7x7, un côté de case représente une unité donc les coins ont pour coordonnées (0,0) (0,1)...(0,6) ... , (6,0)...(6,6)
    CV_MAT_ELEM(*object_points,float,i,0) = (j/board_w)*2.2; 
    CV_MAT_ELEM(*object_points,float,i,1) = (j%board_w)*2.2;
    Au final, je n'arrive plus à avoir une calibration correcte, les valeurs varient sans cesse même quand le damier est fixe.

    Un peu d'aide ne serait pas de refus!
    Merci

  4. #4
    Invité
    Invité(e)
    Par défaut
    Il faut utiliser la fonction "Rodriges" pour convertir le vecteur (4x1) fourni par OpenCV en matrice de rotation (3x3) ou (4x4)....

Discussions similaires

  1. [Web Service] Problème d'affichage des valeurs renvoyées par un webservice
    Par informatique34 dans le forum Bibliothèques et frameworks
    Réponses: 6
    Dernier message: 11/07/2011, 13h34
  2. affichage dans une interface des valeurs renvoyées par le port rs232
    Par EmilieGh dans le forum Bibliothèques, systèmes et outils
    Réponses: 5
    Dernier message: 20/05/2011, 17h51
  3. Réponses: 4
    Dernier message: 30/08/2008, 01h39
  4. Comment récuperer des valeurs renvoyées par Link
    Par 19cmos83 dans le forum Struts 1
    Réponses: 1
    Dernier message: 22/05/2008, 18h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo