Calibración de cámara OpenCV

La dirección reciente se ha decidido hacia la visión estereoscópica binocular, principalmente investigando sobre reconstrucción. El proceso general es adquisición de imágenes -> calibración de la cámara -> extracción de características -> coincidencia -> reconstrucción tridimensional. Por supuesto, el preprocesamiento y la corrección de la imagen se pueden realizar al principio, y más adelante se puede realizar un procesamiento adicional de la nube de puntos, como renderizando la superficie para acercarla al objeto real.

  La adquisición de imágenes es relativamente simple: use una cámara para capturar un objeto objetivo (escena grande u objeto interior pequeño específico). Pero hay dos puntos a tener en cuenta:

  1. Las imágenes necesarias para la reconstrucción binocular son generalmente dos y la diferencia de ángulo no debe ser demasiado grande; de ​​lo contrario, habrá muy pocas partes comunes y el efecto de reconstrucción será deficiente; todo el proceso es simple y el costo no es alto. pero la desventaja es que solo hay dos imágenes y la información del objeto representada por la nube de puntos no será completa;

  2. Las imágenes requeridas para la calibración se toman por separado. Si utiliza el método de calibración de Zhang Zhengyou, pegue la imagen del tablero de ajedrez en blanco y negro al cartón y luego tome las cámaras izquierda y derecha por separado. En teoría, cuantos más ángulos (imágenes) pueda Cuanto más ángulos (imágenes) obtenga, más preciso será el resultado final de la calibración; la placa de calibración se muestra en la siguiente figura:

 

  Aquí damos principalmente una breve introducción a la calibración de la cámara izquierda y derecha basada en OpenCV. Espero que mis amigos puedan corregirme, comunicarse y progresar juntos.

  El problema de calibración de la cámara es un problema introductorio en el campo de la visión artificial y se puede dividir en métodos tradicionales de calibración de cámaras y métodos de autocalibración de cámaras. Existen muchos métodos de calibración, los más comunes son: Tsai (tradicional) y Zhang Zhengyou (entre tradicional y autocalibración), etc.

  Modelo de imágenes de cámara y cuatro sistemas de coordenadas (principios generales).

 

  El modelo de cámara adopta el modelo estenopeico clásico, como se muestra en la figura Oc (centro óptico), el plano de la imagen π representa el plano del campo de visión y su distancia al centro óptico es f (distancia focal de la lente).

  Los cuatro sistemas de coordenadas son: sistema de coordenadas mundial (Ow), sistema de coordenadas de la cámara (Oc), sistema de coordenadas físicas de la imagen (O1, unidad mm), sistema de coordenadas de píxeles de la imagen (O, ubicado en la esquina superior izquierda del plano del campo de visión). , foto de la unidad).

  El proceso de conversión de coordenadas desde un cierto punto P en el espacio a su punto de imagen p se realiza principalmente a través de tres transformaciones de estos cuatro conjuntos de sistemas de coordenadas: primero, el sistema de coordenadas mundial se traduce y convierte para obtener el sistema de coordenadas de la cámara, y luego las coordenadas físicas de la imagen se obtienen de acuerdo con el sistema de transformación geométrica triangular y, finalmente, el sistema de coordenadas de píxeles de la imagen se obtiene en función de la relación de píxeles a unidades métricas. (El proceso de aplicación real es el proceso inverso a este, es decir, la longitud real se conoce a partir de la longitud del píxel).

  ps: mediante la calibración de la cámara, se puede obtener la resolución mm / pix en el plano del campo de visión. Para objetos fuera del plano del campo de visión, aún es necesario obtener el plano del campo de visión mediante la conversión de coordenadas.

  Para conocer el proceso de conversión y la fórmula, consulte: Principio de calibración de la cámara (la clave son los tres sistemas de coordenadas).ppt

 

  2 principios del algoritmo de Zhang Zhengyou

  El método zhang toma fotografías completas de una determinada placa objetivo varias veces (más de tres veces) en diferentes direcciones sin conocer el movimiento de la placa objetivo. Obtenga directamente los parámetros internos de la cámara (matriz de referencia A) y coeficientes de distorsión. Este método de calibración es más preciso que el método de autocalibración y no requiere instrumentos de posicionamiento de alta precisión.

  El algoritmo de ZHANG contiene dos modelos: 1. Modelo estenopeico clásico, que incluye cuatro sistemas de coordenadas, y 2. Modelo de distorsión (se desconoce la fuente de este).

 

  Los tres términos de la fórmula representan a su vez distorsión radial, distorsión tangencial y distorsión de prisma fino. La función en OPENCV solo puede dar k1, k2, p1, p2.

