双目测距基本原理:

如图,P是待测物体上的某一点,OR与OT分别是两个相机的光心,点P在两个相机感光器上的成像点分别为P和P’(相机的成像平面经过旋转后放在了镜头前方),

f为相机焦距,B为两相机中心距,Z为我们想求得的深度信息,设点P到点P’的距离为dis,则:

根据相似三角形原理:

可得:

公式中,焦距f和摄像头中心距B可通过标定得到,因此,只要获得了(即,视差d)的值即可求得深度信息。

双目测距实际操作分4个步骤:相机标定——双目校正——双目匹配——计算深度信息。

相机标定:摄像头由于光学透镜的特性使得成像存在着径向畸变,可由三个参数k1,k2,k3确定;由于装配方面的误差,传感器与光学镜头之间并非完全平行,因此成像存在切向畸变,可由两个参数p1,p2确定。单个摄像头的定标主要是计算出摄像头的内参(焦距f和成像原点cx,cy、五个畸变参数(一般只需要计算出k1,k2,p1,p2,对于鱼眼镜头等径向畸变特别大的才需要计算k3))以及外参(标定物的世界坐标)。而双目摄像头定标不仅要得出每个摄像头的内部参数,还需要通过标定来测量两个摄像头之间的相对位置(即右摄像头相对于左摄像头的旋转矩阵R、平移向量t)。

双目校正:双目校正是根据摄像头定标后获得的单目内参数据(焦距、成像原点、畸变系数)和双目相对位置关系(旋转矩阵和平移向量),分别对左右视图进行消除畸变和行对准,使得左右视图的成像原点坐标一致(CV_CALIB_ZERO_DISPARITY标志位设置时发生作用)、两摄像头光轴平行、左右成像平面共面、对极线行对齐。这样一幅图像上任意一点与其在另一幅图像上的对应点就必然具有相同的行号,只需在该行进行一维搜索即可匹配到对应点。

双目匹配:双目匹配的作用是把同一场景在左右视图上对应的像点匹配起来,这样做的目的是为了得到视差图。双目匹配被普遍认为是立体视觉中最困难也是最关键的问题。得到视差数据,通过上述原理中的公式就可以很容易的计算出深度信息。

下面是简单的测距代码,代码中没有相机的标定部分,因为标定数据是之前测好的所以直接拿来用了。

