立体视觉:相机较正(含代码)

立体视觉:相机较正(含代码)

这篇文章阐述的相机的较正原理,不涉及相机的标定问题,即假设我们已经对相机进行了标定,得到了相机的投影矩阵和畸变参数。

较正可分为三个过程。

(1)首先,是计算新的投影矩阵(我把它命名为扩展投影矩阵),此矩阵用于恢复未较正坐标的相机坐标(即三维点在相机坐标系中坐标)。其实,这里没有真正计算出三维坐标,只是一个相对关系,但可以用此三维坐标重投影得到较正坐标。我们设扩展投影矩阵为camNewMat。计算camNewMat的输入参数包括投影矩阵、畸变参数及图像尺寸,还可以设置主点是否为未较正图像的中心。得到camNewMat的同时,我们还可以得到较正后的图像的有效区域。这里,有效区域是这些区域,在未较正图像中可以找到对应区域的区域。较正图像中,还可能存在一些无区域,即在未较正图像中找不到对应区域的区域。

(2)其次,是根据扩展投影矩阵计算未较正坐标的相机坐标。这个容易进行。若设未较正坐标为Y=(u,v,1)T,相机坐标为X=(x,y,z)T。由成像模型可知,Y=camNewMat.X。所以X=inverse(camNewMat)Y。

(3)最后,就是将相机坐标重投影到像素坐标,即较正坐标。设投影矩阵为camMat,由成像模型可知,较正坐标Z=camMat.X。

过程(2)(3)在OpenCV中的源码如下。我对代码进行了相应的精简和调整,以更好理解。函数输出的是两个映射矩阵,用这两个矩阵再结合remap函数就能将未较正图像映射为较正图像。

 

 1 void initUndistortRectifyMap1(InputArray _camMat, InputArray _distoration,InputArray _rotation, InputArray _newCamMat,Size size, int type, OutputArray _map1, OutputArray _map2 )
 2 
 3 {
 4     Mat_<double> camMat = _camMat.getMat();
 5     Mat_<double> distoration = _distoration.getMat();
 6     Mat_<double> rotation = _rotation.getMat();
 7     Mat_<double> newCamMat = _newCamMat.getMat();
 8     _map1.create(size, type);//暂不考虑CV_32FC情况
 9     _map2.create(size, type == CV_16SC2 ? CV_16UC1 : CV_32FC1 );
10     Mat map1 = _map1.getMat();
11     Mat map2 = _map2.getMat();
12 
13    //计算扩展投影矩阵的逆
14     if(newCamMat.empty()) newCamMat = getDefaultNewCameraMatrix(camMat, size, true );//若未计算扩展投影矩阵则用投影矩阵代替
15     if(rotation.empty()) rotation = Mat_<double>::eye(3, 3);//单目的情况
16     Mat_<double> iR = (newCamMat.colRange(0,3)*rotation).inv(DECOMP_LU);
17 
18     //获取相机参数
19     double cx = camMat(0, 2);
20     double cy = camMat(1, 2);
21     double fx = camMat(0, 0);
22     double fy = camMat(1, 1);
23 
24     //获取畸变参数
25     double k1 = distoration(0);
26     double k2 = distoration(1);
27     double p1 = distoration(2);
28     double p2 = distoration(3);
29     double k3 = distoration.total() >= 5 ? distoration(4) : 0.;
30     double k4 = distoration.total() >= 8 ? distoration(5) : 0.;
31     double k5 = distoration.total() >= 8 ? distoration(6) : 0.;
32     double k6 = distoration.total() >= 8 ? distoration(7) : 0.;
33     double s1 = distoration.total() >= 12 ? distoration(8) : 0.;
34     double s2 = distoration.total() >= 12 ? distoration(9) : 0.;
35     double s3 = distoration.total() >= 12 ? distoration(10) : 0.;
36     double s4 = distoration.total() ? distoration(11) : 0.;
37 
38     //计算映射关系
39     for( int i = 0; i < size.height; i++ )
40 {
41         double x = i*iR(0,1) + iR(0,2);
42         double y = i*iR(1,1) + iR(1,2);
43         double z = i*iR(2,1) + iR(2,2);
44 
45         for( int j = 0; j < size.width; j++, x += iR(0,0), y += iR(1,0), z += iR(2,0) )
46         {
47             double wz = 1./z;if(z>1.0000001){cout<<z;getchar();}
48             ouble wx = x/wz;
49             double wy = y/wz;
50             double x2 = wx*wx;
51             double y2 = wy*wy;
52             double r2 = x2 + y2;
53             double _2xy = 2*wx*wy;
54             double kr = (1 + ((k3*r2 + k2)*r2 + k1)*r2)/(1 + ((k6*r2 + k5)*r2 + k4)*r2);
55             double u = fx*(x*kr + p1*_2xy + p2*(r2 + 2*x2) + s1*r2+s2*r2*r2) + cx;
56             double v = fy*(y*kr + p1*(r2 + 2*y2) + p2*_2xy + s3*r2+s4*r2*r2) + cy;
57             map1.at<float>(i,j)=(float)u;
58             map2.at<float>(i,j)=(float)v;
59         }
60     }
61 }
View Code

关于过程(1)的原理还没弄明白。明白了再写吧。

你可能感兴趣的:(立体视觉:相机较正(含代码))