精华内容
下载资源
问答
  • 双目视觉测距

    2018-11-05 09:33:01
    双目测距好书、场景构建slam等内容很赞! 推荐给各位需要的工程师阅读。
  • opencv实现双目视觉测距

    万次阅读 多人点赞 2017-12-26 11:47:21
    最近一直在研究双目视觉测距,资料真的特别多网上,有matlab 的,python的,C++的,但个人感觉都不详细,对于小白,特别不容易上手,在这里我提供一个傻瓜式教程吧,利用matlab来进行标注,图形界面,无须任何代码,...

    有个群193369905,相关毕设也可找群主,最近一直在研究双目视觉测距,资料真的特别多网上,有matlab 的,python的,C++的,但个人感觉都不详细,对于小白,特别不容易上手,在这里我提供一个傻瓜式教程吧,利用matlab来进行标注,图形界面,无须任何代码,然后利用C++实现测距与深度图,原理太多我就不提了,小白直接照做就OK
    1、准备工作
    硬件准备
    https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4004-17093912817.2.6af681c0jaZTur&id=562773790704
    摄像头一个(如图),淘宝连接
    这里写图片描述
    软件准备
    VS+opencv3.1
    Matlab+toolbox标定工具箱
    C++代码
    Vs+opencv配置各位见这篇博客 https://www.cnblogs.com/linshuhe/p/5764394.html,讲解的够详细了,我们需要用VS+opencv3.1实现实时测距

    2matlab标定****

    matlab用于单目摄像头,双目摄像头的标定,这个我也已经做过了,各位直接参考这篇博客 http://blog.csdn.net/hyacinthkiss/article/details/41317087
    各位准备好上面那些工具以后我们才能正式开始
    我们通过matlab标定可以获得以下数据

    这里写图片描述

    或者使用C++ 进行单双目标定

    单目标定

    #include <iostream>
    #include <sstream>
    #include <time.h>
    #include <stdio.h>
    #include <fstream>
    
    #include <opencv2/core/core.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <opencv2/calib3d/calib3d.hpp>
    #include <opencv2/highgui/highgui.hpp>
    
    using namespace cv;
    using namespace std;
    #define calibration
    
    int main()
    {
    #ifdef calibration
    
    	ifstream fin("right_img.txt");             /* 标定所用图像文件的路径 */
    	ofstream fout("caliberation_result_right.txt");  /* 保存标定结果的文件 */
    
    	// 读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
    	int image_count = 0;  /* 图像数量 */
    	Size image_size;      /* 图像的尺寸 */
    	Size board_size = Size(11,8);             /* 标定板上每行、列的角点数 */
    	vector<Point2f> image_points_buf;         /* 缓存每幅图像上检测到的角点 */
    	vector<vector<Point2f>> image_points_seq; /* 保存检测到的所有角点 */
    	string filename;      // 图片名
    	vector<string> filenames;
    
    	while (getline(fin, filename))
    	{
    		++image_count;
    		Mat imageInput = imread(filename);
    		filenames.push_back(filename);
    
    		// 读入第一张图片时获取图片大小
    		if (image_count == 1)
    		{
    			image_size.width = imageInput.cols;
    			image_size.height = imageInput.rows;
    		}
    
    		/* 提取角点 */
    		if (0 == findChessboardCorners(imageInput, board_size, image_points_buf))
    		{
    			//cout << "can not find chessboard corners!\n";  // 找不到角点
    			cout << "**" << filename << "** can not find chessboard corners!\n";
    			exit(1);
    		}
    		else
    		{
    			Mat view_gray;
    			cvtColor(imageInput, view_gray, CV_RGB2GRAY);  // 转灰度图
    
    			/* 亚像素精确化 */
    			// image_points_buf 初始的角点坐标向量,同时作为亚像素坐标位置的输出
    			// Size(5,5) 搜索窗口大小
    			// (-1,-1)表示没有死区
    			// TermCriteria 角点的迭代过程的终止条件, 可以为迭代次数和角点精度两者的组合
    			cornerSubPix(view_gray, image_points_buf, Size(5, 5), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
    
    			image_points_seq.push_back(image_points_buf);  // 保存亚像素角点
    
    			/* 在图像上显示角点位置 */
    			drawChessboardCorners(view_gray, board_size, image_points_buf, false); // 用于在图片中标记角点
    
    			imshow("Camera Calibration", view_gray);       // 显示图片
    
    			waitKey(500); //暂停0.5S      
    		}
    	}
    	int CornerNum = board_size.width * board_size.height;  // 每张图片上总的角点数
    
    	//-------------以下是摄像机标定------------------
    
    	/*棋盘三维信息*/
    	Size square_size = Size(60, 60);         /* 实际测量得到的标定板上每个棋盘格的大小 */
    	vector<vector<Point3f>> object_points;   /* 保存标定板上角点的三维坐标 */
    
    	/*内外参数*/
    	Mat cameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));  /* 摄像机内参数矩阵 */
    	vector<int> point_counts;   // 每幅图像中角点的数量
    	Mat distCoeffs = Mat(1, 5, CV_32FC1, Scalar::all(0));       /* 摄像机的5个畸变系数:k1,k2,p1,p2,k3 */
    	vector<Mat> tvecsMat;      /* 每幅图像的旋转向量 */
    	vector<Mat> rvecsMat;      /* 每幅图像的平移向量 */
    
    	/* 初始化标定板上角点的三维坐标 */
    	int i, j, t;
    	for (t = 0; t<image_count; t++)
    	{
    		vector<Point3f> tempPointSet;
    		for (i = 0; i<board_size.height; i++)
    		{
    			for (j = 0; j<board_size.width; j++)
    			{
    				Point3f realPoint;
    
    				/* 假设标定板放在世界坐标系中z=0的平面上 */
    				realPoint.x = i * square_size.width;
    				realPoint.y = j * square_size.height;
    				realPoint.z = 0;
    				tempPointSet.push_back(realPoint);
    			}
    		}
    		object_points.push_back(tempPointSet);
    	}
    
    	/* 初始化每幅图像中的角点数量,假定每幅图像中都可以看到完整的标定板 */
    	for (i = 0; i<image_count; i++)
    	{
    		point_counts.push_back(board_size.width * board_size.height);
    	}
    
    	/* 开始标定 */
    	// object_points 世界坐标系中的角点的三维坐标
    	// image_points_seq 每一个内角点对应的图像坐标点
    	// image_size 图像的像素尺寸大小
    	// cameraMatrix 输出,内参矩阵
    	// distCoeffs 输出,畸变系数
    	// rvecsMat 输出,旋转向量
    	// tvecsMat 输出,位移向量
    	// 0 标定时所采用的算法
    	calibrateCamera(object_points, image_points_seq, image_size, cameraMatrix, distCoeffs, rvecsMat, tvecsMat, 0);
    
    	//------------------------标定完成------------------------------------
    
    	// -------------------对标定结果进行评价------------------------------
    
    	double total_err = 0.0;         /* 所有图像的平均误差的总和 */
    	double err = 0.0;               /* 每幅图像的平均误差 */
    	vector<Point2f> image_points2;  /* 保存重新计算得到的投影点 */
    	fout << "每幅图像的标定误差:\n";
    
    	for (i = 0; i<image_count; i++)
    	{
    		vector<Point3f> tempPointSet = object_points[i];
    
    		/* 通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点 */
    		projectPoints(tempPointSet, rvecsMat[i], tvecsMat[i], cameraMatrix, distCoeffs, image_points2);
    
    		/* 计算新的投影点和旧的投影点之间的误差*/
    		vector<Point2f> tempImagePoint = image_points_seq[i];
    		Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
    		Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
    
    		for (int j = 0; j < tempImagePoint.size(); j++)
    		{
    			image_points2Mat.at<Vec2f>(0, j) = Vec2f(image_points2[j].x, image_points2[j].y);
    			tempImagePointMat.at<Vec2f>(0, j) = Vec2f(tempImagePoint[j].x, tempImagePoint[j].y);
    		}
    		err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
    		total_err += err /= point_counts[i];
    		fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
    	}
    	fout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;
    
    	//-------------------------评价完成---------------------------------------------
    
    	//-----------------------保存定标结果------------------------------------------- 
    	Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0));  /* 保存每幅图像的旋转矩阵 */
    	fout << "相机内参数矩阵:" << endl;
    	fout << cameraMatrix << endl << endl;
    	fout << "畸变系数:\n";
    	fout << distCoeffs << endl << endl << endl;
    	for (int i = 0; i<image_count; i++)
    	{
    		fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
    		fout << tvecsMat[i] << endl;
    
    		/* 将旋转向量转换为相对应的旋转矩阵 */
    		Rodrigues(tvecsMat[i], rotation_matrix);
    		fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
    		fout << rotation_matrix << endl;
    		fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
    		fout << rvecsMat[i] << endl << endl;
    	}
    	fout << endl;
    
    	//--------------------标定结果保存结束-------------------------------
    
    	//----------------------显示定标结果--------------------------------
    
    	Mat mapx = Mat(image_size, CV_32FC1);
    	Mat mapy = Mat(image_size, CV_32FC1);
    	Mat R = Mat::eye(3, 3, CV_32F);
    	string imageFileName;
    	std::stringstream StrStm;
    	for (int i = 0; i != image_count; i++)
    	{
    		initUndistortRectifyMap(cameraMatrix, distCoeffs, R, cameraMatrix, image_size, CV_32FC1, mapx, mapy);
    		Mat imageSource = imread(filenames[i]);
    		Mat newimage = imageSource.clone();
    		remap(imageSource, newimage, mapx, mapy, INTER_LINEAR);
    		StrStm.clear();
    		imageFileName.clear();
    		StrStm << i + 1;
    		StrStm >> imageFileName;
    		imageFileName += "_d.jpg";
    		imwrite(imageFileName, newimage);
    	}
    
    	fin.close();
    	fout.close();
    
    #else 
    		/// 读取一副图片,不改变图片本身的颜色类型(该读取方式为DOS运行模式)
    		Mat src = imread("F:\\lane_line_detection\\left_img\\1.jpg");
    		Mat distortion = src.clone();
    		Mat camera_matrix = Mat(3, 3, CV_32FC1);
    		Mat distortion_coefficients;
    
    
    		//导入相机内参和畸变系数矩阵
    		FileStorage file_storage("F:\\lane_line_detection\\left_img\\Intrinsic.xml", FileStorage::READ);
    		file_storage["CameraMatrix"] >> camera_matrix;
    		file_storage["Dist"] >> distortion_coefficients;
    		file_storage.release();
    
    		//矫正
    		cv::undistort(src, distortion, camera_matrix, distortion_coefficients);
    
    		cv::imshow("img", src);
    		cv::imshow("undistort", distortion);
    		cv::imwrite("undistort.jpg", distortion);
    
    		cv::waitKey(0);
    #endif // DEBUG
    	return 0;
    }
    
    
    

    双目标定

    //双目相机标定 
    #include <opencv2/core/core.hpp>
    #include <opencv2/imgproc/imgproc.hpp>
    #include <opencv2/calib3d/calib3d.hpp>
    #include <opencv2/highgui/highgui.hpp>
    
    #include <vector>
    #include <string>
    #include <algorithm>
    #include <iostream>
    #include <iterator>
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    
    #include <opencv2/opencv.hpp>
    //#include <cv.h>
    //#include <cv.hpp>
    
    using namespace std;
    using namespace cv;
    //摄像头的分辨率
    const int imageWidth = 640;
    const int imageHeight = 480;
    //横向的角点数目
    const int boardWidth = 11;
    //纵向的角点数目
    const int boardHeight = 8;
    //总的角点数目
    const int boardCorner = boardWidth * boardHeight;
    //相机标定时需要采用的图像帧数
    const int frameNumber = 8;
    //标定板黑白格子的大小 单位是mm
    const int squareSize = 60;
    //标定板的总内角点
    const Size boardSize = Size(boardWidth, boardHeight);
    Size imageSize = Size(imageWidth, imageHeight);
    
    Mat R, T, E, F;
    //R旋转矢量 T平移矢量 E本征矩阵 F基础矩阵
    vector<Mat> rvecs; //R
    vector<Mat> tvecs; //T
    //左边摄像机所有照片角点的坐标集合
    vector<vector<Point2f>> imagePointL;
    //右边摄像机所有照片角点的坐标集合
    vector<vector<Point2f>> imagePointR;
    //各图像的角点的实际的物理坐标集合
    vector<vector<Point3f>> objRealPoint;
    //左边摄像机某一照片角点坐标集合
    vector<Point2f> cornerL;
    //右边摄像机某一照片角点坐标集合
    vector<Point2f> cornerR;
    
    Mat rgbImageL, grayImageL;
    Mat rgbImageR, grayImageR;
    
    Mat intrinsic;
    Mat distortion_coeff;
    //校正旋转矩阵R,投影矩阵P,重投影矩阵Q
    Mat Rl, Rr, Pl, Pr, Q;
    //映射表
    Mat mapLx, mapLy, mapRx, mapRy;
    Rect validROIL, validROIR;
    //图像校正之后,会对图像进行裁剪,其中,validROI裁剪之后的区域
    /*事先标定好的左相机的内参矩阵
    fx 0 cx
    0 fy cy
    0  0  1
    */
    Mat cameraMatrixL = (Mat_<double>(3,3) << 271.7792785637638, 0, 313.4559554347688,
    	0, 271.9513066781816, 232.7561625477742,
    	0, 0, 1);
    //获得的畸变参数
    Mat distCoeffL = (Mat_<double>(5,1) << -0.3271838086967946, 0.1326861805365006, -0.0008527407221595511, -0.0003398213328658643, -0.02847446149341753);
    /*事先标定好的右相机的内参矩阵
    fx 0 cx
    0 fy cy
    0  0  1
    */
    Mat cameraMatrixR = (Mat_<double>(3,3) << 268.4990780091891, 0, 325.75156647688,
    	0, 269.7906504513069, 212.5928387210573,
    	0, 0, 1);
    Mat distCoeffR = (Mat_<double>(5,1) << -0.321298212260166, 0.1215100334221875, -0.0007504391036193558, -1.732473939234179e-05, -0.02234659175488724);
    
    /*计算标定板上模块的实际物理坐标*/
    void calRealPoint(vector<vector<Point3f>>& obj, int boardWidth, int boardHeight, int imgNumber, int squareSize)
    {
        vector<Point3f> imgpoint;
        for (int rowIndex = 0; rowIndex < boardHeight; rowIndex++)
        {
            for (int colIndex = 0; colIndex < boardWidth; colIndex++)
            {
                imgpoint.push_back(Point3f(rowIndex * squareSize, colIndex * squareSize, 0));
            }
        }
        for (int imgIndex = 0; imgIndex < imgNumber; imgIndex++)
        {
            obj.push_back(imgpoint);
        }
    }
    
    
    
    void outputCameraParam(void)
    {
    	/*保存数据*/
    	/*输出数据*/
    	FileStorage fs("intrisics.yml", FileStorage::WRITE);
    	if (fs.isOpened())
    	{
    		fs << "cameraMatrixL" << cameraMatrixL << "cameraDistcoeffL" << distCoeffL << "cameraMatrixR" << cameraMatrixR << "cameraDistcoeffR" << distCoeffR;
    		fs.release();
    		cout << "cameraMatrixL=:" << cameraMatrixL << endl << "cameraDistcoeffL=:" << distCoeffL << endl << "cameraMatrixR=:" << cameraMatrixR << endl << "cameraDistcoeffR=:" << distCoeffR << endl;
    	}
    	else
    	{
    		cout << "Error: can not save the intrinsics!!!!" << endl;
    	}
    
    	fs.open("extrinsics.yml", FileStorage::WRITE);
    	if (fs.isOpened())
    	{
    		fs << "R" << R << "T" << T << "Rl" << Rl << "Rr" << Rr << "Pl" << Pl << "Pr" << Pr << "Q" << Q;
    		cout << "R=" << R << endl << "T=" << T << endl << "Rl=" << Rl << endl << "Rr" << Rr << endl << "Pl" << Pl << endl << "Pr" << Pr << endl << "Q" << Q << endl;
    		fs.release();
    	}
    	else
    	{
    		cout << "Error: can not save the extrinsic parameters\n";
    	}
    
    }
    
    
    int main(int argc, char* argv[])
    {
        Mat img;
        int goodFrameCount = 0;
        while (goodFrameCount < frameNumber)
        {
            char filename[100];
            /*读取左边的图像*/
            sprintf(filename, "/home/crj/calibration/left_img/left%d.jpg", goodFrameCount + 1);
    		
            rgbImageL = imread(filename, CV_LOAD_IMAGE_COLOR);
    		imshow("chessboardL", rgbImageL);
            cvtColor(rgbImageL, grayImageL, CV_BGR2GRAY);
            /*读取右边的图像*/
            sprintf(filename, "/home/crj/calibration/right_img/right%d.jpg", goodFrameCount + 1);
            rgbImageR = imread(filename, CV_LOAD_IMAGE_COLOR);
            cvtColor(rgbImageR, grayImageR, CV_BGR2GRAY);
    
            bool isFindL, isFindR;
            isFindL = findChessboardCorners(rgbImageL, boardSize, cornerL);
            isFindR = findChessboardCorners(rgbImageR, boardSize, cornerR);
            if (isFindL == true && isFindR == true)
            {
                cornerSubPix(grayImageL, cornerL, Size(5,5), Size(-1,1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 20, 0.1));
                drawChessboardCorners(rgbImageL, boardSize, cornerL, isFindL);
                imshow("chessboardL", rgbImageL);
                imagePointL.push_back(cornerL);
    
                cornerSubPix(grayImageR, cornerR, Size(5,5), Size(-1,-1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 20, 0.1));
                drawChessboardCorners(rgbImageR, boardSize, cornerR, isFindR);
                imshow("chessboardR", rgbImageR);
                imagePointR.push_back(cornerR);
    
                goodFrameCount++;
                cout << "the image" << goodFrameCount << " is good" << endl;
            }
            else
            {
                cout << "the image is bad please try again" << endl;
            }
            if (waitKey(10) == 'q')
            {
                break;
            }
        }
    
        //计算实际的校正点的三维坐标,根据实际标定格子的大小来设置
        calRealPoint(objRealPoint, boardWidth, boardHeight, frameNumber, squareSize);
        cout << "cal real successful" << endl;
    
        //标定摄像头
        double rms = stereoCalibrate(objRealPoint, imagePointL, imagePointR,
            cameraMatrixL, distCoeffL,
            cameraMatrixR, distCoeffR,
            Size(imageWidth, imageHeight), R, T, E, F, CALIB_USE_INTRINSIC_GUESS,
            TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, 1e-5));
    
        cout << "Stereo Calibration done with RMS error = " << rms << endl;
    
        stereoRectify(cameraMatrixL, distCoeffL, cameraMatrixR, distCoeffR, imageSize, R, T, Rl, 
            Rr, Pl, Pr, Q, CALIB_ZERO_DISPARITY, -1, imageSize, &validROIL,&validROIR);
        
    
        //摄像机校正映射
        initUndistortRectifyMap(cameraMatrixL, distCoeffL, Rl, Pl, imageSize, CV_32FC1, mapLx, mapLy);
        initUndistortRectifyMap(cameraMatrixR, distCoeffR, Rr, Pr, imageSize, CV_32FC1, mapRx, mapRy);
    
        Mat rectifyImageL, rectifyImageR;
        cvtColor(grayImageL, rectifyImageL, CV_GRAY2BGR);
        cvtColor(grayImageR, rectifyImageR, CV_GRAY2BGR);
    
        imshow("Recitify Before", rectifyImageL);
        cout << "按Q1退出..." << endl;
        //经过remap之后,左右相机的图像已经共面并且行对准了
        Mat rectifyImageL2, rectifyImageR2;
        remap(rectifyImageL, rectifyImageL2, mapLx, mapLy, INTER_LINEAR);
        remap(rectifyImageR, rectifyImageR2, mapRx, mapRy, INTER_LINEAR);
        cout << "按Q2退出..." << endl;
    
        imshow("rectifyImageL", rectifyImageL2);
        imshow("rectifyImageR", rectifyImageR2);
    
        outputCameraParam();
    
        //显示校正结果
        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(0, 0, w, h));
        resize(rectifyImageL2, canvasPart, canvasPart.size(), 0, 0, INTER_AREA);
        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(rectifyImageR2, 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, 255, 0), 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);
        
        cout << "wait key" << endl;
        waitKey(0);
        return 0;
    }
    
    

    **3 **C++与opencv实现测距 ****
    我们把matlab数据填写到下列代码中,各位切记不要填写错误,以免导致出现离奇的数据,我已经注释的非常清楚了;

    /*
    事先标定好的相机的参数
    fx 0 cx
    0 fy cy
    0 0  1
    */
    Mat cameraMatrixL = (Mat_<double>(3, 3) << 682.55880, 0, 384.13666,
        0, 682.24569, 311.19558,
        0, 0, 1);
    //对应matlab里的左相机标定矩阵
    Mat distCoeffL = (Mat_<double>(5, 1) << -0.51614, 0.36098, 0.00523, -0.00225, 0.00000);
    //对应Matlab所得左i相机畸变参数
    
    Mat cameraMatrixR = (Mat_<double>(3, 3) << 685.03817, 0, 397.39092,
        0, 682.54282, 272.04875,
        0, 0, 1);
    //对应matlab里的右相机标定矩阵
    
    Mat distCoeffR = (Mat_<double>(5, 1) << -0.46640, 0.22148, 0.00947, -0.00242, 0.00000);
    //对应Matlab所得右相机畸变参数
    
    Mat T = (Mat_<double>(3, 1) << -61.34485, 2.89570, -4.76870);//T平移向量
                                                        //对应Matlab所得T参数
    Mat rec = (Mat_<double>(3, 1) << -0.00306, -0.03207, 0.00206);//rec旋转向量,对应matlab om参数
    Mat R;//R 旋转矩阵
    
    

    4、完整代码 (我这里以上述摄像头拍摄的两张图来作为测距,同样可修改作为视频的实时测距,一定要将图片拷贝到你的工程目录下)

    
    /******************************/
    /*        立体匹配和测距        */
    /******************************/
    
    #include <opencv2/opencv.hpp>  
    #include <iostream>  
    
    using namespace std;
    using namespace cv;
    
    const int imageWidth = 800;                             //摄像头的分辨率  
    const int imageHeight = 600;
    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) << 682.55880, 0, 384.13666,
    	0, 682.24569, 311.19558,
    	0, 0, 1);
    //对应matlab里的左相机标定矩阵
    Mat distCoeffL = (Mat_<double>(5, 1) << -0.51614, 0.36098, 0.00523, -0.00225, 0.00000);
    //对应Matlab所得左i相机畸变参数
    
    Mat cameraMatrixR = (Mat_<double>(3, 3) << 685.03817, 0, 397.39092,
    	0, 682.54282, 272.04875,
    	0, 0, 1);
    //对应matlab里的右相机标定矩阵
    
    Mat distCoeffR = (Mat_<double>(5, 1) << -0.46640, 0.22148, 0.00947, -0.00242, 0.00000);
    //对应Matlab所得右相机畸变参数
    
    Mat T = (Mat_<double>(3, 1) << -61.34485, 2.89570, -4.76870);//T平移向量
                                                        //对应Matlab所得T参数
    Mat rec = (Mat_<double>(3, 1) << -0.00306, -0.03207, 0.00206);//rec旋转向量,对应matlab om参数
    Mat R;//R 旋转矩阵
    
    
    	  /*****立体匹配*****/
    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);
    }
    
    /*****描述:鼠标操作回调*****/
    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("left.bmp", CV_LOAD_IMAGE_COLOR);
    	cvtColor(rgbImageL, grayImageL, CV_BGR2GRAY);
    	rgbImageR = imread("right.bmp", 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);
    	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);
    	stereo_match(0, 0);
    
    	waitKey(0);
    	return 0;
    }
    

    如果对此代码和标定过程,或者遇到什么困难,大家可发邮件到1039463596@qq.com,或者加入到 193369905进行讨论,谢谢大家,原创不易,欢迎打赏
    在这里插入图片描述

    展开全文
  • 通过双目视觉测距.zip

    2020-07-09 16:03:52
    通过双目视觉测距Python代码,可以运行。
  • 点击–>双目视觉测距原理 很好的一篇原理入门级文章

    点击–>双目视觉测距原理
    很好的一篇原理入门级文章

    展开全文
  • 双目视觉测距系统软硬件设计

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

    双目视觉测距系统软硬件设计

    1、 简介

    随着计算机技术和光电技术的发展,机器视觉技术应运而生。在图像处理技术领域中,有一种采用 CCD摄像机作为图像传感器采集数据的非接触式测量方法,这种方法具有精度高、速度快、成本低等诸多优点,在三维测量方面具有广泛的应用前景。双目测距技术运用两个摄像头对同一场景进行拍摄,从而产生图像视差,然后通过该视差建立物体距离测量模型,从而实现景物距离的实时计算。

    2、机器视觉应用与测量方法

    随着计算机信号处理技术的不断发展,利用摄像机获取环境图像信息,从而实现对视觉信息的信息化处理成为了可能。计算机视觉观测技术能够使计算机具备环境信息认知的能力,从而完成人眼所不能胜任的工作,大大扩展了视觉信息处理的广度和深度。以计算机视觉理论基础,重点研究如何感知环境中物体的形状、位置、姿态、运动要素即为机器视觉。机器视觉的应用领域非常广泛,主要涉及工业自动化生产线应用、各类检验和监视应用、视觉导航应用、图像自动解释应用、人机交互应用、虚拟现实应用等多个领域和场合,并取得了很多实用的成果。在数字图像处理和计算机视觉理论研究的基础上,三维曲面非接触式测量技术获得了长足发展,并由此研究出了与众多领域相适应的测量方法,主要包括:
    1)激光干涉测量法。该方法是基于光波叠加原理,利用光的干涉原理对物理进行测量,在干涉场中产生亮暗交替的干涉条纹,通过分析处理干涉条纹来获取被测物体相关信息。
    2)激光扫描法。该方法是基于光学三角形,从激光光源向实物表面投射一亮点或直线条纹,从 CCD 相机中获得光束影像,根据光学三角关系计算反射点三维坐标来进行测量。
    3)双目立体视觉测量。该方法是基于视差原理,由多幅图像获取物体三维几何信息,然后通过视差原理恢复出物体三维几何信息,从而重建周围景物的三维形状与位置信息。
    4)结构光三维视觉测量。基于光学三角法测量原理,利用光源和成像系统之间的三角几何信息进行三维形面测量。

    3 、基于轴线平行结构的双目视觉测距原理

    双目立体视觉测量方法是研究如何利用二维投影图像重构三维景物世界,运用两台不同位置的摄像机(CCD)拍摄同一场景,计算空间点在图像中的视差,从而获取该点三维空间坐标。双目立体视觉是基于视差原理,由三角法原理进行三维信息的获取,即由两个摄像机的图像平面和北侧物体之间构成一个三角形,两个摄像机之间的位置关系,便可以获得两摄像机公共视场内物体的三维尺寸及空间物体特征点的三维坐标。图 1为简单的平视双目立体成像原理图,两台摄像机的投影中心连线的距离,即基线距离B。两台摄像机在同一时刻聚焦到时空物体的同一特征点P,分别在“左眼”和“右眼”上获取了点P的图像,他们在左右图像上的成像点分别是 pl 和 pr ,将两台摄像机的图像放在同一平面上,则特征点P的图像坐标的“Y”坐标一定是相同的。由三角几何关系可以得如下关系式:
    加粗样式
    设视差为 D = Xl - Xr 。由此可计算出特征点P在摄像机坐标系下的三维坐标为:
    在这里插入图片描述
    因此,通过计算被测目标在“左眼”、“右眼”中的像素视差值,然后由标定参数即可计算出该点的三维坐标。这种方法是点对点的运算,平面上所有点只要存储在相应的匹配点,就可以通过计算从而获取对应的三维坐标。
    在这里插入图片描述

    4、基于轴线汇聚结构的双目视觉测距原理

    虽然轴线平行结构的双目视觉测距系统原理简单,计算方便,但该结构是理想的结构形式,实际应用中容易受到摄像机性能差异、安装工艺等各种因素的影响。通常情况下,双目视觉测距系统倾向于采用轴线汇聚结构。空间参考点 P 在已标定摄像机 Cl 和 Cr 上的像点分别为 pl 和 pr ,如图2所示。
    在这里插入图片描述
    其投影矩阵分别为 M1 和 M2 ,由矩阵变换关系可得:(下面图片3、4)
    在这里插入图片描述
    式中,(ulvl1) 为 pl 在图像坐标系下的齐次坐标;(urvr1)T 为 pr 在 图 像 坐 标 系 中 的 齐 次 坐 标 ;(xcyczc1)T 为点 P 在世界坐标系下的齐次坐标。矩阵令M1、M2的表达形式为
    在这里插入图片描述
    将 M1、M2的表达形式代入式(3)、(4),采用最小二乘解算法得到空间坐标为
    在这里插入图片描述
    式中,在这里插入图片描述
    在这里插入图片描述

    可得目标距离:
    在这里插入图片描述

    5 、系统软硬件架构

    在充分理解双目系统测距原理的基础来,设计系统软硬件架构。

    5.1 、硬件架构

    双目测距系统硬件由 CCD 摄像机、图像采集卡、计算机系统以及显示设备构成。CCD 摄像机的功能是获取目标图像信息;图像采集设备的功能是将图像信息转化为计算机数字信息;计算机系统的功能是处理图像数据,实现2D图像坐标到3D空间位置的恢复,最后输出和显示测量结果。系统硬件构成如图3所示。
    在这里插入图片描述

    5.2 软件架构

    测量系统软件结构方案采用模块化,各软件功能模块及其相互关系如图4所示,软件架构主要由摄像机标定模块、图像采集与信息处理模块、数字图像特征检测与特征提取模块、数字图像特征立体匹配模块、目标距离测量模块以及数据输出模块等构成。
    摄像机标定模块负责系统标定以及坐标系转换;图像采集与信息处理模块负责实现图像采集初始化,并对图像信息进行数字化转换;数字图像特征检测与特征提取模块负责对图像特征进行精细检测与精确提取;数字图像特征立体匹配模块功能为实现数字特征立体匹配算法;目标距离测量模块功能为:在精确检测与提取特征信息的基础上,解算三维坐标,实现距离在线解算,并通过数据输出模块输出相应息。
    在这里插入图片描述
    双目视觉测距系统开启工作时,首先通过镜头将被测量物体的光学图像成像在 CCD图像传感器上;然后图像传感器将光信号转换为模拟电信号,并经数模转换器将模拟信号转换为数字信号;然后经过图像处理器对数字信息进行处理,并存储在存储器中;最后,通过数字接口或视频接口输入。

    关注苏州程序大白,持续更新技术分享。谢谢大家支持

    展开全文
  • 本发明属于双目视觉技术领域,具体涉及一种基于可变焦相机的双目视觉测距方法。背景技术:在这个计算机视觉技术发展迅速的时代,获取深度信息成为了一个热门的课题,因其所诞生的方法也各式各样,但是绝大部分的方法...

    本发明属于双目视觉技术领域,具体涉及一种基于可变焦相机的双目视觉测距方法。

    背景技术:

    在这个计算机视觉技术发展迅速的时代,获取深度信息成为了一个热门的课题,因其所诞生的方法也各式各样,但是绝大部分的方法都有一定的缺陷。例如,目前比较成熟的利用相同型号的固定焦距的相机来获取深度信息的方法。这个方法成本很低,在一定范围内,它所获得的深度准确度也较高,但是一旦所测目标超出了这个范围,那么所获取的深度信息的精确度就会大打折扣。其原因就是因为用于获取信息的两个相机的焦距是固定的,那么所获得的视野也就是固定的。假如,所测目标离双目系统较远,在相机中的成像也比较模糊,那么获取的信息量就少,由此得出的深度信息精确度也较低。

    所以人们想到了使用变焦相机来进行双目测距,根据所选取的目标来变换相机的焦距,来达到目标在相机成像清晰的目的,使测出来的深度信息更为精确。但是对于不同距离的测量目标,相机的调焦量也不同,每次调焦都会改变相机的焦距,所以两个相机的焦距难以保持一致,而该方法就是针对两个相机焦距不一样时,如何进行双目测距实验的。

    技术实现要素:

    本发明主要考虑到计算机视觉的迅猛发展,目前获取深度信息的方法各色各异,但是都不能完全解决测距过程中存在的问题。本方法应用于基于两个相同型号的可变焦相机的双目测距,相对于传统的双目测距,该测距系统可以根据测量目标的距离的改变,来改变相机的焦距,使得测量目标在相机图像中处于一个清晰的状态,所测出深度信息也较为精确。简而言之,就是该测距系统可以根据实际情况来调整系统参数,使测量结果处于一个较准确的状态。

    该方法按照以下步骤实施:

    步骤1:选取两个相同规格的可变焦相机,将相机并列摆放,两个相机镜头之间的距离D,并且两个相机的相机平面处于同一平面上,同时两个相机也处于同一水平高度上,从而构建一个简易的双目测距实验台;

    步骤2:根据被测目标,调整两个相机的焦距,当测量目标处于清晰状态后,开始计算当前状态下两个相机的焦距,具体步骤如下:

    2-1.取一条已知长度的笔直物体作为标准杆),并固定在一个背景较为纯净的位置,调整双目测距实验台位置,使得相机平面和标准杆处于平行的状态;

    2-2.利用相机成像原理以及三角形相似原理,获取以下公式:

    化简得到:

    其中,f1和f2分别是左相机焦距和右相机焦距;t1、t2分别是标准杆在左相机成像平面中的长度和在右相机成像平面中的长度;T是标准杆的长度,u是标准杆到相机平面的距离;

    设两个相机的CCD横向尺寸为v,设标准杆在电脑中读取的左右相机的图像中的长度为s1,s2,电脑中读取的左右相机的图像尺寸为V,则:

    然后将(5)式代入(3)式,(6)式代入(4)式,计算出f1,f2 的值;

    步骤3:将双目测距试验台对准被测目标,使得被测目标的水平坐标要夹在两个相机中心线之间,即目标在左相机画面中要处于右半面,在右相机画面中要处于左半面,然后获取被测目标的图像信息,计算物距信息,具体步骤如下:

    3-1.计算L和R:设左边相机斜率绝对值为kl、右边相机斜率绝对值为kr,然后根据kl与kr之间的比值关系来瓜分Xl到Xr之间的水平距离,从而得出L与R:

    其中,Xl是被测目标在左相机的成像在左相机平面的横坐标,Xr是被测目标在右相机的成像在右相机平面的横坐标;Xl和Xr是能够利用图像处理软件根据图像得出的,所以L和R最后是已知数,D是两个相机镜头之间的距离;b是相机画面中点的横坐标;所以L和R是最后是已知数;L 是被测目标与左相机光轴之间的水平距离;R是被测目标与左相机光轴之间的水平距离;

    3-2.利用L和R,以及三角形相似原理,计算得出物距信息U:

    根据三角形相似,可以得出:

    化简得:

    最后算出两个物距信息U的值,最后得到的深度信息取这两个物距信息U的平均值,最终结果记为Z:

    本发明有益效果如下:

    本发明方法不同于传统的利用两个固定焦距相机的双目测距,它使用了两个可变焦相机来进行双目视觉测距,在根据被测目标的距离来调整两个相机的焦距后,两个相机焦距难以保持一致的情况下,以较高的精度获取目标的物距信息。

    但是本方法同样存在着一定的局限,比如被测目标的水平坐标要夹在两个相机中心线之间。即目标在左相机画面中要处于右半面,在右相机画面中要处于左半面。

    附图说明

    图1是简易的双目测距实验台的示意图。

    图2是计算相机焦距的原理图;

    图3是计算被测目标深度信息的原理图。

    具体实施方式

    下面结合附图和实施例对本发明作进一步说明。

    本方法应用于基于两个相同型号的可变焦相机的双目测距,相对于传统的双目测距,该测距系统可以根据测量目标的距离的改变,来改变相机的焦距,使得测量目标在相机图像中处于一个清晰的状态,所测出深度信息也较为精确。简而言之,就是该测距系统可以根据实际情况来调整系统参数,使测量结果处于一个较准确的状态。

    该方法按照以下步骤实施:

    步骤1:选取两个相同规格的可变焦相机,例如索尼w100。将相机并列摆放,两个相机镜头之间的距离D,并且两个相机的相机平面处于同一平面上,同时两个相机也处于同一水平高度上,如图1所示。构建一个简易的双目测距实验台。

    步骤2:根据被测目标,调整两个相机的焦距,当测量目标处于清晰状态后,开始计算当前状态下两个相机的焦距,具体步骤如下:

    2-1.取一条已知长度的笔直物体作为标准杆(例如一根笔直木棍),并固定在一个背景较为纯净的位置,调整双目测距实验台位置,使得相机平面和标准杆处于平行的状态。

    2-2.根据图2的原理图,利用相机成像原理以及三角形相似原理(这里用虚拟成像平面替换实际成像平面,方便数学上的处理)我们可以得出:

    化简得到:

    其中,f1和f2分别是左相机焦距和右相机焦距;t1、t2分别是标准杆在左相机成像平面中的长度和在右相机成像平面中的长度;T是标准杆的长度(已知),u是标准杆到相机平面的距离(已知);

    因为电脑读取相机拍摄的画面的时候,是将这个画面进行了放大的。所以t1,t2并不等于电脑读取的图像中标准杆的长度。所以这里需要通过opencv等软件计算出t1,t2的数据。设这两个相机的CCD横向尺寸为v (已知),设标准杆在电脑中读取的左右相机的图像中的长度为s1,s2 (可以通过opencv的函数计算获得),电脑中读取的左右相机的图像尺寸为V(左右图像尺寸是一样大小的)。那么就可以得出:

    然后将(5)式代入(3)式,(6)式代入(4)式,计算出f1,f2 的值;

    步骤3:将双目测距试验台对准被测目标,使得被测目标的水平坐标要夹在两个相机中心线之间,即目标在左相机画面中要处于右半面,在右相机画面中要处于左半面。然后获取被测目标的图像信息,计算物距信息,具体步骤如下:

    3-1.计算L和R:设左边相机斜率绝对值为kl、右边相机斜率绝对值为kr,然后根据kl与kr之间的比值关系来瓜分Xl到Xr之间的水平距离(也就是瓜分D-Xl+Xr),从而得出L与R:

    如图3所示,Xl是被测目标在左相机的成像在左相机平面的横坐标, Xr是被测目标在右相机的成像在右相机平面的横坐标;Xl和Xr是能够利用图像处理软件根据图像得出的,所以L和R最后是已知数,D是两个相机镜头之间的距离;b是相机画面中点的横坐标;所以L和R是最后是已知数; L是被测目标与左相机光轴之间的水平距离;R是被测目标与左相机光轴之间的水平距离;

    3-2.利用L和R,以及三角形相似原理,计算得出物距信息U:

    根据三角形相似,可以得出:

    化简得:

    最后算出两个U的值,这两个值会有一些小小的差别,因为实验必然存在着误差,所以最后的得到的深度信息取这两个结果的平均值,可以相对地提高精度,最终结果记为Z:

    展开全文
  • 双目视觉测距原理深度剖析:一个被忽略的小问题

    千次阅读 热门讨论 2018-12-21 17:03:22
    这里不对双目视觉测距的原理进行过多讲解,而是针对双目测距公式,一个容易忽视的小问题,讲一下我的学习所得,欢迎大家批评指正。 参考博客: 对于双目测距原理不了解的,可以参考如下博客,讲解的都很详细: 双目...
  • 两个部分,一个是相机的参数设置,一个是测距运用matlab里面的stereo Camera Calibrator APP进行拍照 拍个30多张,然后拉线,留个10-20张进行计算,把双目摄像机的数据填到camera_configs.py里面camera_configs.py...
  • 双目视觉测距原理,数学推导及三维重建资源 被低估的单目视觉识别 深度相机原理揭秘--双目立体视觉 什么是图像金字塔 Sift中尺度空间、高斯金字塔、差分金字塔(DOG金字塔)、图像金字塔 ...
  • python、opencv 双目视觉测距代码

    千次阅读 热门讨论 2020-05-25 19:32:50
    两个部分,一个是相机的参数设置,一个是测距 运用matlab里面的stereo Camera Calibrator APP进行拍照 拍个30多张,然后拉线,留个10-20张进行计算,把双目摄像机的数据填到camera_configs.py里面 camera_...
  • 双目视觉测距原理,数学推导及三维重建资源

    万次阅读 多人点赞 2018-01-09 21:15:20
    先说一下单/双目测距原理区别:单目测距原理:先通过图像匹配进行目标识别(各种车型、行人、物体等),再通过目标在图像中的大小去估算目标距离。这就要求在估算距离之前首先对目标进行准确识别,是汽车还是行人...
  • 结构光双目视觉测距原理

    千次阅读 2020-02-20 15:04:41
    结构光视觉技术是一种主动投影式的三维测量技术,通过使用投影仪和相机组成的系统来对物体进行三维测量 系统结构: 硬件系统: 常见编码方法: 结构光图案编码 常用的是格雷码和传统的二进制码相比,格雷...
  • 基于计算机视觉理论的双目视觉测距技术在板料成形动态测量、极限曲线检测、零部件检测等上具有较大的应用前景并将成为今后研究中的重点和难点。目前的测距方法主要有主动测距和被动测距2种方法。本研究采用被动测距...
  • 简述: 双目测距测距目标是一个贴在墙上的正方形,已经通过张氏标定得出了内外参数。但是无法确定如何选取世界坐标系以及相应的坐标。 1、问题:单目标定棋盘,世界坐标系设定于棋盘上,世界坐标系的原点选择棋盘...
  • 在学校里做完了一个双目测距的工程设计后,打算用写博文的形式对过去一段时间的工作做一个总结,也希望给需要的朋友...利用双目摄像头,可以通过双目视觉算法寻找标签,并计算各标签相对于相机的距离。然后,根据各标签
  • 学习OpenCV快3个月了,主要是根据课题需要实现双目视觉测距、景深重建和目标(障碍物)检测。目前已经能实现摄像头定标和校正、双目匹配、获取视差图和环境景深图像,但是在测距方面还没有精确实现,主要是还没彻底...
  • 学习OpenCV快3个月了,主要是根据课题需要实现双目视觉测距、景深重建和目标(障碍物)检测。目前已经能实现摄像头定标和校正、双目匹配、获取视差图和环境景深图像,但是在测距方面还没有精确实现,主要是还没彻底...
  • 一、双目测距原理 通过对两幅图像视差的计算,直接对前方景物(图像所拍摄到的范围)进行距离测量。双目摄像头的原理与人眼相似。人眼能够感知物体的远近,是由于两只眼睛对同一个物体呈现的图像存在差异,也称...
  • 我的两个相机是竖直交叉放置的,以下相机光心作为世界坐标系原点,以下相机光轴作为世界坐标系Z轴。通过坐标系转换,建立超定方程,求解得到目标点的三维信息(X,Y,Z),但是这个Z不是深度值,他只是世界坐标系Z轴...
  • 我的两个相机是竖直交叉放置的,以下相机光心作为世界坐标系原点,以下相机光轴作为世界坐标系Z轴。通过坐标系转换,建立超定方程,求解得到目标点的三维信息(X,Y,Z),但是这个Z不是深度值,他只是世界坐标系Z轴...
  • 双目摄像头测距算法输入输出接口Input:(1)左右两个摄像头采集的实时图像视频分辨率(整型int)(2)左右两个摄像头采集的实时图像视频格式 (RGB,YUV,MP4等)(3)摄像头标定参数(中心位置(x,y)和5个畸变...
  • 基于Opencv的双目立体视觉测距,,中文论文,包含双目立体视觉模型,摄像机标定,立体匹配等
  • opencv实现双目视觉测距 sgbm参数设置 双目视觉 测距,多谢博主分享!
  • 基于OpenCV的双目立体视觉测距 基于OpenCV的双U立体视觉测距 论文导读: 双U立体视觉模型摄像机标定立体匹配采用OpenCV库中的块匹配立体算 法U询的测距方法主要有主动测距和被动测距两种方法论文 关键词: 双U立体视觉...

空空如也

空空如也

1 2 3 4 5 ... 15
收藏数 294
精华内容 117
关键字:

双目视觉测距