OpenCV双目相机的标定C++

代码来和数据集来自于“小白公众号”
链接:https://pan.baidu.com/s/1bYrj57MEdhwWp45XXVbdpA 提取码:b3m6

双目相机标定的过程:
1.,调节两个相机的角度,给标定板拍10组左右的照片。
2,通过张正友的思想得到两个相机的内外参矩阵和畸变矩阵,为两个相机的畸变矫正做准备。
3,现实情况中,我们无法完全控制两个相机是完全平行的拍一个物体,所以只能通过矫正,来构造平行这一条件,然后通过两个相机的一些参数计算出深度z。
4,通过计算图片中物体的每一个点距离相机镜头的深度,从而构建出该物体的三维立体图。

总而言之,双目相机可以照到一个物体的更多细节,然后根据该细节在不同角度的照片中的位置,得到该细节的空间坐标信息,最终还原照片中的物体在三维空间中的图像。

缺点:双目相机只能对两个镜头都拍摄到的物体细节提取空间信息,也就是说对两个相机拍摄的物体细节无交集的那部分,会产生3D空间还原误差。

思考:如果是更加多维的相机,是不是还原的效果更好呢?
目前只知道,多目相机可以使还原的速度更快

双目相机的应用:
1,根据视差测距离
2,3d构建

代码:
以下是双目相机的标定代码,以及将两个相机的畸变矫正代码。
下一步计划:利用双目相机拍一个实际物体,利用双目参数进行三维立体的投影。

#include 
#include  
#include 
#include 

using namespace std;
using namespace cv;

void getImgsPoints(vector<Mat> imgs, vector<vector<Point2f>>& imgsPoints, Size board_size)
{
	for (int i = 0; i < imgs.size(); i++)
	{
		Mat img1 = imgs[i];
		Mat gray1;
		cvtColor(img1, gray1, COLOR_BGR2GRAY);
		vector<Point2f> img1_points;
		findChessboardCorners(gray1, board_size, img1_points);  //计算方格标定板角点
		find4QuadCornerSubpix(gray1, img1_points, Size(5, 5));  //细化方格标定板角点坐标
		imgsPoints.push_back(img1_points);
	}
}

int main()
{
	//读取所有图像
	vector<Mat> imgLs;
	vector<Mat> imgRs;
	string imgLName;
	string imgRName;
	ifstream finL("steroCalibDataL.txt");
	ifstream finR("steroCalibDataR.txt");
	while (getline(finL, imgLName) && getline(finR, imgRName))
	{
		Mat imgL = imread(imgLName);
		Mat imgR = imread(imgRName);
		imgLs.push_back(imgL);
		imgRs.push_back(imgR);
	}

	Size board_size = Size(9, 6);  //方格标定板内角点数目(行,列)
	vector<vector<Point2f>> imgLsPoints;
	vector<vector<Point2f>> imgRsPoints;
	getImgsPoints(imgLs, imgLsPoints, board_size);
	getImgsPoints(imgRs, imgRsPoints, board_size);

	//生成棋盘格每个内角点的空间三维坐标
	Size squareSize = Size(10, 10);  //棋盘格每个方格的真实尺寸
	vector<vector<Point3f>> objectPoints;
	for (int i = 0; i < imgLsPoints.size(); i++)
	{
		vector<Point3f> tempPointSet;
		for (int j = 0; j < board_size.height; j++)
		{
			for (int k = 0; k < board_size.width; k++)
			{
				Point3f realPoint;
				// 假设标定板为世界坐标系的z平面,即z=0
				realPoint.x = j * squareSize.width;
				realPoint.y = k * squareSize.height;
				realPoint.z = 0;
				tempPointSet.push_back(realPoint);
			}
		}
		objectPoints.push_back(tempPointSet);
	}

	//图像尺寸
	Size imageSize;
	imageSize.width = imgLs[0].cols;
	imageSize.height = imgLs[0].rows;

	Mat Matrix1, dist1, Matrix2, dist2, rvecs, tvecs;
	calibrateCamera(objectPoints, imgLsPoints, imageSize, Matrix1, dist1, rvecs, tvecs, 0);
	calibrateCamera(objectPoints, imgRsPoints, imageSize, Matrix2, dist2, rvecs, tvecs, 0);

	//双目相近进行标定
	Mat R, T, E, F;
	stereoCalibrate(objectPoints, imgLsPoints, imgRsPoints, Matrix1, dist1, Matrix2, dist2, imageSize, R, T, E, F, CALIB_USE_INTRINSIC_GUESS);

	//计算校正变换矩阵
	Mat R1, R2, P1, P2, Q;
	stereoRectify(Matrix1, dist1, Matrix2, dist2, imageSize, R, T, R1, R2, P1, P2, Q, 0);

	//计算校正映射矩阵
	Mat map11, map12, map21, map22;
	initUndistortRectifyMap(Matrix1, dist1, R1, P1, imageSize, CV_16SC2, map11, map12);
	initUndistortRectifyMap(Matrix2, dist2, R2, P2, imageSize, CV_16SC2, map21, map22);

	for (int i = 0; i < imgLs.size(); i++)
	{
		//进行校正映射
		Mat img1r, img2r;
		remap(imgLs[i], img1r, map11, map12, INTER_LINEAR);
		remap(imgRs[i], img2r, map21, map22, INTER_LINEAR);

		//拼接图像
		Mat result;
		hconcat(img1r, img2r, result);

		//绘制直线,用于比较同一个内角点y轴是否一致
		line(result, Point(-1, imgLsPoints[i][0].y), Point(result.cols, imgLsPoints[i][0].y), Scalar(0, 0, 255), 2);
		imshow("校正后结果", result);
		waitKey(0);
	}
	return 0;
}

所需文件:
OpenCV双目相机的标定C++_第1张图片
结果:

数据集:
steroCalibDataL.txt 存储左相机拍的照片
steroCalibDataR.txt 存储右相机拍的照片
OpenCV双目相机的标定C++_第2张图片
OpenCV双目相机的标定C++_第3张图片
OpenCV双目相机的标定C++_第4张图片
OpenCV双目相机的标定C++_第5张图片
OpenCV双目相机的标定C++_第6张图片
OpenCV双目相机的标定C++_第7张图片
OpenCV双目相机的标定C++_第8张图片
OpenCV双目相机的标定C++_第9张图片

你可能感兴趣的:(opencv,计算机视觉)