1、双目摄像头协同工作#include stdafx.h#include camerads.h#include #include #include #include #include #include / 单窗口显示多幅图像的函数voidcvShowMultiImages(char* title, intnArgs, .) / 略,详见学习笔记(5)int main( intargc, char* argv ) intcam_count;/仅仅获取摄像头数目cam_count = CCameraDS:CameraCount();printf(There are %d cameras./n, cam
2、_count);/获取所有摄像头的名称for(inti=0; i0)printf(Camera #%ds Name is %s./n, i, camera_name);elseprintf(Can not get Camera #%ds name./n, i); if(cam_count=0)return -1;/ 创建2个摄像头类CCameraDS camera1;CCameraDS camera2; /打开第一个摄像头 /if(! camera.OpenCamera(0, true) /弹出属性选择窗口if(! camera1.OpenCamera(0, false, 320,240) /
3、不弹出属性选择窗口,用代码制定图像宽和高 fprintf(stderr, Can not open camera./n);return -1; /打开第二个摄像头camera2.OpenCamera(1, false, 320,240);cvNamedWindow(Multiple Cameras);/ 初始化在子图像中显示字符的字体格式CvFonttFont;cvInitFont(&tFont, CV_FONT_HERSHEY_COMPLEX, 0.5f,0.7f,0,1,8);char cam1str = Camera #1;char cam2str = Camera #2;/ 为读取系统
4、时间信息分配内存chartimestr25;memset(timestr, 0, 25 * sizeof(char); while(1) /获取一帧IplImage *pFrame1 = camera1.QueryFrame();IplImage *pFrame2 = camera2.QueryFrame();/ 获取当前帧的灰度图IplImage* frame_gray_1 = cvCreateImage(cvGetSize(pFrame1),pFrame1-depth,1);IplImage* frame_gray_2 = cvCreateImage(cvGetSize(pFrame2),
5、pFrame2-depth,1);cvCvtColor(pFrame1,frame_gray_1,CV_RGB2GRAY);cvCvtColor(pFrame2,frame_gray_2,CV_RGB2GRAY);/ 对灰度图像进行Canny边缘检测 / 然后将图像通道数改为三通道IplImage* frame_canny_1 = cvCreateImage(cvGetSize(pFrame1),pFrame1-depth,1);IplImage* frame_canny_2 = cvCreateImage(cvGetSize(pFrame2),pFrame2-depth,1);IplImag
6、e* frame1 = cvCreateImage(cvGetSize(pFrame1),pFrame1-depth,pFrame1-nChannels);IplImage* frame2 = cvCreateImage(cvGetSize(pFrame2),pFrame2-depth,pFrame2-nChannels);cvCanny(frame_gray_1,frame_canny_1,20,75,3);cvCanny(frame_gray_2,frame_canny_2,20,75,3);cvCvtColor(frame_canny_1,frame1,CV_GRAY2BGR);cvCv
7、tColor(frame_canny_2,frame2,CV_GRAY2BGR);/ 获取系统时间信息time_trawtime; struct tm* timeinfo; rawtime = time( NULL ); timeinfo = localtime( &rawtime ); char* p = asctime( timeinfo );/ 字符串 p 的第25个字符是换行符 /n / 但在子图像中将乱码显示 / 故仅读取 p 的前 24 个字符for (inti = 0; i 4);可以看到,原始视差在左移8位(256)并且加上一个修正值之后又右移了4位,最终的结果就是左移4位因此
8、,在实际求距离时,cvReprojectTo3D出来的X/W,Y/W,Z/W都要乘以16 (也就是W除以16),才能得到正确的三维坐标信息Q4:利用双摄像头进行测距的时候世界坐标的原点究竟在哪里?A:世界坐标系的原点是左摄像头凸透镜的光心。说起这个,就不得不提到针孔模型。如图3所示,针孔模型是凸透镜成像的一种简化模型。当物距足够远时(远大于两倍焦距),凸透镜成像可以看作是在焦距处的小孔成像。(ref: 图3. 针孔模型在实际计算过程中,为了计算方便,我们将像平面翻转平移到针孔前,从而得到一种数学上更为简单的等价形式(方便相似三角形的计算),如图4所示。图4. 针孔模型的数学等价形式因此,对应图
9、2就可以知道,世界坐标系原点就是左摄像头针孔模型的针孔,也就是左摄像头凸透镜的光心Q5:f和d的单位是像素,那这个像素到底表示什么,它与毫米之间又是怎样换算的?A:这个问题也与针孔模型相关。在针孔模型中,光线穿过针孔(也就是凸透镜中心)在焦距处上成像,因此,图3的像平面就是摄像头的CCD传感器的表面。每个CCD传感器都有一定的尺寸,也有一定的分辨率,这个就确定了毫米与像素点之间的转换关系。举个例子,CCD的尺寸是8mm X 6mm,分辨率是640X480,那么毫米与像素点之间的转换关系就是80pixel/mm。在实际运用中,我们在数学上将这个像平面等效到小孔前(图4),这样就相当于将在透镜中心
10、点之前假设了一块虚拟的CCD传感器。Q6:为什么cvStereoRectify求出的Q矩阵cx, cy, f都与原来的不同?A:这个在前文有提到过。在实际测量中,由于摄像头摆放的关系,左右摄像头的f, cx, cy都是不相同的。而为了使左右视图达到完全平行对准的理想形式从而达到数学上运算的方便,立体校准所做的工作事实上就是在左右像重合区域最大的情况下,让两个摄像头光轴的前向平行,并且让左右摄像头的f, cx, cy相同。因此,Q矩阵中的值与两个instrinsic矩阵的值不一样就可以理解了。实验结果:实验下来,虽然Block Matching算法本身对精度有所限制,但测距基本能达到能让人接受的
11、精度,结果如下图5所示图5. OpenCV双摄像头测距结果上图中,中、左、右三个物体分别被放在离摄像头50cm, 75cm和90cm的位置。可以看出测距的结果相当不错。当然,上面这幅图是比较好的结果。由于BM算法的限制,同一点云中相同距离的点一般会有正负2厘米之内的误差。图6是利用双目摄像头测物体长宽的结果,可以看出结果似乎不太准确。图6. OpenCV双摄像头测边长结果其中,物体宽为117-88=29mm,但实际宽度为5.2cm,物体高位71-13=58mm,但实际高度为13cm。这方面的误差还是比较难以理解此外,还有一个问题至今尚未完全理解,就是双目摄像头的中心距,为什么采用Tx而不是T向量的长度。因为如果要左右视图重合区域最大化的话两个摄像头的光轴都要与T垂直才是(如图7),这样的话,校正后两个摄像头的中心距应该是T才对。不知道我这样的理解对不对?图7. 双摄像头立体校准俯视图
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1