关于双目立体视觉的一些总结(一)

时间:2023-02-03 08:25:53

由于项目和毕设的需要,最近在做一些立体视觉的东西,总算是把立体视觉建立起来了,中途查了很多相关资料,这里做一个总结。

1.简介:

双目视觉是模拟人类视觉原理,使用计算机被动感知距离的方法。从两个或者多个点观察一个物体,获取在不同视角下的图像,根据图像之间像素的匹配关系,通过三角测量原理计算出像素之间的偏移来获取物体的三维信息。得到了物体的景深信息,就可以计算出物体与相机之间的实际距离,物体3维大小,两点之间实际距离。

2.建立立体视觉

为了精确地求得某个点在三维空间里的深度信息,我们需要获得的参数有焦距f、视差d、摄像头中心距Tx;
为了获得某个点的X坐标和Y坐标,还需要知道左右像平面的坐标系与立体坐标系中原点的偏移cx和cy。
因此我们需要进行下列三个步骤:相机标定,图像校正,立体匹配。

相机标定

  • 标定目的:获取相机的内参(焦距,图像中心,畸变系数等)和外参(R(旋转)矩阵T(平移)矩阵)
    相机标定需要采集标定数据,通常使用打印棋盘格的纸作为特制的标定参照物,摄像头获取该物体的图像,并由此计算摄像头的内外参数。
  • 相机标定有两种方法:
    方法一:Bouguet的Matlab标定工具箱(http://www.vision.caltech.edu/bouguetj/calib_doc/);有比较详细的介绍和使用方法,用起来还是比较方便的,只不过做完标定要继续的话要把标定结果存入xml导入OpenCV再进行。
    方法二:OpenCV的cvStereoCalibrate;在《学习OpenCV》第11,12章有比较详细的介绍。12章后有相关程序代码。

双目图像校正

双目校正是根据摄像头定标后获得的单目内参数据(焦距、成像原点、畸变系数)和双目相对位置关系(旋转矩阵和平移向量),分别对左右视图进行消除畸变和行对准,使得左右视图的成像原点坐标一致、两摄像头光轴平行、左右成像平面共面、对极线行对齐。将左右视图调整成完全平行对准的理想形式(如下图)。
关于双目立体视觉的一些总结(一)关于双目立体视觉的一些总结(一)
校正反映到图像上就是要把消除畸变后的两幅图像严格地行对应,使得两幅图像的对极线恰好在同一水平线上,这样一幅图像上任意一点与其在另一幅图像上的对应点就必然具有相同的行号,只需在该行进行一维搜索即可匹配到对应点。下图来自于Stefano Mattoccia
“Stereo vision: algorithms and applications”http://vision.deis.unibo.it/~smatt/Seminars/StereoVision.pdf
(这个ppt对立体视觉做了一个很详尽的讲述,读了可以对立体视觉方面有一个比较好的了解)
关于双目立体视觉的一些总结(一)
我在这部分用的是OpenCV中的cvStereoRectify,得出校准参数之后用cvRemap来校准输入的左右图像。这里要提一下cvRemap这个函数src与dst大小格式通道必须一致,所以在使用之前要先对左右图像做处理。

立体匹配

立体匹配主要是通过找出每对图像间的对应关系,根据三角测量原理,得到视差图;在获得了视差信息后,根据投影模型很容易地可以得到原始图像的深度信息和三维信息。
立体匹配是建立立体视觉中最重要的一环,立体匹配的效果直接影响得到的三维信息。
由于现在只是使用了OpenCV的BM方法和SGBM方法,并没有做深入的了解,所以关于这方面后续会再写篇博客讨论一下这方面的问题。
BM方法:

CvStereoBMState *BMState = cvCreateStereoBMState();
assert(BMState != 0);

BMState->preFilterSize=41;
BMState->preFilterCap=31;
BMState->SADWindowSize=41;
BMState->minDisparity=-64;
BMState->numberOfDisparities=128;
BMState->textureThreshold=10;
BMState->uniquenessRatio=10;

SGBM方法:

cv::StereoSGBM sgbm;
sgbm.preFilterCap = 63;
int SADWindowSize=11;
int cn = 1;
sgbm.SADWindowSize = SADWindowSize > 0 ? SADWindowSize : 3;
sgbm.P1 = 4*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
sgbm.P2 = 32*cn*sgbm.SADWindowSize*sgbm.SADWindowSize;
sgbm.minDisparity = 0;
sgbm.numberOfDisparities = 32;
sgbm.uniquenessRatio = 10;
sgbm.speckleWindowSize = 100;
sgbm.speckleRange = 32;
sgbm.disp12MaxDiff = 1;

立体匹配后得到视差图后获取三维信息的方式(世界坐标系是以左相机光心为原点,光轴为Z轴,基线为X轴的右手系)
这里有一点要注意,立体匹配得出的视差结果是以16位符号数的形式的存储的,出于精度需要,所有的视差在输出时都扩大了16倍(2^4),因此,在实际求距离时,cvReprojectTo3D出来的X/W,Y/W,Z/W都要乘以16 (也就是W除以16),才能得到正确的三维坐标信息。
一个简单的输出某个像素点三维信息的例子:

cvReprojectImageTo3D(disp,depth,&_Qtest);//_Qtest是双目校正得到的Q矩阵
Point p;
p.x = 400;
p.y = 300;

Mat tempDepth = Mat(depth);
cout << "in world coordinate: " << tempDepth.at<Vec3f>(p)*16 << endl;


待续