1. 程式人生 > >相機標定和校正

相機標定和校正

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<Point2f> corners;                  /****    快取每幅影象上檢測到的角點       ****/
	vector<vector<Point2f>>  corners_Seq;    /****  儲存檢測到的所有角點       ****/
	vector<Mat>  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<vector<Point3f>>  object_Points;
	//Mat img_points = Mat(1, count, CV_32FC2, Scalar::all(0));////
	//vector<int>  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<cv::Mat> rotation_vectors;
	vector<cv::Mat> translation_vectors;
	
	for (int n = 0; n < img_count; ++n)
	{
		vector<Point3f> 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<Point2f>  image_points2;
	for (int n = 0; n < img_count; ++n)
	{
		vector<Point3f> tempPointSet = object_Points[n];
		/****    通過得到的攝像機內外引數,對空間的三維點進行重新投影計算,得到新的投影點     ****/
		projectPoints(tempPointSet, rotation_vectors[n], translation_vectors[n], intrinsic_matrix, distortion_coeffs, image_points2);
		/* 計算新的投影點和舊的投影點之間的誤差*/
		vector<Point2f> 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<Vec2f>(0, i) = Vec2f(image_points2[i].x, image_points2[i].y);
			tempImagePointMat.at<Vec2f>(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);
}