OpenCV 相机标定和图像矫正实例演示

本文主要记录相机标定的代码实现,关于相机标定的原理可以参考:https://blog.csdn.net/weixin_43843780/article/details/89294131

本文相机标定的照片采用OpenCV提供的图片,位置:...\opencv\opencv\sources\samples\data中left01~left14.jpg

相机标定在OpenCV中实现的主要步骤为:

1. 查找每幅图像中的角点坐标和亚像素角点坐标

2. 构建每幅图像世界坐标系中的角点坐标

3. 调用相机标定算子计算相机的内参和外参

4. 计算此次相机标定的误差

 

关于详细的讲解注释在代码中

//棋盘格的大小,每行/列的角点个数
	Size boardsize = Size(9, 6);
	//记录每幅图中的角点
	vector> corners_Seq;
	//记录所有图像中的角点总和
	int count = 0;
	//棋盘格图像
	Mat srcImg;
	//图像的个数
	int image_count = 0;
	for (int i = 1; i <= 13; i++)
	{
		//记录每幅图像的名称
		string Img_files = to_string(i) + ".jpg";
		//读取图像,若读取失败则发送提示
		srcImg = imread(Img_files);
		if (!srcImg.data)
		{
			cout << "读取"< corners;
		bool cornerfound = findChessboardCorners(grayImg, boardsize, corners, CALIB_CB_ADAPTIVE_THRESH);
		if (!cornerfound)
		{
			cout << "角点查找失败" << endl;
			continue;
		}

		//根据棋盘格图像角点寻找亚像素角点
		cornerSubPix(grayImg, corners, Size(5, 5), Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 30, 0.001));

		//累计角点的个数
		count += corners.size();
		//将本幅图像的角点添加到列表中
		corners_Seq.push_back(corners);
		//图像个数+1
		image_count++;
	}

	//测量每幅图像中每个格子的大小
	Size square_size = Size(26, 26);
	//计算世界坐标系中角点的座标
	vector> object_Points;
	for (int i = 0; i < image_count; i++)
	{
		//记录当前图像中角点的世界坐标值
		vector tempPointset;
		for (int h = 0; h < boardsize.height; h++)
		{
			for (int w = 0; w < boardsize.width; w++)
			{
				Point3f tempPoint;
				tempPoint.x = w * square_size.width;
				tempPoint.y = h * square_size.height;
				tempPoint.z = 0;
				tempPointset.push_back(tempPoint);
			}
		}
		object_Points.push_back(tempPointset);
	}

	//记录相机
	//   fx,  0, cx
	//    0, fy, cy
	//    0,  0, 1
	//矩阵的参数
	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;
	//相机标定
	calibrateCamera(object_Points, corners_Seq, srcImg.size(), intrinsic_matrix, distortion_coeffs, rotation_vectors, translation_vectors, 0);

	//对标定参数的评估
	double total_err = 0.0;
	double err = 0.0;
	vector image_points2;
	for (int i = 0; i < image_count; i++)
	{
		//获取每幅图像世界坐标系下的角点坐标
		vector tempPointSet = object_Points[i];
		//根据相机的内参和外参计算得出图像坐标系下的角点坐标
		projectPoints(tempPointSet, rotation_vectors[i], translation_vectors[i], intrinsic_matrix, distortion_coeffs, image_points2);

		//记录真实图像坐标系下的角点坐标
		vector tempImagePoint = corners_Seq[i];

		//将计算得出的图像坐标系下的角点 和 真实图像坐标系下的角点坐标分别放入两个图像中
		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 << "第" << i << "幅图像的平均误差:" << err << "像素" << endl;
	}
	cout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;

	//将相机标定参数写入xml文件中
	FileStorage fs1("calibration.xml", FileStorage::WRITE);
	fs1 << "intrinsic_matrix" << intrinsic_matrix;
	fs1 << "distortion_coeffs" << distortion_coeffs;
	fs1.release();

图像矫正代码

//矫正图像
	//读取xml中的相机标定参数
	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("1.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+remap进行图像矫正
	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);

参考:https://blog.csdn.net/qq_40250862/article/details/82912698

你可能感兴趣的:(OpenCV)