#include <opencv2\opencv.hpp>
#include<iostream>
#include <fstream>using namespace cv;
using namespace std;
//f is 1383.144277、B is 0.21087920785  Z = f * B /d.  f * B = 291.67636947602097445
void mouseHandler(int event, int x, int y, int flags, void* param);
CvMat *disp;  //disparity map
bool left_mouse = false;void main()
{IplImage* imageLeft;IplImage* imageRight;imageLeft = cvLoadImage("image001.pgm"); //读入左侧相机的图像,3通道的imageRight = cvLoadImage("image010.pgm");//读入右侧相机的图像  //int d = imageLeft->depth;int width = imageLeft->width;//图片宽度int height = imageLeft->height;//图片高度//这里是根据图像位数进行灰度值调整,不是必须的,可根据实际情况自行删减cvScale(imageLeft,imageLeft,16, 0);  cvScale(imageRight,imageRight,16, 0);//初始化相机的标定数据,由于不同的相机标定参数不同,所以这里用XX代替double M1[3][3]={xx.x00000,xx.000000,xx.xxx000,xx.000000,xx.xx0000,xx.xxx000,xx.000000,xx.000000,xx.000000};double M2[3][3]={xx.x00000,xx.000000,xx.xxx000,xx.000000,xx.xx0000,xx.xxx000,xx.000000,xx.000000,xx.000000};double D1[5]={x.xxx, x.xxx0, xx.xxx,x.xxx, x.xxx};double D2[5]={x.xxx, x.xxx0, xx.xxx,x.xxx, x.xxx};CvMat _M1calib = cvMat(3, 3, CV_64F, M1 );CvMat _M2calib = cvMat(3, 3, CV_64F, M2 );CvMat _D1      = cvMat(1, 5, CV_64F, D1 );CvMat _D2      = cvMat(1, 5, CV_64F, D2 );double R1[3][3]={xx.x00000,xx.000000,xx.xxx000,xx.000000,xx.xx0000,xx.xxx000,xx.000000,xx.000000,xx.000000};double R2[3][3]={xx.x00000,xx.000000,xx.xxx000,xx.000000,xx.xx0000,xx.xxx000,xx.000000,xx.000000,xx.000000};double P1[3][4]={xx.x00000,xx.000000,xx.xxx000,xx.000000,xx.xx0000,xx.xxx000,xx.000000,xx.000000,xx.000000,xx.000000,xx.000000,xx.000000};double P2[3][4]={xx.x00000,xx.000000,xx.xxx000,xx.000000,xx.xx0000,xx.xxx000,xx.000000,xx.000000,xx.000000,xx.000000,xx.000000,xx.000000};CvMat _R1 = cvMat(3, 3, CV_64F, R1);CvMat _R2 = cvMat(3, 3, CV_64F, R2);CvMat _P1 = cvMat(3, 4, CV_64F, P1);CvMat _P2 = cvMat(3, 4, CV_64F, P2); CvMat* mx1calib = cvCreateMat( height,width, CV_32F );CvMat* my1calib = cvCreateMat( height,width, CV_32F );CvMat* mx2calib = cvCreateMat( height,width, CV_32F );CvMat* my2calib = cvCreateMat( height,width, CV_32F );//双目校正,分别得到左右两个相机的X坐标重映射矩阵和Y坐标重映射矩阵cvInitUndistortRectifyMap(&_M1calib,&_D1,&_R1,&_P1,mx1calib,my1calib);cvInitUndistortRectifyMap(&_M2calib,&_D2,&_R2,&_P2,mx2calib,my2calib);CvMat *img1r,     //rectified left image*img2r,       //rectified right image     *vdisp,     //scaled disparity map for viewing*pair,*depthM;img1r = cvCreateMat( height,width, CV_8U );        //rectified left imageimg2r = cvCreateMat( height,width, CV_8U );      //rectified right imagedisp  = cvCreateMat( height,width, CV_16S );        //disparity mapvdisp = cvCreateMat( height,width, CV_8U );CvStereoBMState *BMState = cvCreateStereoBMState(); assert(BMState != 0);//BMState->preFilterSize = 63;//stereoPreFilterSize; //BMState->preFilterCap = 63;//stereoPreFilterCap;BMState->SADWindowSize = 15;// stereoDispWindowSize; //33BMState->minDisparity = 0;BMState->numberOfDisparities = 48;//stereoNumDisparities; //48BMState->textureThreshold = 20;//stereoDispTextureThreshold; //20BMState->uniquenessRatio = 15;///stereoDispUniquenessRatio;//15BMState->speckleWindowSize = 200;BMState->speckleRange = 32;BMState->disp12MaxDiff = 2;IplImage   *img1,  //left image*img2;img1 = cvCreateImage(cvSize(width,height), IPL_DEPTH_8U, 1);     img2 = cvCreateImage(cvSize(width,height), IPL_DEPTH_8U, 1);cvCvtColor(imageLeft, img1, CV_BGR2GRAY);cvCvtColor(imageRight, img2, CV_BGR2GRAY);cvRemap( img1, img1r, mx1calib, my1calib );cvRemap( img2, img2r, mx2calib, my2calib );cvFindStereoCorrespondenceBM(img1r, img2r, disp, BMState);cvNormalize( disp, vdisp, 0, 256, CV_MINMAX );//cvNamedWindow( "Rectified", 1);//cvNamedWindow( "uDisparity Map",0 );cvNamedWindow( "Disparity Map",0 );//cvShowImage("Rectified", pair);//cvShowImage("uDisparity Map", disp);cvShowImage("Disparity Map", vdisp);cvSetMouseCallback("Disparity Map", mouseHandler, NULL);cvNamedWindow("left",0);//cvNamedWindow("right",0);cvShowImage("left",imageLeft);//cvShowImage("right",imageRight);cvWaitKey(0);cvDestroyWindow("Rectified");cvDestroyWindow("Disparity Map");cvDestroyWindow("left");//cvDestroyWindow("right");cvReleaseImage(&imageLeft);cvReleaseImage(&imageRight);
}void mouseHandler(int event, int x, int y, int flags, void *param){if (event == CV_EVENT_LBUTTONDOWN){cout << "x:" << x<< "y:" << y << endl;//l = cvGet2D(stereoFunc->depthM, x, y);CvScalar s = cvGet2D( disp, y, x );double dep1 = s.val[0];double dep = 291.67636947602097445/dep1;dep *= 16;//int dep2 = cvmGet( vdisp, 1000, 500 );//printf("dep1 = %d\n",dep1);printf("Distance to this object is: %f m \n", dep);left_mouse = true;}else if (event == CV_EVENT_LBUTTONUP){left_mouse = false;}else if ((event == CV_EVENT_MOUSEMOVE) && (left_mouse == true)){}
}

最后得到的视差图:

测距结果:(实际距离8.521m)

双目测距原理与基于opencv的简单实现相关推荐

  1. 基于OpenCV实现简单人脸面具、眼镜、胡须、鼻子特效(详细步骤 + 源码)

    点击下方卡片,关注"OpenCV与AI深度学习"公众号! 视觉/图像重磅干货,第一时间送达! 导读 本文给大家分享一个基于OpenCV实现简单人脸面具.眼镜.胡须.鼻子特效的实例, ...

  2. 图形识别-基于opencv+java简单程序

    前言:如需转载请注明出处: 图形识别-基于opencv+java简单程序_x业精于勤x的博客-CSDN博客 OpenCV的 全称是:Open Source Computer Vision Librar ...

  3. 【双目测距】2 双目测距原理

    主要看下面的注,相似三角形的求解. 傻瓜式讲述,没有比这更直白的了. 双目测距原理推导 如下图,为一组平行双目视觉模型. 平行双目立体视觉模型 让两摄像机光心相距T平行放置. 左右成像仪的像素原点都是 ...

  4. 学习OpenCV双目测距原理及常见问题解答

    转自博客:https://blog.csdn.net/angle_cal/article/details/50800775 一. 整体思路和问题转化.   图1. 双摄像头模型俯视图  图1解释了双摄 ...

  5. OpenCV学习笔记(16)双目测距与三维重建的OpenCV实现问题集锦(一)图像获取与单目定标

    转载地址:http://blog.csdn.net/chenyusiyuan/article/details/5961769 一:双目测距的基本原理 如上图所示,双目测距主要是利用了目标点在左右两幅视 ...

  6. 双目视觉-双目测距原理剖析

    这是一篇好文章, 深入浅出,帮助我们更好地了解了双目相机的工作原理. 1.从相似三角形原理可知,我们仅仅需要分析出左眼图片和右眼图片中,相同物体的两个不同坐标,就可以算出深度值. 2. 计算 两个图片 ...

  7. 水下机器人基于双目测距原理测量鱼长

    这是我发表的第一篇文章,在学习前人和师兄的基础上完成的. 硬件:双目相机 因为是水下机器人拍的,借用了树莓派作为图像处理的平台 效果图: 实现思路:视差-距离-长度 图像前期处理:HSV阈值切割进行边 ...

  8. SURF原理及基于OPENCV实现

    写在前面: 六月,沉云湿雨.黄宁然--Time to say goodbye. 参考文献镇楼: [1]卜珂,基于SURF的图像配准与拼接技术研究 [2]曹君宇,基于SURF的图像拼接算法研究 [3]陈 ...

  9. 基于OpenCV的简单人脸识别系统

    目录 1. 调用库函数 2. 调用摄像头并设置窗口 3. 设置图片正负样本数据集的路径 4. 调用人脸检测器 5. 正负样本载入 6.提取人脸区域 7. 建立LBPH人脸识别模型 8. 实时检测 9. ...

最新文章

  1. 从小乡村走出的985高校博导坦言:读书这条路最简单!
  2. 谷歌迈出量子计算开源第一步,推出首个量子机器学习库TensorFlow Quantum
  3. mybatis的实际应用
  4. Linux的常用的命令
  5. 推荐给开发和设计人员的iPad应用
  6. HoloLens开发手记-全息Hologram
  7. 网络营销第四课:网络营销需要掌握的网页代码(2)
  8. JEECG 树列表操作总刷新列表,需要重新展开问题 【官方补丁,适用所有版本】
  9. java http服务_springboot官方例子中文翻译--RESTful服务启用CORS支持
  10. H264/H265/YUV码流分析工具推荐(一)
  11. SpringMVC学习(一)SpringMVC入门 、HelloSpringMVC程序、SpringMVC执行原理
  12. xps文件服务器端,黑苹果从入门到精通 篇七:XPS 9360完美黑果实战
  13. java重新温习基础笔记
  14. Windows Server 2012 R2 安装 Office2016 和 Visual Studio 2015的问题
  15. 微信二维码无法下载APK解决方案,用Mindjump实现自动跳转浏览器
  16. PG distinct与distinct on
  17. 蓝桥杯---二阶魔方旋转
  18. 微信CRM管理系统功能分析
  19. ctf-wp-mmmmpy
  20. 天花板建筑材料英国UKCA认证—EN 1364-2

热门文章

  1. 17届竞赛技术报告-越野组 | 山东大学(威海)-越野三队
  2. php网络电台源码,网络有声电台源码仿邻居的耳朵 v1.0.0
  3. The 400 Blows - 四百击
  4. 计算机开机免密码,电脑开机不用密码就可以自动打开,怎么回事?
  5. Windows下Qt拔插U盘的检测方法
  6. spool for oracle
  7. Java调用OpenCV来识别面部或眼睛
  8. 财务管理计算题(持续更新)
  9. 【android UI学习】LinearGradient实现歌词滚动
  10. 赛码习题:约德尔测试