相机标定和校正

1.标定:

首先要制作一个标定板,OpenCV包里有一个黑白棋盘标定板,直接A4纸打印就OK了。然后用需要标定的摄像头拍几张照片(注意:要从不同角度多拍几张,我用了22张。标定板上的点个的个数为54,一行9个,一列6个),首先就是找亚像素角点findChessboardCorners,看看是否是54个点。然后进一步提取亚像素角点cornerSubPix,保存角点。在标定前需要先测量标定板上一块格子的大小,单位为mm,我量的是26mm。对于标定结果,我们只关心2个量,一个是相机的内参矩阵(3*3的矩阵),另一个是畸变参数(1*5的矩阵),我只保存这两个量。然后算标定板上角点在世界坐标系下的坐标,为方便计算,假设标定板就在XOY平面上,即Z=0,也就是直接在原有坐标上*26就可以了。最后调用calibrateCamera进行标定。

void main()//标定
{ 
	
	Size board_size = Size(9, 6);            /****    定标板上每行、列的角点数       ****/
	vector corners;                  /****    缓存每幅图像上检测到的角点       ****/
	vector>  corners_Seq;    /****  保存检测到的所有角点       ****/
	vector  image_Seq;
	int count = 0;
	int img_count = 0;
	string imgname;
	ifstream fin("C:/Users/Administrator/Desktop/cam_pic/pic.txt");
	Mat src;
	while (getline(fin, imgname))
	{
		img_count++;
		imgname = "C:/Users/Administrator/Desktop/cam_pic/" + imgname;
		src = imread(imgname);

		Mat img_gray;
		cvtColor(src, img_gray, CV_BGR2GRAY);
		bool patternfound = findChessboardCorners(src, board_size, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE +
			CALIB_CB_FAST_CHECK);
		if (!patternfound)
		{
			cout << "not found" << endl;
			break;
		}
		else
		{
			cornerSubPix(img_gray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.01));
			Mat img_temp = src.clone();
			for (int i = 0; i < corners.size(); ++i)
			{
				circle(img_temp, corners[i], 2, Scalar(0, 0, 255), 2, 8, 0);
			}
			/*imshow("img_temp", img_temp);
			waitKey(0);*/
			count += corners.size();
			corners_Seq.push_back(corners);
		}
	}

	Size square_size = Size(26, 26);//
	vector>  object_Points;
	//Mat img_points = Mat(1, count, CV_32FC2, Scalar::all(0));
	//vector  point_counts;/
	Mat intrinsic_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
	Mat distortion_coeffs = Mat(1, 5, CV_32FC1, Scalar::all(0));
	vector rotation_vectors;
	vector translation_vectors;
	
	for (int n = 0; n < img_count; ++n)
	{
		vector tempPointSet_1;
		for (int i = 0; i < board_size.height; i++)
		{
			for (int j = 0; j < board_size.width; j++)
			{
				Point3f tempPoint;
				tempPoint.x = i*square_size.width;
				tempPoint.y = j*square_size.height;
				tempPoint.z = 0;
				tempPointSet_1.push_back(tempPoint);
			}
		}
		object_Points.push_back(tempPointSet_1);
	}
	calibrateCamera(object_Points, corners_Seq, src.size(), intrinsic_matrix, distortion_coeffs, rotation_vectors, translation_vectors, 0);
	

	double total_err = 0.0;                   /* 所有图像的平均误差的总和 */
	double err = 0.0;                        /* 每幅图像的平均误差 */
	vector  image_points2;
	for (int n = 0; n < img_count; ++n)
	{
		vector tempPointSet = object_Points[n];
		/****    通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点     ****/
		projectPoints(tempPointSet, rotation_vectors[n], translation_vectors[n], intrinsic_matrix, distortion_coeffs, image_points2);
		/* 计算新的投影点和旧的投影点之间的误差*/
		vector tempImagePoint = corners_Seq[n];
		Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
		Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
		for (size_t i = 0; i != tempImagePoint.size(); i++)
		{
			image_points2Mat.at(0, i) = Vec2f(image_points2[i].x, image_points2[i].y);
			tempImagePointMat.at(0, i) = Vec2f(tempImagePoint[i].x, tempImagePoint[i].y);
		}
		err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
		total_err += err /= 54;//point_counts[0]
		cout << "第" << n + 1 << "幅图像的平均误差:" << err << "像素" << endl;
	}
	cout << "总体平均误差:" << total_err /img_count<< "像素" << endl << endl;
	FileStorage fs("calibration.xml", FileStorage::WRITE);
	fs << "intrinsic_matrix" << intrinsic_matrix;
	fs << "distortion_coeffs" << distortion_coeffs;
	fs.release();
	waitKey(0);
}

2.校正:

校正就是直接读取标定保存的文件,调用initUndistortRectifyMap和remap进行校正即可。

void main()//校正
{
	FileStorage fs;
	fs.open("calibration.xml", FileStorage::READ);
	Mat intrinsic_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0));
	Mat distortion_coeffs = Mat(1, 5, CV_32FC1, Scalar::all(0));
	fs["intrinsic_matrix"] >> intrinsic_matrix;
	fs["distortion_coeffs"] >> distortion_coeffs;
	Mat src = imread("C:/Users/Administrator/Desktop/cam_pic/6.jpg");
	imshow("src", src);

	Mat mapx = Mat(src.size(), CV_32FC1);
	Mat mapy = Mat(src.size(), CV_32FC1);
	Mat R = Mat::eye(3, 3, CV_32F);

	initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R, getOptimalNewCameraMatrix(intrinsic_matrix, distortion_coeffs, src.size(), 1, src.size(), 0), src.size(), CV_32FC1, mapx, mapy);
	Mat dst = src.clone();
	remap(src, dst, mapx, mapy, INTER_LINEAR);
	imshow("dst",dst);
	waitKey(0);
}

整个的标定与校正在OpenCV包里有源码,具体位置在:E:\opencv\sources\modules\calib3d\src\calibration.cpp

你可能感兴趣的:(OpenCV)