Existe otro modelo de distorsión; consulte la página 26 del artículo "Diseño y verificación experimental de la biblioteca de algoritmos de calibración de cámaras".

 

  Zhang Zhengyou calibró la caja de herramientas TOOLBOX_CAL de matlab y la biblioteca OpenCV. El siguiente es el código de C ++ combinado con OpenCV:

  1 #include "cvut.h"
  2 #include <iostream>
  3 #include <fstream>
  4 #include <string>
  5 using namespace cvut;
  6 using namespace std;
  7 void main() 
  8 {
  9      ifstream fin("calibdata.txt");
 10      ofstream fout("calibration_result.txt"); 
 11      //****************开始提取角点***********************//
 12      cout<<"开始提取角点………………";
 13      int image_count=0; 
 14      CvSize image_size; 
 15      CvSize board_size = cvSize(5,7);   
 16      CvPoint2D32f * image_points_buf =
 17                 new CvPoint2D32f[board_size.width*board_size.height];  
 18      Seq<CvPoint2D32f> image_points_seq; 
 19      string filename;
 20      while (std::getline(fin,filename))
 21      {
 22           cout<<"\n 将鼠标焦点移到标定图像所在窗口"
 23           <<"并输入回车进行下一幅图像的角点提取 \n";
 24           image_count++;
 25           int count;
 26           Image<uchar> view(filename); 
 27           if (image_count == 1)
 28           {
 29                image_size.width = view.size().width;
 30                image_size.height = view.size().height;
 31           }
 32           if (0 == cvFindChessboardCorners( view.cvimage, board_size,
 33                 image_points_buf, &count, CV_CALIB_CB_ADAPTIVE_THRESH ))
 34           {
 35                 cout<<"can not find chessboard corners!\n";
 36                 exit(1);
 37           }
 38           else
 39          {
 40            Image<uchar> view_gray(view.size(),8,1);
 41            rgb2gray(view,view_gray);
 42            cvFindCornerSubPix( view_gray.cvimage, 
 43            image_points_buf, count, cvSize(11,11),
 44            cvSize(-1,-1), 
 45            cvTermCriteria( CV_TERMCRIT_EPS+CV_TERMCRIT_ITER, 30, 0.1 ));
 46            image_points_seq.push_back(image_points_buf,count);
 47            cvDrawChessboardCorners( view.cvimage, board_size, 
 48                     image_points_buf, count, 1);
 49            view.show("calib");
 50            cvWaitKey(); 
 51            view.close();
 52          }
 53      }//角点提取循环
 54      delete []image_points_buf; 
 55      cout<<"角点提取完成!\n"<<endl;
 56      cout<<"开始定标………………"<<"\n"<<endl;
 57      CvSize square_size = cvSize(10,10); 
 58      Matrix<double> object_points(1,
 59                 board_size.width*board_size.height*image_count,3);
 60      Matrix<double> image_points(1,image_points_seq.cvseq->total,2);
 61      Matrix<int>    point_counts(1,image_count,1);
 62      Matrix<double> intrinsic_matrix(3,3,1);
 63      Matrix<double> distortion_coeffs(1,4,1);
 64      Matrix<double> rotation_vectors(1,image_count,3);
 65      Matrix<double> translation_vectors(1,image_count,3);
 66      int i,j,t;
 67      for (t=0;t<image_count;t++) {
 68           for (i=0;i<board_size.height;i++) {
 69                for (j=0;j<board_size.width;j++) {
 70                     object_points(0,t*board_size.height*board_size.width
 71                     + i*board_size.width + j,0) = i*square_size.width;
 72                     object_points(0,t*board_size.height*board_size.width
 73                     + i*board_size.width + j,1) = j*square_size.height;
 74                     object_points(0,t*board_size.height*board_size.width
 75                     + i*board_size.width + j,2) = 0;
 76                }
 77           }
 78      }
 79      char  str[10];
 80      itoa(image_points_seq.cvseq->total,str,10);
 81      cout<<str<<"\n"<<endl;
 82      for (i=0;i<image_points_seq.cvseq->total;i++)
 83      {
 84             image_points(0,i,0) = image_points_seq[i].x;
 85             image_points(0,i,1) = image_points_seq[i].y;
 86      }
 87      for (i=0;i<image_count;i++)
 88     {
 89            point_counts(0,i) = board_size.width*board_size.height;
 90     }
 91      cvCalibrateCamera2(object_points.cvmat,
 92             image_points.cvmat,
 93             point_counts.cvmat,
 94             image_size,
 95             intrinsic_matrix.cvmat,
 96             distortion_coeffs.cvmat,
 97             rotation_vectors.cvmat,
 98             translation_vectors.cvmat,
 99             0);
100      cout<<"定标完成!\n";
101      cout<<"标定结果显示\n";
102      cout<<"***************************************\n";
103      cout<<"相机内参intrinsic_matrix\n";
104      for(int h=0;h<3;h++)
105      {
106         cout<<"X:"<<intrinsic_matrix(h,0,0)<<"\tY:"<<
107         intrinsic_matrix(h,1,0)<<"\tZ:"<<intrinsic_matrix(h,2,0)
108         <<"\n";
109      }
110      cout<<"\n畸变系数:distortion_coeffs\n";
111      for(int ndis=0;ndis<4;ndis++)
112      {
113         cout<<distortion_coeffs(0,ndis,0)<<"\\";
114      }
115      cout<<"\n";
116      cout<<"\nrotation_vectors\n";
117      for(int rot=0;rot<7;rot++)
118      {
119            cout<<"X:"<<rotation_vectors(0,rot,0)<<"\tY:"
120            <<rotation_vectors(0,rot,1)<<"\tZ:"<<rotation_vectors(0,rot,2)
121            <<"\n";
122      }
123      cout<<"\ntranslation_vectors\n";
124      for(i=0;i<7;i++)
125      {
126           cout<<"第"<<i+1<<"张图"<<"\tX:"<<translation_vectors(0,i,0)
127           <<"\tY:"<<translation_vectors(0,i,1)
128           <<"\tZ:"<<translation_vectors(0,i,2)<<"\n";
129      }
130      cout<<"*********************\n";
131      cout<<"开始评价定标结果………………\n";
132      double total_err = 0.0;
133      double err = 0.0;
134      Matrix<double> image_points2(1,point_counts(0,0,0),2);
135      int temp_num  = point_counts(0,0,0); 
136      cout<<"\t每幅图像的定标误差:\n";
137      fout<<"每幅图像的定标误差:\n";
138      for (i=0;i<image_count;i++)
139      {
140           cvProjectPoints2(object_points.get_cols(i * 
141               point_counts(0,0,0),(i+1)*point_counts(0,0,0)-1).cvmat,
142               rotation_vectors.get_col(i).cvmat,
143               translation_vectors.get_col(i).cvmat,
144               intrinsic_matrix.cvmat,
145               distortion_coeffs.cvmat,
146               image_points2.cvmat,
147               0,0,0,0);
148               err = cvNorm(image_points.get_cols(i*point_counts(0,0,0),(i+1)
149               *point_counts(0,0,0)-1).cvmat,
150               image_points2.cvmat,
151               CV_L1);
152           total_err += err/=point_counts(0,0,0);
153           cout<<"****************************\n";
154           cout<<"\t\t第"<<i+1<<"幅图像的平均误差:"<<err<<"像素"<<'\n';
155           fout<<"\t第"<<i+1<<"幅图像的平均误差:"<<err<<"像素"<<'\n';
156           cout<<"显示image_point2\n";
157           for(int ih=0;ih<7;ih++)
158           {
159                 cout<<"X:"<<image_points2(0,ih,0)<<"\tY:"
160                 <<image_points2(0,ih,1)<<"\n";
161           }
162           cout<<"显示object_Points\n";
163           for(int iw=0;iw<7;iw++)
164           {
165                cout<<"X:"<<image_points.get_cols(i*point_counts(0,0,0),(i+1)
166                *point_counts(0,0,0)-1)(0,iw,0)
167                <<"\tY:"<<image_points.get_cols(i*point_counts(0,0,0),(i+1)
168                *point_counts(0,0,0)-1)(0,iw,1)<<"\n";
169           }
170      }    
171      cout<<"\t总体平均误差:"<<total_err/image_count<<"像素"<<'\n';
172      fout<<"总体平均误差:"<<total_err/image_count<<"像素"<<'\n'<<'\n';
173      cout<<"评价完成!\n";
174      cout<<"开始保存定标结果………………";
175      Matrix<double> rotation_vector(3,1);
176      Matrix<double> rotation_matrix(3,3);
177      fout<<"相机内参数矩阵:\n";
178      fout<<intrinsic_matrix<<'\n';
179      fout<<"畸变系数:\n";
180      fout<<distortion_coeffs<<'\n';
181      for (i=0;i<image_count;i++) {
182      fout<<"第"<<i+1<<"幅图像的旋转向量:\n";
183      fout<<rotation_vectors.get_col(i);
184      for (j=0;j<3;j++) 
185      {
186         rotation_vector(j,0,0) = rotation_vectors(0,i,j);
187      }
188      cvRodrigues2(rotation_vector.cvmat,rotation_matrix.cvmat);
189      fout<<"第"<<i+1<<"幅图像的旋转矩阵:\n";
190      fout<<rotation_matrix;
191      fout<<"第"<<i+1<<"幅图像的平移向量:\n";
192      fout<<translation_vectors.get_col(i)<<'\n';
193     }
194     cout<<"完成保存\n";
195 }

  Este programa se puede ejecutar directamente. Lo estoy ejecutando en un entorno vs2010 + OpenCV2.4.0. La configuración se presentó en el artículo anterior. El nombre de la secuencia de imágenes de la placa de calibración se coloca en el archivo "calibdata.txt", con un nombre de imagen por línea. El problema de la intensidad de la ruta no se discutirá aquí. como

    imagen/ajedrez1.jpg
    imagen/ajedrez2.jpg

    ……

  El resultado final de la calibración se almacena en "calibration_result.txt" y la ventana de la línea de comando también mostrará cierta información. Al observar los resultados, encontrará que la matriz de parámetros internos de la cámara M1 y los coeficientes de distorsión k1, k2, p1, p2 se resuelven llamando directamente a la función de calibración en OpenCV, así como la matriz de rotación R' (o vector de rotación) de cada uno. imagen relativa al plano de imagen de la cámara correspondiente) y el vector de traducción t', no el sistema de coordenadas mundiales relativo al sistema de coordenadas de la cámara, ni la relación espacial entre las dos cámaras. En cuanto al parámetro externo [R t], siempre ha sido un problema muy abstracto.

  Durante el proceso de reconstrucción se requieren dos elementos principales:

  1. Cámara interna M1, parámetro externo M2 (o matriz de proyección M=M1*M2)

  2. Coincidencia de pares de puntos característicos en los planos de imagen izquierdo y derecho

  Finalmente, las coordenadas de los puntos espaciales correspondientes a los puntos característicos del objeto se calculan mediante el principio de paralaje y se obtiene la nube de puntos final.

  Por supuesto, aquellos que estén interesados ​​pueden continuar estudiando e investigando. Los parámetros externos se pueden calcular utilizando una serie de relaciones matemáticas a través de puntos en la imagen y coordenadas espaciales de puntos en el objeto en el sistema de coordenadas mundial obtenido previamente.

  En la operación real, la autocalibración se puede realizar durante el proceso de reconstrucción, es decir, no es necesario calibrar por separado para obtener los parámetros de la cámara, sino calcular directamente la matriz de proyección a través de pares de puntos característicos. Los siguientes pasos son los mismos que los anteriores. Por supuesto, la precisión de los resultados obtenidos mediante la autocalibración no es muy alta. Actualmente, el método de calibración de Zhang Zhengyou mencionado anteriormente se usa con más frecuencia, que se encuentra entre el tradicional y la autocalibración. 

 Únase al grupo para recibir materiales de aprendizaje sobre desarrollo de Qt e intercambios técnicos a continuación ↓↓↓↓↓↓↓↓ 

Supongo que te gusta

Origin blog.csdn.net/hw5230/article/details/130266338
Recomendado
Clasificación