双目相机标定精度测量:匹配点对(2D)的距离(3D)与实际距离的差

相机标定注意事项

听了上海交大的博士的相机标定直播,列举了以下注意事项

  1. 拍摄15-20张图片进行标定;
  2. 使用标准的标定板减小误差,最好不要直接打印一张A4的棋盘格就去标定,由于张氏标定法假设z=0,A4纸粘在纸板上无法保证z=0,从标定处便引入了误差,圆形标定板的精度比棋盘格高;
  3. 拍摄图片中棋盘格的位置最好在中心和边缘都有分布;
  4. 标定精度可用重投影误差计算,还可以从2D到3D投影特定点,比较点之间的距离。

使用边长为25mm的12*9的标准棋盘格标定相机,使用标定好的参数将两对匹配点投影到3D控件,计算点与点之间的距离,并与实际的3D点的距离比较,从而得到精度。
以下程序选取棋盘格的距离最远的两个角点。

#include
#include
using namespace cv;
using namespace std;


///双目相机,y方向存在误差
Mat cameraMatrixL = (Mat_(3, 3) << 2324.328, 0, 338.492,
	0, 2325.87799, 268.76668, 0, 0, 1);
Mat distCoeffL = (Mat_(5, 1) << -0.603, 1.3469, 0.0, 0.0, 0.00000);

Mat cameraMatrixR = (Mat_(3, 3) << 2324.518, 0, 303.5,
	0, 2324.6, 274.7977, 0, 0, 1);
Mat distCoeffR = (Mat_(5, 1) << -0.6034, 1.6096, 0.0,
	0.0, 0.00000);
//左右目之间的R,t可通过stereoCalibrate()或matlab工具箱calib求得
Mat T = (Mat_(3, 1) << 0.2799, 23.91316, 7.2362);		//T平移向量
Mat R = (Mat_(3, 3) << 1.0, 0.00064, 0.0024,
	-0.00064, 1.0, 0.0013, -0.0024,-0.0013, 1.0);


void reconstruct(Mat& K1, Mat& K2, Mat& R, Mat& T, vector& p1, vector& p2, Mat& structure)
{
	//两个相机的投影矩阵[R T],triangulatePoints只支持float型
	//K1,K2是相机的内参矩阵
	Mat proj1(3, 4, CV_32FC1);
	Mat proj2(3, 4, CV_32FC1);

	proj1(Range(0, 3), Range(0, 3)) = Mat::eye(3, 3, CV_32FC1);
	proj1.col(3) = Mat::zeros(3, 1, CV_32FC1);

	R.convertTo(proj2(Range(0, 3), Range(0, 3)), CV_32FC1);
	T.convertTo(proj2.col(3), CV_32FC1);

	Mat fK1,fK2;
	K1.convertTo(fK1, CV_32FC1);
	K2.convertTo(fK2, CV_32FC1);

	proj1 = fK1 * proj1;
	proj2 = fK2 * proj2;

	//三角化重建
	triangulatePoints(proj1, proj2, p1, p2, structure);
}



int main()
{
	char left_path[100], right_path[100];
	sprintf_s(left_path, "images/left/left.txt");
	sprintf_s(right_path, "images/right/right.txt");
	ifstream finL(left_path);
	ifstream finR(right_path);
	string left_img, right_img;
	float num= 0;
	float total_dis=0;
	while (getline(finL,left_img)&& getline(finR, right_img))
	{
		left_img = "images/left/"+left_img;
		right_img = "images/right/" + right_img;

		Mat f1 = imread(left_img);
		Mat f2 = imread(right_img);	//左右图读入
		Mat undistorf1, undistorf2;
		undistort(f1, undistorf1, cameraMatrixL, distCoeffL);
		undistort(f2, undistorf2, cameraMatrixR, distCoeffR);//图片去畸变

		vector p1, p2;
		vector p3, p4;
		//vector undistorp3, undistorp4;

		findChessboardCorners(undistorf1, Size(11, 8), p1);
		findChessboardCorners(undistorf2, Size(11, 8), p2);
		p3.push_back(p1[0]);
		p3.push_back(p1[p1.size() - 1]);
		p4.push_back(p2[0]);
		p4.push_back(p2[p2.size() - 1]);
		Mat structure;
		reconstruct(cameraMatrixL, cameraMatrixR, R, T, p3, p4, structure);
		int i = 0;
		vector calculat;
		for (i = 0; i < structure.cols; i++)
		{
			Mat_ col = structure.col(i);
			col /= col(3);
		//	cout << "x:" << col(0) << endl << "y:" << col(1) << endl << "z:" << col(2) << endl;
			calculat.push_back(col(0));
			calculat.push_back(col(1));
			calculat.push_back(col(2));
		}
		float cal_dis = sqrtf(powf(calculat[0] - calculat[3], 2) + powf(calculat[1] - calculat[4], 2) +
			powf(calculat[2] - calculat[5], 2));
		calculat.clear();
		cout << "The calculated distance is " << cal_dis << "mm" << endl;
		//cout << "The real distance is " << 305.164 << "mm" << endl;
		total_dis=total_dis+cal_dis;
		num++;
	}
	float mean_dis = total_dis / num;
	cout << "The real distance is " << 305.164 << "mm" << endl;
	cout << "The mean calculated distance is " <

我使用的11*8的棋盘格,格子的长度为25mm,2D投影到3D的距离(格子的边长)计算如下
双目相机标定精度测量:匹配点对(2D)的距离(3D)与实际距离的差_第1张图片

计算距离最远的角点的距离双目相机标定精度测量:匹配点对(2D)的距离(3D)与实际距离的差_第2张图片

你可能感兴趣的:(3D)