精华内容
下载资源
问答
  • 双目相机测距代码演示

    千次阅读 2019-04-16 19:55:11
    双目测距的操作流程有四步:相机标定——双目校正——双目匹配——计算深度,具体内容参考 : https://blog.csdn.net/qq_38236355/article/details/88933839 其中相机标定通常用matlab现成的工具箱进行标定,具体...

    双目测距的操作流程有四步:相机标定——双目校正——双目匹配——计算深度,具体内容参考 : https://blog.csdn.net/qq_38236355/article/details/88933839

    其中相机标定通常用matlab现成的工具箱进行标定,具体操作参考: https://blog.csdn.net/qq_38236355/article/details/89280633

    我们接下来在完成相机标定的基础上,用标定得到的数据,按上述流程对双目深度进行计算。如果用的是任意的两个单目摄像头拼成的双目相机,则需要按上述所说进行双目校正;如果用的是成品的双目相机,则不需要进行双目校正,商家已经对相机校正好了。

    一、双目校正+BM算法双目匹配生成视差图+生成深度图

    #include <opencv2\opencv.hpp>
    #include <iostream>
    using namespace std;
    using namespace cv;
    
    const int imagewidth = 752;
    const int imageheigh = 480; // 摄像头分辨率752*480
    Size imageSize = Size(imagewidth, imageheigh);
    
    Mat grayImageL;
    Mat grayImageR;
    Mat rectifyImageL, rectifyImageR;
    Mat disp, disp8;//视差图
    
    Rect vaildROIL;
    Rect vaildROIR;//图像校正后,会对图像进行裁剪,这里的vaildROIR就是指裁剪之后的区域
    
    Mat maplx, maply, mapRx, mapRy;//映射表
    Mat Rl, Rr, Pl, Pr, Q; //校正旋转矩阵R,投影矩阵P,重投影矩阵Q
    Mat xyz;
    int blockSize = 0, uniquenessRatio = 0, numDisparities = 0;
    Ptr<StereoBM>bm = StereoBM::create(16, 9);
    
    //事先用matlab标定好的相机参数
    //matlab里的左相机标定参数矩阵
    Mat cameraMatrixL = (Mat_<float>(3, 3) << 165.9419, -0.2471, 372.8349, 0, 164.8281, 325.8182, 0, 0, 1);
    //matlab里左相机畸变参数
    Mat distCoeffL = (Mat_<double>(5, 1) << -0.0218, -0.0014, -0.0104, -0.0025, -0.000024286);
    //matlab右相机标定矩阵
    Mat cameraMatrixR = (Mat_<double>(3, 3) << 168.2781, 0.1610, 413.2010, 0, 167.7710, 304.7487, 0, 0, 1);
    //matlab右相机畸变参数
    Mat distCoffR = (Mat_<double>(5, 1) << -0.0332, 0.0033, -0.0090, -0.0029, -0.00038324);
    //matlab T 平移参数
    Mat T = (Mat_<double>(3, 1) << -117.2789, -0.8970, 0.9281);
    //旋转矩阵
    Mat R = (Mat_<double>(3, 3) << 1.0000, -0.0040, -0.000052, 0.0040, 1.0000, -0.0041, 0.0000683, 0.0041, 1.0000);
    //立体匹配 BM算法
    void stereo_match(int, void*)
    {
    	bm->setBlockSize(2 * blockSize + 5);//SAD窗口大小
    	bm->setROI1(vaildROIL);
    	bm->setROI2(vaildROIR);
    	bm->setPreFilterCap(31);
    	bm->setMinDisparity(0);//最小视差,默认值为0
    	bm->setNumDisparities(numDisparities * 16 + 16);//视差窗口,最大视差值与最小视差值之差
    	bm->setTextureThreshold(10);
    	bm->setUniquenessRatio(uniquenessRatio);//可以防止误匹配
    	bm->setSpeckleWindowSize(100);
    	bm->setSpeckleRange(32);
    	bm->setDisp12MaxDiff(-1);
    	bm->compute(rectifyImageL, rectifyImageR, disp);//生成视差图
    	disp.convertTo(disp8, CV_8U, 255 / ((numDisparities * 16 + 16) * 16.));//计算出的视差是CV_16S格式,将其转化为CV_8U的形式
    	reprojectImageTo3D(disp, xyz, Q, true);
    	xyz = xyz * 16;//在实际求距离时,ReprojectTo3D出来的X / W, Y / W, Z / W都要乘以16(也就是W除以16),才能得到正确的三维坐标信息。
    	imshow("disp image", disp8);
    }
    //生成深度图
    void disp2Depth(int, void*)
    {
    	Mat depthMap = Mat(disp.size(), CV_16UC1, 255);
    
    	int type = disp.type();
    	float fx = cameraMatrixL.at<float>(0, 0);
    	float fy = cameraMatrixL.at<float>(1, 1);
    	float cx = cameraMatrixL.at<float>(0, 2);
    	float cy = cameraMatrixL.at<float>(1, 2);
    
    	float baseline = 40; //基线距离40mm
    
    	if (type == CV_16S)
    	{
    		int height = disp.rows;
    		int width = disp.cols;
    		short* dispData = (short*)disp.data;
    		ushort* depthData = (ushort*)depthMap.data;
    		for (int i = 0; i < height; i++)
    		{
    			for (int j = 0; j < width; j++)
    			{
    				int id = i * width + j;
    				if (!dispData[id])
    				{
    					continue;
    				}
    				depthData[id] = ushort((float)fx*baseline / ((float)dispData[id]));
    			}
    		}
    	}
    	else
    	{
    		cout << "please onfirm dispImage's type" << endl;
    	}
    	Mat depthMap8;
    	depthMap.convertTo(depthMap8, CV_8U);//计算出的深度图是CV_16U格式
    	imshow("depth image", depthMap8);
    }
    int main()
    {
    	//双目校正
    	stereoRectify(cameraMatrixL, distCoeffL, cameraMatrixR, distCoffR, imageSize, R, T, Rl, Rr, Pl, Pr, Q, CALIB_ZERO_DISPARITY, -1, imageSize, &vaildROIL, &vaildROIR);
    	initUndistortRectifyMap(cameraMatrixL, distCoeffL, Rl, Pl , imageSize, CV_32FC1, maplx, maply);
    	initUndistortRectifyMap(cameraMatrixR, distCoffR, Rr, Pr, imageSize, CV_32FC1, mapRx, mapRy);
    	//读取图像
    	grayImageL = imread("D:/opencv learning/diannao_left.png", 0);
    	grayImageR = imread("D:/opencv learning/diannao_right.png", 0);
    	if (grayImageR.empty() || grayImageL.empty())
    	{
    		printf("can not load image...");
    		return -1;
    	}
    	imshow("imageL before rectify", grayImageL);
    	imshow("imageR bedore rectify", grayImageR);
    	//经过remap之后,左右相机的图像已经共面并且行对准了
    	remap(grayImageL, rectifyImageL, maplx, maply, INTER_LINEAR);
    	remap(grayImageR, rectifyImageR, mapRx, mapRy, INTER_LINEAR);
    	//把校正结果显示出来
    	imshow("imageL after rectify", rectifyImageL);
    	imshow("imageR after rectify", rectifyImageR);
    	//显示在同一张图上
    	Mat canvas;
    	double sf;
    	int w, h;
    	sf = 600. / MAX(imageSize.width, imageSize.height);
    	w = cvRound(imageSize.width*sf);
    	h = cvRound(imageSize.height*sf);
    	canvas.create(h, w * 2, CV_8UC1);
    	//左图像画到画布上
    	Mat canvaspart = canvas(Rect(w * 0, 0, w, h));
    	resize(rectifyImageL, canvaspart, canvaspart.size(), 0, 0, INTER_AREA);
    	Rect vroil(cvRound(vaildROIL.x*sf), cvRound(vaildROIL.y*sf), cvRound(vaildROIL.width*sf), cvRound(vaildROIL.height*sf));
    	cout << "Painted imagel" << endl;
    	//右图像画到画布上
    	canvaspart = canvas(Rect(w, 0, w, h));
    	resize(rectifyImageR, canvaspart, canvaspart.size(), 0, 0, INTER_LINEAR);
    	Rect vroiR(cvRound(vaildROIR.x*sf), cvRound(vaildROIR.y*sf), cvRound(vaildROIR.width*sf), cvRound(vaildROIR.height*sf));
    	cout << "Painted imageR" << endl;
    	//画上对应线条
    	for (int i = 0; i < canvas.rows; i += 16)
    	{
    		line(canvas, Point(0, i), Point(canvas.cols, i), Scalar(0, 255, 0), 1, 8);
    		imshow("rectified", canvas);
    	}
    	//立体匹配
    	namedWindow("disp image", CV_WINDOW_AUTOSIZE);
    	createTrackbar("blocksize:\n", "disp image", &blockSize, 8, stereo_match);
    	createTrackbar("UniquenessRatio:\n", "disp image", &uniquenessRatio, 50, stereo_match);
    	createTrackbar("NumDisparities:\n", "disp image", &numDisparities, 16, stereo_match);
    	stereo_match(0, 0);
    	disp2Depth(0, 0);
    	waitKey(0);
    	return 0;
    }
    

    二、成品双目无双目校正,BM算法双目匹配生成视差图+生成深度图

    #include <opencv2/opencv.hpp>
    #include <iostream>
    using namespace std;
    using namespace cv;
    
    const int imagewidth = 752;
    const int imageheigh = 480; // 摄像头分辨率752*480
    Size imageSize = Size(imagewidth, imageheigh);
    
    int blockSize = 0, uniquenessRatio = 0, numDisparities = 0;
    Ptr<StereoBM> bm = StereoBM::create(16, 9); //用Block Matching算法,实现双目匹配
    
    Mat grayImageL, grayImageR , disp, disp8;
    
    Rect vaildROIL = Rect(0, 0, 752, 480);
    Rect vaildROIR = Rect(0, 0, 752, 480);
    
    Mat cameraMatrixL = (Mat_<float>(3, 3) << 165.9419, -0.2471, 372.8349, 0, 164.8281, 325.8182, 0, 0, 1);
    
    void stereo_match(int, void*); //双目匹配,生成视差图(xl-xr)
    void disp2Depth(int, void*); //视差图转为深度图
    
    int main()
    {
    	grayImageL = imread("D:/opencv learning/liangdui_left.png", 0);
    	grayImageR = imread("D:/opencv learning/liangdui_right.png", 0);
    	if (grayImageL.empty() || grayImageR.empty())
    	{
    		printf("can not load image...");
    	}
    	imshow("input ImageL", grayImageL);
    	imshow("input ImageR", grayImageR);
    
    	//显示在同一张图上
    	Mat canvas;
    	double sf;
    	int w, h;
    	sf = 600. / MAX(imageSize.width, imageSize.height);
    	w = cvRound(imageSize.width*sf);
    	h = cvRound(imageSize.height*sf);
    	canvas.create(h, w * 2, CV_8UC1);
    	//左图像画到画布上
    	Mat canvaspart = canvas(Rect(w * 0, 0, w, h));
    	resize(grayImageL, canvaspart, canvaspart.size(), 0, 0, INTER_AREA);
    	Rect vroil(cvRound(vaildROIL.x*sf), cvRound(vaildROIL.y*sf), cvRound(vaildROIL.width*sf), cvRound(vaildROIL.height*sf));
    	cout << "Painted imagel" << endl;
    	//右图像画到画布上
    	canvaspart = canvas(Rect(w, 0, w, h));
    	resize(grayImageR, canvaspart, canvaspart.size(), 0, 0, INTER_LINEAR);
    	Rect vroiR(cvRound(vaildROIR.x*sf), cvRound(vaildROIR.y*sf), cvRound(vaildROIR.width*sf), cvRound(vaildROIR.height*sf));
    	cout << "Painted imageR" << endl;
    	//画上对应线条
    	for (int i = 0; i < canvas.rows; i += 16)
    	{
    		line(canvas, Point(0, i), Point(canvas.cols, i), Scalar(0, 255, 0), 1, 8);
    		imshow("rectified", canvas);
    	}
    
    	//立体匹配
    	namedWindow("disparity", CV_WINDOW_AUTOSIZE);
    	createTrackbar("BlockSize:\n", "disparity", &blockSize, 8, stereo_match);//创建SAD窗口Trackbar
    	createTrackbar("UniquenessRatio:\n", "disparity", &uniquenessRatio, 50, stereo_match);//创建视差唯一性百分比窗口 Trackbar
    	createTrackbar("NumDisparities:\n", "disparity", &numDisparities, 16, stereo_match);// 创建视差窗口 Trackbar
    	stereo_match(0, 0);
    	disp2Depth(0, 0);
    
    	waitKey(0);
    	return 0;
    }
    void stereo_match(int, void*)
    {
    	bm->setBlockSize(2 * blockSize + 5); //SAD窗口大小,5-21之间为宜
    	bm->setROI1(vaildROIL);
    	bm->setROI2(vaildROIR);
    	bm->setPreFilterCap(31);
    	bm->setMinDisparity(0); //最小视差
    	bm->setNumDisparities(numDisparities * 16 + 16);
    	bm->setTextureThreshold(10);
    	bm->setUniquenessRatio(uniquenessRatio); //uniquenessRatio主要可以防止误匹配
    	bm->setSpeckleRange(32);
    	bm->setSpeckleWindowSize(100);
    	bm->setDisp12MaxDiff(-1);
    	bm->compute(grayImageL, grayImageR, disp); //输入图像必须为灰度图,输出视差图
    	disp.convertTo(disp8, CV_8U, 255 / ((numDisparities * 16 + 16)*16.));//计算出的视差是CV_16S格式
    	imshow("disparity", disp8);
    }
    void disp2Depth(int, void*)
    {
    	Mat depthMap = Mat(disp.size(), CV_16UC1, 255);
    
    	int type = disp.type();
    	float fx = cameraMatrixL.at<float>(0, 0);
    	float fy = cameraMatrixL.at<float>(1, 1);
    	float cx = cameraMatrixL.at<float>(0, 2);
    	float cy = cameraMatrixL.at<float>(1, 2);
    
    	float baseline = 40; //基线距离40mm
    
    	if (type == CV_16S)
    	{
    		int height = disp.rows;
    		int width = disp.cols;
    		short* dispData = (short*)disp.data;
    		ushort* depthData = (ushort*)depthMap.data;
    		for (int i = 0; i < height; i++)
    		{
    			for (int j = 0; j < width; j++)
    			{
    				int id = i * width + j;
    				if (!dispData[id])
    				{
    					continue;
    				}
    				depthData[id] = ushort((float)fx*baseline / ((float)dispData[id]));
    			}
    		}
    	}
    	else
    	{
    		cout << "please onfirm dispImage's type" << endl;
    	}
    	Mat depthMap8;
    	depthMap.convertTo(depthMap8, CV_8U);//计算出的深度图是CV_16U格式
    	imshow("depth image", depthMap8);
    }
    

    我拍了一幅电脑的图片,效果如下图所示:

    左右原图:
    在这里插入图片描述
    校正后放到同一平面:
    在这里插入图片描述
    视差图:
    在这里插入图片描述
    深度图:
    在这里插入图片描述

    展开全文
  • OpenCV双目相机测距程序

    千次阅读 2018-06-08 14:45:13
    本文主要分享一个双目测距的实现程序,用的bumblebee2相机。使用的OpenCV自带的BM算法。 在OpenCV3中,StereoBM算法发生了比较大的变化,StereoBM被定义为纯虚类,因此不能直接实例化,只能用智能指针的形式实例化...

       本文主要分享一个双目测距的实现程序,用的bumblebee2相机。使用的OpenCV自带的BM算法。 在OpenCV3中,StereoBM算法发生了比较大的变化,StereoBM被定义为纯虚类,因此不能直接实例化,只能用智能指针的形式实例化,也不用StereoBMState类来设置了,而是改成用bm->set...的形式。(转载请注明出处)

    详细参数代码请查看链接http://www.cnblogs.com/polly333/p/5130375.html

    另外,双目标定,立体匹配和测距的原理网上的已经很全啦,就不多啰嗦啦。使用的matlab自带的标定工具箱进行的标定。下面就上代码吧,废话少说敲打。。。。

    #include <opencv2/opencv.hpp>  
    #include <iostream>  
    
    using namespace std;
    using namespace cv;
    
    const int imageWidth = 1024;                             //摄像头的分辨率  
    const int imageHeight = 768;
    Size imageSize = Size(imageWidth, imageHeight);
    
    Mat rgbImageL, grayImageL;
    Mat rgbImageR, grayImageR;
    Mat rectifyImageL, rectifyImageR;
    
    Rect validROIL;//图像校正之后,会对图像进行裁剪,这里的validROI就是指裁剪之后的区域  
    Rect validROIR;
    
    Mat mapLx, mapLy, mapRx, mapRy;     //映射表  
    Mat Rl, Rr, Pl, Pr, Q;              //校正旋转矩阵R,投影矩阵P 重投影矩阵Q
    Mat xyz;              //三维坐标
    
    Point origin;         //鼠标按下的起始点
    Rect selection;      //定义矩形选框
    bool selectObject = false;    //是否选择对象
    
    int blockSize = 0, uniquenessRatio = 0, numDisparities = 0;
    Ptr<StereoBM> bm = StereoBM::create(16, 9);
    
    /*
    事先标定好的相机的参数
    fx 0 cx
    0 fy cy
    0 0  1
    */
    Mat cameraMatrixL = (Mat_<double>(3, 3) << 1324.4092, 0, 521.2833,
    	0, 1328.0859, 392.6668,
    	0, 0, 1);
    //对应matlab里的左相机标定矩阵
    Mat distCoeffL = (Mat_<double>(1, 5) << -0.58627, 0.16595, 0, 0.00000, 0.00000);
    //对应Matlab所得左i相机畸变参数
    
    Mat cameraMatrixR = (Mat_<double>(3, 3) << 1323.9, 0, 523.453,
    	0, 1326.88, 397.6582,
    	0, 0, 1);
    //对应matlab里的右相机标定矩阵
    
    Mat distCoeffR = (Mat_<double>(1, 5) << -0.63278, 0.47043, 0.00000, 0.00000, 0.00000);
    //对应Matlab所得右相机畸变参数
    
    Mat T = (Mat_<double>(3, 1) << -120.9319, 0.3701, 0.1176);//T平移向量
    														  //对应Matlab所得T参数
    Mat rec = (Mat_<double>(3, 1) << 0.0022, 0.0113, -0.0001);//rec旋转向量,对应matlab om参数
    Mat R;//R 旋转矩阵
    	  /*****伪彩色函数*****/
    void F_Gray2Color(CvMat* gray_mat, CvMat* color_mat)
    {
    	if (color_mat)
    		cvZero(color_mat);
    
    	int stype = CV_MAT_TYPE(gray_mat->type), dtype = CV_MAT_TYPE(color_mat->type);
    	int rows = gray_mat->rows, cols = gray_mat->cols;
    
    	// 判断输入的灰度图和输出的伪彩色图是否大小相同、格式是否符合要求
    	if (CV_ARE_SIZES_EQ(gray_mat, color_mat) && stype == CV_8UC1 && dtype == CV_8UC3)
    	{
    		CvMat* red = cvCreateMat(rows, cols, CV_8U);      // 红色分量
    		CvMat* green = cvCreateMat(rows, cols, CV_8U);   // 绿色分量
    		CvMat* blue = cvCreateMat(rows, cols, CV_8U);    // 蓝色分量
    		CvMat* mask = cvCreateMat(rows, cols, CV_8U);
    
    		// 计算各彩色通道的像素值
    		cvSubRS(gray_mat, cvScalar(255), blue); // blue(I) = 255 - gray(I)
    		cvCopy(gray_mat, red);          // red(I) = gray(I)
    		cvCopy(gray_mat, green);            // green(I) = gray(I),if gray(I) < 128
    		cvCmpS(green, 128, mask, CV_CMP_GE);   // green(I) = 255 - gray(I), if gray(I) >= 128
    		cvSubRS(green, cvScalar(255), green, mask);
    		cvConvertScale(green, green, 2.0, 0.0);
    
    		// 合成伪彩色图
    		cvMerge(blue, green, red, NULL, color_mat);
    
    		cvReleaseMat(&red);
    		cvReleaseMat(&green);
    		cvReleaseMat(&blue);
    		cvReleaseMat(&mask);
    	}
    	else cout << "大小格式不符合要求" << endl;
    }
    
    
    	  /*****立体匹配*****/
    void stereo_match(int, void*)
    {
    	bm->setBlockSize(2 * blockSize + 5);     //SAD窗口大小,5~21之间为宜
    	bm->setROI1(validROIL);
    	bm->setROI2(validROIR);
    	bm->setPreFilterCap(31);
    	bm->setMinDisparity(0);  //最小视差,默认值为0, 可以是负值,int型
    	bm->setNumDisparities(numDisparities * 16 + 16);//视差窗口,即最大视差值与最小视差值之差,窗口大小必须是16的整数倍,int型
    	bm->setTextureThreshold(10);
    	bm->setUniquenessRatio(uniquenessRatio);//uniquenessRatio主要可以防止误匹配
    	bm->setSpeckleWindowSize(100);
    	bm->setSpeckleRange(32);
    	bm->setDisp12MaxDiff(-1);
    	Mat disp, disp8;
    	bm->compute(rectifyImageL, rectifyImageR, disp);//输入图像必须为灰度图
    	disp.convertTo(disp8, CV_8U, 255 / ((numDisparities * 16 + 16)*16.));//计算出的视差是CV_16S格式
    	reprojectImageTo3D(disp, xyz, Q, true); //在实际求距离时,ReprojectTo3D出来的X / W, Y / W, Z / W都要乘以16(也就是W除以16),才能得到正确的三维坐标信息。
    	xyz = xyz * 16;
    	imshow("disparity", disp8);
    	/*Mat im=imread("left11.png",0);
    	imshow("im", im);*/
    	CvMat disp8cv = disp8;
    	int m = disp8.rows;
    	int n = disp8.cols;
    	CvMat* vdispRGB= cvCreateMat(m, n, CV_8UC3);
    	
    	
    	//disp.convertTo(disp8, CV_8U, 255 / (numDisparities *16.));
    	F_Gray2Color(&disp8cv, vdispRGB);
    	//CvMat* b = &disp8cv;
    	CvMat* b = vdispRGB;
    	Mat gray2= cvarrToMat(b);
    	
    	imshow("伪彩色深度图", gray2);
    }
    
    /*****描述:鼠标操作回调*****/
    static void onMouse(int event, int x, int y, int, void*)
    {
    	if (selectObject)
    	{
    		selection.x = MIN(x, origin.x);
    		selection.y = MIN(y, origin.y);
    		selection.width = std::abs(x - origin.x);
    		selection.height = std::abs(y - origin.y);
    	}
    
    	switch (event)
    	{
    	case EVENT_LBUTTONDOWN:   //鼠标左按钮按下的事件
    		origin = Point(x, y);
    		selection = Rect(x, y, 0, 0);
    		selectObject = true;
    		cout << origin << "in world coordinate is: " << xyz.at<Vec3f>(origin) << endl;
    		break;
    	case EVENT_LBUTTONUP:    //鼠标左按钮释放的事件
    		selectObject = false;
    		if (selection.width > 0 && selection.height > 0)
    			break;
    	}
    }
    
    
    /*****主函数*****/
    int main()
    {
    	/*
    	立体校正
    	*/
    	Rodrigues(rec, R); //Rodrigues变换
    	stereoRectify(cameraMatrixL, distCoeffL, cameraMatrixR, distCoeffR, imageSize, R, T, Rl, Rr, Pl, Pr, Q, CALIB_ZERO_DISPARITY,
    		0, imageSize, &validROIL, &validROIR);
    	initUndistortRectifyMap(cameraMatrixL, distCoeffL, Rl, Pr, imageSize, CV_32FC1, mapLx, mapLy);
    	initUndistortRectifyMap(cameraMatrixR, distCoeffR, Rr, Pr, imageSize, CV_32FC1, mapRx, mapRy);
    
    	/*
    	读取图片
    	*/
    	rgbImageL = imread("left11.png", CV_LOAD_IMAGE_COLOR);
    	cvtColor(rgbImageL, grayImageL, CV_BGR2GRAY);
    	rgbImageR = imread("right11.png", CV_LOAD_IMAGE_COLOR);	
    	cvtColor(rgbImageR, grayImageR, CV_BGR2GRAY);
    
    	imshow("ImageL Before Rectify", grayImageL);
    	imshow("ImageR Before Rectify", grayImageR);
    
    	/*
    	经过remap之后,左右相机的图像已经共面并且行对准了
    	*/
    	remap(grayImageL, rectifyImageL, mapLx, mapLy, INTER_LINEAR);
    	remap(grayImageR, rectifyImageR, mapRx, mapRy, INTER_LINEAR);
    
    	/*
    	把校正结果显示出来
    	*/
    	Mat rgbRectifyImageL, rgbRectifyImageR;
    	cvtColor(rectifyImageL, rgbRectifyImageL, CV_GRAY2BGR);  //伪彩色图
    	cvtColor(rectifyImageR, rgbRectifyImageR, CV_GRAY2BGR);
    
    	//单独显示
    	//rectangle(rgbRectifyImageL, validROIL, Scalar(0, 0, 255), 3, 8);
    	//rectangle(rgbRectifyImageR, validROIR, Scalar(0, 0, 255), 3, 8);
    	namedWindow("ImageL After Rectify", WINDOW_NORMAL);
    	imshow("ImageL After Rectify", rgbRectifyImageL);
    	imshow("ImageR After Rectify", rgbRectifyImageR);
    
    	//显示在同一张图上
    	Mat canvas;
    	double sf;
    	int w, h;
    	sf = 600. / MAX(imageSize.width, imageSize.height);
    	w = cvRound(imageSize.width * sf);
    	h = cvRound(imageSize.height * sf);
    	canvas.create(h, w * 2, CV_8UC3);   //注意通道
    
    										//左图像画到画布上
    	Mat canvasPart = canvas(Rect(w * 0, 0, w, h));                                //得到画布的一部分  
    	resize(rgbRectifyImageL, canvasPart, canvasPart.size(), 0, 0, INTER_AREA);     //把图像缩放到跟canvasPart一样大小  
    	Rect vroiL(cvRound(validROIL.x*sf), cvRound(validROIL.y*sf),                //获得被截取的区域    
    		cvRound(validROIL.width*sf), cvRound(validROIL.height*sf));
    	//rectangle(canvasPart, vroiL, Scalar(0, 0, 255), 3, 8);                      //画上一个矩形  
    	cout << "Painted ImageL" << endl;
    
    	//右图像画到画布上
    	canvasPart = canvas(Rect(w, 0, w, h));                                      //获得画布的另一部分  
    	resize(rgbRectifyImageR, canvasPart, canvasPart.size(), 0, 0, INTER_LINEAR);
    	Rect vroiR(cvRound(validROIR.x * sf), cvRound(validROIR.y*sf),
    		cvRound(validROIR.width * sf), cvRound(validROIR.height * sf));
    	//rectangle(canvasPart, vroiR, Scalar(0, 0, 255), 3, 8);
    	cout << "Painted ImageR" << endl;
    
    	//画上对应的线条
    	for (int i = 0; i < canvas.rows; i += 16)
    		line(canvas, Point(0, i), Point(canvas.cols, i), Scalar(0, 255, 0), 1, 8);
    	imshow("rectified", canvas);
    
    	/*
    	立体匹配
    	*/
    	namedWindow("disparity", CV_WINDOW_AUTOSIZE);
    	// 创建SAD窗口 Trackbar
    	createTrackbar("BlockSize:\n", "disparity", &blockSize, 8, stereo_match);
    	// 创建视差唯一性百分比窗口 Trackbar
    	createTrackbar("UniquenessRatio:\n", "disparity", &uniquenessRatio, 50, stereo_match);
    	// 创建视差窗口 Trackbar
    	createTrackbar("NumDisparities:\n", "disparity", &numDisparities, 16, stereo_match);
    	//鼠标响应函数setMouseCallback(窗口名称, 鼠标回调函数, 传给回调函数的参数,一般取0)
    	setMouseCallback("disparity", onMouse, 0);
    	namedWindow("伪彩色深度图", CV_WINDOW_AUTOSIZE);
    	// 创建SAD窗口 Trackbar
    	createTrackbar("BlockSize:\n", "伪彩色深度图", &blockSize, 8, stereo_match);
    	// 创建视差唯一性百分比窗口 Trackbar
    	createTrackbar("UniquenessRatio:\n", "伪彩色深度图", &uniquenessRatio, 50, stereo_match);
    	// 创建视差窗口 Trackbar
    	createTrackbar("NumDisparities:\n", "伪彩色深度图", &numDisparities, 16, stereo_match);
    	//鼠标响应函数setMouseCallback(窗口名称, 鼠标回调函数, 传给回调函数的参数,一般取0)
    	setMouseCallback("伪彩色深度图", onMouse, 0);
    	stereo_match(0, 0);
    
    	waitKey(0);
    	return 0;
    }

    本人菜鸟一只,代码也是参考的一篇博客上的,http://blog.csdn.net/u013316124/article/details/53856797 。。。。代码有简单的修改,增加了伪彩色深度图显示。直接使用的话需要改动图片大小,标定数据和读图地址,另外算法的参数也得微调,不然出来的图会乱七八糟。。。

    下面放一些效果图。。。。(深度图的效果一般,bm算法速度快,效果确实差些,参数调的也有点着急)




    本文结束。还望多多指教。。。。。(不喜勿喷)

    展开全文
  • 双目相机测距原理图和生成深度图

    千次阅读 2020-05-27 18:01:10
    根据上面的原理图可知,Z(深度)只和三个参数有关,即:B(两个相机中心间距), f(相机的焦距) , d(左右对应点的视差) B和f对于固定相机来说是个定制,因此得到视差图后就知道每个点的d值,继而得出每个点的Z深度值...

    之前看了很多的示意图,但是感觉讲解和推导都不清楚,所以自己画了一个原理图,看不懂的话可以留言

      

    根据上面的原理图可知,Z(深度)只和三个参数有关,即:B(两个相机中心间距), f(相机的焦距) , d(左右对应点的视差)

    B和f对于固定相机来说是个定制,因此得到视差图后就知道每个点的d值,继而得出每个点的Z深度值。

    下面用到BM和SGBM两种立体匹配方法生成深度图,根据深度图测距。

    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/core/core.hpp>
    #include <opencv2/opencv.hpp>
    
    
    using namespace cv;
    using namespace std;
    
    int blockSize = 0, uniquenessRatio = 0, numDisparities = 0;
    Ptr<StereoBM> bm = StereoBM::create(16, 9);
    Mat xyz;              //三维坐标
    
    Mat Q;//深度视差映射矩阵
    Rect left_valid_roi, right_valid_roi;//图像校正之后,会对图像进行裁剪,这里的validRoi就是指裁剪之后的区域
    Mat left_rectified_gray, right_rectified_gray;//左右摄像头校准后图像
    Mat img;
    Mat left_img, right_img;//左右摄像头原始图像
    Mat left_rectified_img, right_rectified_img;//左右摄像头校准后图像
    
    Vec3f  point3;
    float d;
    Point origin;         //鼠标按下的起始点
    Rect selection;      //定义矩形选框
    bool selectObject = false;    //是否选择对象
    int mindisparity = 0;
    int ndisparities = 64;
    int SADWindowSize = 5;
    
    void stereo_BM_match(int, void*)
    {
        bm->setBlockSize(2 * blockSize + 5);     //SAD窗口大小,5~21之间为宜
        bm->setROI1(left_valid_roi);
        bm->setROI2(right_valid_roi);
        bm->setPreFilterCap(31);
        bm->setMinDisparity(0);  //最小视差,默认值为0, 可以是负值,int型
        bm->setNumDisparities(numDisparities * 16 + 16);//视差窗口,即最大视差值与最小视差值之差,窗口大小必须是16的整数倍,int型
        bm->setTextureThreshold(10);
        bm->setUniquenessRatio(uniquenessRatio);//uniquenessRatio主要可以防止误匹配
        bm->setSpeckleWindowSize(100);
        bm->setSpeckleRange(32);
        bm->setDisp12MaxDiff(-1);
        Mat disp, disp8;
        bm->compute(left_rectified_gray, right_rectified_gray, disp);//输入图像必须为灰度图
        disp.convertTo(disp8, CV_8UC1, 255 / ((numDisparities * 16 + 16) * 16.));//计算出的视差是CV_16S格式
        reprojectImageTo3D(disp, xyz, Q, true); //在实际求距离时,ReprojectTo3D出来的X / W, Y / W, Z / W都要乘以16(也就是W除以16),才能得到正确的三维坐标信息。
        xyz = xyz * 16;
        imshow("disparity_BM", disp8);
    }
    
    
    void stereo_SGBM_match(int, void*)
    {
        Mat disp;
    
        //SGBM
        cv::Ptr<cv::StereoSGBM> sgbm = cv::StereoSGBM::create(mindisparity, ndisparities, SADWindowSize);
        int P1 = 8 * left_rectified_img.channels() * SADWindowSize * SADWindowSize;
        int P2 = 10 * left_rectified_img.channels() * SADWindowSize * SADWindowSize;
        sgbm->setP1(P1);
        sgbm->setP2(P2);
        sgbm->setPreFilterCap(15);
        sgbm->setUniquenessRatio(10);
        sgbm->setSpeckleRange(2);
        sgbm->setSpeckleWindowSize(100);
        sgbm->setDisp12MaxDiff(1);
        //sgbm->setMode(cv::StereoSGBM::MODE_HH);
        sgbm->compute(left_rectified_img, right_rectified_img, disp);
        disp.convertTo(disp, CV_32F, 1.0 / 16);                //除以16得到真实视差值
        Mat disp8U = Mat(disp.rows, disp.cols, CV_8UC1);       //显示
        normalize(disp, disp8U, 0, 255, NORM_MINMAX, CV_8UC1);
        reprojectImageTo3D(disp8U, xyz, Q, true); //在实际求距离时,ReprojectTo3D出来的X / W, Y / W, Z / W都要乘以16(也就是W除以16),才能得到正确的三维坐标信息。
        xyz = xyz * 16;
        namedWindow("disparity_SGBM", WINDOW_AUTOSIZE);
        imshow("disparity_SGBM", disp8U);
    
    }
    
    /*void stereo_GC_match(int, void*)
    {
        CvStereoGCState* state = cvCreateStereoGCState(16, 2);
        left_disp_ = cvCreateMat(left->height, left->width, CV_32F);
        right_disp_ = cvCreateMat(right->height, right->width, CV_32F);
        cvFindStereoCorrespondenceGC(left, right, left_disp_, right_disp_, state, 0);
        cvReleaseStereoGCState(&state);
        CvMat* disparity_left_visual = cvCreateMat(size.height, size.width, CV_8U); 
        cvConvertScale(disparity_left, disparity_left_visual, -16);
    }
    */
    
    /*****描述:鼠标操作回调*****/
    static void onMouse(int event, int x, int y, int, void*)
    {
    	if (selectObject)
    	{
    		selection.x = MIN(x, origin.x);
    		selection.y = MIN(y, origin.y);
    		selection.width = std::abs(x - origin.x);
    		selection.height = std::abs(y - origin.y);
    	}
    
    	switch (event)
    	{
    	case EVENT_LBUTTONDOWN:   //鼠标左按钮按下的事件
    		origin = Point(x, y);
    		selection = Rect(x, y, 0, 0);
    		selectObject = true;
    		//cout << origin << "in world coordinate is: " << xyz.at<Vec3f>(origin) << endl;
    		point3 = xyz.at<Vec3f>(origin);
    		point3[0];
    		//cout << "point3[0]:" << point3[0] << "point3[1]:" << point3[1] << "point3[2]:" << point3[2]<<endl;
    		cout << "世界坐标:" << endl;
    		cout << "x: " << point3[0] << "  y: " << point3[1] << "  z: " << point3[2] << endl;
    		d = point3[0] * point3[0] + point3[1] * point3[1] + point3[2] * point3[2];
    		d = sqrt(d);   //mm
    	   // cout << "距离是:" << d << "mm" << endl;
    
    		d = d / 10.0;   //cm
    		cout << "距离是:" << d << "cm" << endl;
    
    		// d = d/1000.0;   //m
    		// cout << "距离是:" << d << "m" << endl;
    
    		break;
    	case EVENT_LBUTTONUP:    //鼠标左按钮释放的事件
    		selectObject = false;
    		if (selection.width > 0 && selection.height > 0)
    			break;
    	}
    }
    
    int main()
    {
        VideoCapture cap(1);
        int FRAME_WIDTH = cap.get(CAP_PROP_FRAME_WIDTH);
        int FRAME_HEIGHT = cap.get(CAP_PROP_FRAME_HEIGHT);
        Mat aligned_rectified_img(FRAME_HEIGHT, FRAME_WIDTH, CV_8UC3);//校准+对齐后的图像
        cout << "Resolution:<" << cap.get(CAP_PROP_FRAME_WIDTH) << "," << cap.get(CAP_PROP_FRAME_HEIGHT) << ">\n";
        namedWindow("camera", WINDOW_AUTOSIZE);
        //    namedWindow("left_img",CV_WINDOW_NORMAL);
        //    namedWindow("right_img",CV_WINDOW_NORMAL);
        //    namedWindow("left_rectified_img",CV_WINDOW_NORMAL);
        //    namedWindow("right_rectified_img",CV_WINDOW_NORMAL);
        //    namedWindow("rectified_img",CV_WINDOW_NORMAL);
        namedWindow("aligned_rectified_img", WINDOW_AUTOSIZE);
        //resizeWindow("camera", 1200, 600);
       // resizeWindow("aligned_rectified_img", 1200, 600);
    
        Mat left_cameraMatrix = Mat::eye(3, 3, CV_64F);//左相机内参矩阵
        left_cameraMatrix.at<double>(0, 0) = 2.762165790037839e+02;//Fx
        left_cameraMatrix.at<double>(0, 1) = 0;
        left_cameraMatrix.at<double>(0, 2) = 1.765880468329375e+02;//Cx
        left_cameraMatrix.at<double>(1, 1) = 2.762317738515432e+02;//Fy
        left_cameraMatrix.at<double>(1, 2) = 1.272320444598781e+02;//Cy
    
        Mat left_distCoeffs = Mat::zeros(5, 1, CV_64F);//畸变系数
        left_distCoeffs.at<double>(0, 0) = 0.065542106666972;//k1
        left_distCoeffs.at<double>(1, 0) = -0.099179821896270;//k2
        left_distCoeffs.at<double>(2, 0) = 0;//p1
        left_distCoeffs.at<double>(3, 0) = 0;//p2
        left_distCoeffs.at<double>(4, 0) = 0;
    
        Mat right_cameraMatrix = Mat::eye(3, 3, CV_64F);//右相机内参矩阵
        right_cameraMatrix.at<double>(0, 0) = 2.734695143541476e+02;//Fx
        right_cameraMatrix.at<double>(0, 1) = 0;
        right_cameraMatrix.at<double>(0, 2) = 1.724017536155269e+02;//Cx
        right_cameraMatrix.at<double>(1, 1) = 2.733548075965133e+02;//Fy
        right_cameraMatrix.at<double>(1, 2) = 1.255695004672240e+02;//Cy
    
        Mat right_distCoeffs = Mat::zeros(5, 1, CV_64F);//畸变系数
        right_distCoeffs.at<double>(0, 0) = 0.067619149443979;//k1
        right_distCoeffs.at<double>(1, 0) = -0.104286472771764;//k2
        right_distCoeffs.at<double>(2, 0) = 0;//p1
        right_distCoeffs.at<double>(3, 0) = 0;//p2
        right_distCoeffs.at<double>(4, 0) = 0;
    
    
        Mat rotation_matrix = Mat::zeros(3, 3, CV_64F);//旋转矩阵
        rotation_matrix.at<double>(0, 0) = 0.999997933684708;
        rotation_matrix.at<double>(0, 1) = 5.541735042905797e-04;
        rotation_matrix.at<double>(0, 2) = -0.001955893157243;
        rotation_matrix.at<double>(1, 0) = -5.560064711997943e-04;
        rotation_matrix.at<double>(1, 1) = 0.999999406695233;
        rotation_matrix.at<double>(1, 2) = -9.367315446314680e-04;
        rotation_matrix.at<double>(2, 0) = 0.001955372884999;
        rotation_matrix.at<double>(2, 1) = 9.378170983011573e-04;
        rotation_matrix.at<double>(2, 2) = 0.999997648505221;
    
        Mat rotation_vector;//旋转矩阵
        Rodrigues(rotation_matrix, rotation_vector);//旋转矩阵转化为旋转向量,罗德里格斯变换
    
        Mat translation_vector = Mat::zeros(3, 1, CV_64F);//平移向量
        translation_vector.at<double>(0, 0) = -74.303646210221200;
        translation_vector.at<double>(1, 0) = -0.208289299602746;
        translation_vector.at<double>(2, 0) = -1.203122420388863;
    
        Mat R1, R2;//左右相机的3x3矫正变换(旋转矩阵)
        Mat P1, P2;//左右相机新的坐标系统(矫正过的)输出 3x4 的投影矩阵
       // Mat Q;//深度视差映射矩阵
    
       // Rect left_valid_roi, right_valid_roi;//图像校正之后,会对图像进行裁剪,这里的validRoi就是指裁剪之后的区域
        Mat rmap[2][2];//映射表 必须为:CV_16SC2/CV_32FC1/CV_32FC2
        Size imageSize;
        imageSize = Size(FRAME_WIDTH >> 1, FRAME_HEIGHT);
    
        /*
            立体校正的时候需要两幅图像共面并且行对准 以使得立体匹配更加的可靠
            使得两幅图像共面的方法就是把两个摄像头的图像投影到一个公共成像面上,这样每幅图像从本图像平面投影到公共图像平面都需要一个旋转矩阵R
            stereoRectify 这个函数计算的就是从图像平面投影都公共成像平面的旋转矩阵R1,R2。 R1,R2即为左右相机平面行对准的校正旋转矩阵。
            左相机经过R1旋转,右相机经过R2旋转之后,两幅图像就已经共面并且行对准了。
            其中P1,P2为两个相机的投影矩阵,其作用是将3D点的坐标转换到图像的2D点的坐标:P*[X Y Z 1]' =[x y w]
            Q矩阵为重投影矩阵,即矩阵Q可以把2维平面(图像平面)上的点投影到3维空间的点:Q*[x y d 1] = [X Y Z W]。其中d为左右两幅图像的视差
        */
        //双目校准
        stereoRectify(left_cameraMatrix, left_distCoeffs,//左摄像头内参和畸变系数
            right_cameraMatrix, right_distCoeffs,//右摄像头内参和畸变系数
            imageSize, rotation_vector, translation_vector,//图像大小,右摄像头相对于左摄像头旋转矩阵,平移向量
            R1, R2, P1, P2, Q,//输出的参数
            CALIB_ZERO_DISPARITY, -1, imageSize, &left_valid_roi, &right_valid_roi);
        //Precompute maps for cv::remap().
        //用来计算畸变映射,输出的X / Y坐标重映射参数,remap把求得的映射应用到图像上。
        initUndistortRectifyMap(left_cameraMatrix, left_distCoeffs, R1, P1, imageSize, CV_16SC2, rmap[0][0], rmap[0][1]);
        initUndistortRectifyMap(right_cameraMatrix, right_distCoeffs, R2, P2, imageSize, CV_16SC2, rmap[1][0], rmap[1][1]);
    
        while (1)
        {
    
            cap >> img;
    
            left_img = img(Rect(0, 0, FRAME_WIDTH >> 1, FRAME_HEIGHT));
            right_img = img(Rect(FRAME_WIDTH >> 1, 0, FRAME_WIDTH >> 1, FRAME_HEIGHT));
    
            //经过remap之后,左右相机的图像已经共面并且行对准了
            remap(left_img, left_rectified_img, rmap[0][0], rmap[0][1], INTER_LINEAR);
            remap(right_img, right_rectified_img, rmap[1][0], rmap[1][1], INTER_LINEAR);
    
            //立体匹配生成深度图需要用到灰度图
            cvtColor(left_rectified_img, left_rectified_gray, COLOR_BGR2GRAY);
            cvtColor(right_rectified_img, right_rectified_gray, COLOR_BGR2GRAY);
    
            //复制左相机校准图像到总图像上
            for (int i = 0; i < left_rectified_img.rows; i++)
            {
                for (int j = 0; j < left_rectified_img.cols; j++)
                {
                    aligned_rectified_img.at<Vec3b>(i, j)[0] = left_rectified_img.at<Vec3b>(i, j)[0];
                    aligned_rectified_img.at<Vec3b>(i, j)[1] = left_rectified_img.at<Vec3b>(i, j)[1];
                    aligned_rectified_img.at<Vec3b>(i, j)[2] = left_rectified_img.at<Vec3b>(i, j)[2];
                }
            }
            //复制右相机校准图像到总图像上
            for (int i = 0; i < right_rectified_img.rows; i++)
            {
                for (int j = 0; j < right_rectified_img.cols; j++)
                {
                    aligned_rectified_img.at<Vec3b>(i, j + (FRAME_WIDTH >> 1))[0] = right_rectified_img.at<Vec3b>(i, j)[0];
                    aligned_rectified_img.at<Vec3b>(i, j + (FRAME_WIDTH >> 1))[1] = right_rectified_img.at<Vec3b>(i, j)[1];
                    aligned_rectified_img.at<Vec3b>(i, j + (FRAME_WIDTH >> 1))[2] = right_rectified_img.at<Vec3b>(i, j)[2];
                }
            }
    
            //红色框出校正后的左右图像
            rectangle(img, left_valid_roi, Scalar(0, 0, 255), 2, 8);
            rectangle(img, Rect(right_valid_roi.x + (FRAME_WIDTH >> 1), right_valid_roi.y, right_valid_roi.width, right_valid_roi.height), Scalar(0, 0, 255), 2, 8);
    
            //做绿色线增强对比
            for (int i = 0; i < aligned_rectified_img.rows; i += 32)
            {
                line(aligned_rectified_img, Point(0, i), Point(aligned_rectified_img.cols, i), Scalar(0, 255, 0), 1, LINE_8);
            }
    
    
            imshow("camera", img);
            imshow("left_img",left_img);
            imshow("right_img",right_img);
            imshow("left_rectified_img",left_rectified_img);
            imshow("right_rectified_img",right_rectified_img);
            imshow("aligned_rectified_img", aligned_rectified_img);
    
            stereo_BM_match(0, 0);
            stereo_SGBM_match(0, 0);
            
             //创建SAD窗口 Trackbar
    		createTrackbar("BlockSize:\n", "disparity_BM", &blockSize, 8, stereo_BM_match);
    		// 创建视差唯一性百分比窗口 Trackbar
    		createTrackbar("UniquenessRatio:\n", "disparity_BM", &uniquenessRatio, 50, stereo_BM_match);
    		// 创建视差窗口 Trackbar
    		createTrackbar("NumDisparities:\n", "disparity_BM", &numDisparities, 16, stereo_BM_match);
    
            createTrackbar("SADWindowSize:\n", "disparity_SGBM", &SADWindowSize, 30, stereo_SGBM_match);
            setMouseCallback("disparity_SGBM", onMouse, 0);
            setMouseCallback("disparity_BM", onMouse, 0);
            int key = waitKey(30);
            if (key == 27)//按下Esc退出
    
                return 0;
        }
    }
    
    

     

    展开全文
  • 谈到双目相机测距,我们首先要先了解测距的原理:如下图所示,这是双目摄像头的俯视图。 上图解释了双摄像头测距的原理,书中Z的公式如下:b代表基线,根据相似三角形关系, 这里d表示为左右图横坐标之差,称为视差...

    谈到双目相机测距,我们首先要先了解测距的原理:如下图所示,这是双目摄像头的俯视图。
    在这里插入图片描述
    上图解释了双摄像头测距的原理,书中Z的公式如下:b代表基线,根据相似三角形关系,在这里插入图片描述
    这里d表示为左右图横坐标之差,称为视差,视差的单位是像素点。但是通过标定得出的UR是负的,

    在OpenCV中,焦距f的量纲是像素点,基线b的量纲由定标棋盘格的实际尺寸和用户输入值确定,一般总是设成毫米,当然为了精度提高也可以设置为0.1毫米量级,视差d=xl-xr(ul-ur)的量纲也是像素点。因此分子分母约去,z的量纲与d相同。
    在这里插入图片描述
    图2解释了双摄像头获取空间中某点三维坐标的原理。
    可以看到,实际的坐标计算利用的都是相似三角形的原理
    因此,为了精确地求得某个点在三维空间里的距离,我们需要获得的参数有焦距f、视差d、摄像头中心距Tx。
    如果还需要获得X坐标和Y坐标的话,那么还需要额外知道左右像平面的坐标系与立体坐标系中原点的偏移cx和cy。其中f, Tx, cx和cy可以通过立体标定获得初始值,并通过立体校准优化,使得两个摄像头在数学上完全平行放置,并且左右摄像头的cx, cy和f相同(也就是实现图2中左右视图完全平行对准的理想形式)。而立体匹配所做的工作,就是在之前的基础上,求取最后一个变量:视差d(这个d一般需要达到亚像素精度)。从而最终完成求一个点三维坐标所需要的准备工作。

    展开全文
  • 双目视觉的目标测距主要任务为利用双目相机完成对场景中物体或障碍物距离的计算,提供场景深度信息。 双目视觉的目标测距流程主要包括以下几个步骤:图像的获取、图像的矫正、立体匹配和距离计算。其中立体匹配是...
  • opencv实现双目视觉测距

    万次阅读 多人点赞 2017-12-26 11:47:21
    最近一直在研究双目视觉测距,资料真的特别多网上,有matlab 的,python的,C++的,但个人感觉都不详细,对于小白,特别不容易上手,在这里我提供一个傻瓜式教程吧,利用matlab来进行标注,图形界面,无须任何代码,...
  • 转载双目相机标定以及立体测距原理及OpenCV实现 http://blog.csdn.net/dcrmg/article/details/52986522?locationNum=15&fps=1 单目相机标定的目标是获取相机的内参和外参,内参(1/dx,1/dy,Cx,Cy,f)表征了...
  • 最近在做双目测距,觉得有必要记录点东西,所以我的第一篇博客就这么诞生啦~双目测距属于立体视觉这一块,我觉得应该有很多人踩过这个坑了,但网上的资料依旧是云里雾里的,要么是理论讲一大堆,最后发现还不知道...
  • 这是我双目测距代码中的使用opencv3.1进行相机标定的代码。
  • 双目测距

    热门讨论 2018-11-21 14:04:13
    环境配置。visual Studio2013。Python3.5。OpenCV4.0、numpy1.16。相机标定。MATLAB的Camera Calibration Toolbox工具箱。张正友相机标定算法。左右相机的标定。立体标定。...双目测距。结果演示。
  • 如果你已经看完了:一起做双目测距-USB_CAMERA检测人脸距离系列(1)–OpenCV打开双目摄像头,那么你的摄像头将可以像电脑摄像头那样读取到图片数据了,接下来我们关注了解你所拥有的这对摄像头,进行双目相机的标定...
  • 为了得到一种易实现且精度较高的双目测距方法,立体校正左右相机的非前向平行结构,先将改进的Census变换算法应用于立体匹配,得到准确的视差值,再根据双目视觉特殊的外极线几何结构计算出实际的距离信息。将原始Census...
  • 双目测距 ZED OpenCV

    2020-03-27 03:40:49
    使用双目相机ZED OpenCV3.1 完成一个双目测距,使用OpenCV3.1中 ximgproc的disparity_filter类,得到效果不错的深度图,并且转换成实际的距离。编译版本为release 使用CMake编译带扩展的OpenCV3.1,需要配置zedsdk。...
  • 双目摄像头测距算法

    千次阅读 2020-03-11 17:43:49
    双目摄像头测距算法 输入输出接口 Input: (1)左右两个摄像头采集的实时图像视频分辨率(整型int) (2)左右两个摄像头采集的实时图像视频格式 (RGB,YUV,MP4等) (3)摄像头标定参数(中心位置(x,y)和5个...
  • 双目视觉测距原理深度剖析:一个被忽略的小问题

    千次阅读 热门讨论 2018-12-21 17:03:22
    这里不对双目视觉测距的原理进行过多讲解,而是针对双目测距公式,一个容易忽视的小问题,讲一下我的学习所得,欢迎大家批评指正。...双目相机–双目视差与深度距离关系推导详解 以下内容也是由此引发: ...
  • right.jpg") height, width= imgL.shape[0:2]#读取相机内参和外参 config =stereoconfig.stereoCameral() map1x, map1y, map2x, map2y, Q=getRectifyTransform(height, width, config) iml_rectified, imr_rectified...
  • 转载 双目相机标定以及立体测距原理及OpenCV实现 http://blog.csdn.net/dcrmg/article/details/52986522?locationNum=15&fps=1 单目相机标定的目标是获取相机的内参和外参,内参(1/dx,1/dy,Cx,Cy,f)表征...
  • 最近在做双目相机测距及三维重建,我从tb买了一个双目相机,第一步需要通过棋盘图来对双目相机进行标定,由于双目相机拍出来的左右相机的图片是一张图,需要进行分割。 #include<iostream> #include<...
  • 双目视觉测距系统软硬件设计

    千次阅读 热门讨论 2021-05-11 08:27:59
    双目视觉测距系统软硬件设计 1、 简介 随着计算机技术和光电技术的发展,机器视觉技术应运而生。在图像处理技术领域中,有一种采用 CCD摄像机作为图像传感器采集数据的非接触式测量方法,这种方法具有精度高、速度快...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,346
精华内容 538
关键字:

双目相机测距