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 ↓↓↓↓↓↓↓↓