1.opencv自带标定需要定义棋盘格尺寸,必须拍全,大大限定了标定条件,本示例实现标定板角点提取,算法参考基于生长的棋盘格角点检测,二维码定义棋盘格实际坐标系和棋盘格规格,不用输入任何参数(自动识别棋盘格规格,本示例用的2*2mm标定片),绿色为识别到的角点,上方数字为对应点的棋盘格世界坐标(图片比较大,截取了一部分)

 

 2.将标定结果打包保存成本地文件,其中包括校正前后图片,保存内容如下图结构体ccbi2文件,大小大概5M

 3.读取标定文件,并利用标定文件里的标定参数(相机内参,畸变,外参等)将世界坐标Z=0平面点转换成像素坐标,映射在畸变校正后的标定板图片上,基本每个角点都是对准的,如果用像素坐标(亚像素坐标)转世界坐标误差大概在0.01mm;

 

4.下面为手动估计着找的4个非亚像素坐标点,转换为世界坐标,映射到图片上的效果,如果是输入物理坐标,算出亚像素坐标,再将亚像素坐标转换为世界坐标,基本和输入的差距在0.01mm

5.反向找到畸变校正后图片角点坐标,并把角点坐标用标定参数全部转换为世界坐标,对比和标定之前世界坐标值之间的差异(图片比较大,放大展示一下图片四个角的值吧,一般图片四个角误差最大,中心误差小)

左上

 右上

左下

 

 右下

 

 

 以下是代码结构逻辑图

int main()
{
	
	clock_t start, end;
	start = clock();
	checkerboard cb;	

	//创建并生成标定板
	//cb.checkerboard_create(30,30,2, src1,true);

	//Mat src1 = imread("E:\\Project_Opencv\\Class_Blues\\Class_Blues\\pic\\Image_3.png", IMREAD_GRAYSCALE);	

	相机标定
	//CalibratedCheckerBoardInfo ccbi1 = cb.checkerboard_calibration(src1);
	将标定结果保存于本地文件
	//cb.CaliResultFileWrite("checkerboardresult.yml", ccbi1);
	
	//读取本地标定信息
	CalibratedCheckerBoardInfo ccbi2 ;	
	cb.CaliResultFileRead("checkerboardresult.yml", ccbi2);
	
	//从本地标定文件拿到原始标定板图片
	Mat img_src = ccbi2.Img_checkerboard;
	
	//从本地文件拿到标定后校正图片
	Mat img_cali = ccbi2.Img_Calibrated;

	//校正前后后灰度图片转彩色
	Mat img_cali_color,img_src_color,img_src_color1;

	cvtColor(img_cali, img_cali_color,COLOR_GRAY2BGR);
	cvtColor(img_src, img_src_color, COLOR_GRAY2BGR);
	cvtColor(img_src, img_src_color1, COLOR_GRAY2BGR);
	//undistort(color_img, img_calib, ccbi2.cameraMatrix, ccbi2.distCoeffs);
	
	//定义世界坐标点
	vector<Point3d> worldpoints;
	for (int i = 10; i < 80; i++)
	{
		for (int j = -22; j < 70; j++)
		{
			Point3d temp;
			temp.x = i * 2;
			temp.y = j * 2;
			temp.z = 0;
			worldpoints.push_back(temp);
		}
	}
	//世界坐标转换到图片像素坐标
	struct CalibratedResultInfo caliInfo;
	caliInfo.cameraMatrix = ccbi2.cameraMatrix;
	caliInfo.distCoeffs = ccbi2.distCoeffs;
	caliInfo.rvecsMat = ccbi2.rvecsMat;
	caliInfo.tvecsMat = ccbi2.tvecsMat;
	vector<Point2d> pixel_points;
	cb.WorldPoints2PixelPoints(caliInfo, worldpoints, pixel_points);	
	
	//将世界坐标转换后的像素坐标画在图片上
	for (int i = 0; i < pixel_points.size(); i++)
	{
		drawMarker(img_cali_color, pixel_points[i],Scalar(0,255,0), MARKER_TILTED_CROSS,20,2,8);
		drawMarker(img_src_color, pixel_points[i], Scalar(0, 0, 255), MARKER_TILTED_CROSS, 20, 2, 8);		
	}

	//绘制识别到的棋盘格角点和重投影点
	for (int i = 0; i < ccbi2.Pixel_Points.size(); i++)
	{
		
		drawMarker(img_src_color1, ccbi2.Pixel_Points[i], Scalar(0, 255, 0), MARKER_SQUARE, 15, 2, 8);
		drawMarker(img_src_color1, ccbi2.Reprojected_Points[i], Scalar(255, 0, 0), MARKER_TILTED_CROSS, 20, 2, 8);
	}
	//像素坐标转世界坐标
	//定义图片上四个关键点的像素坐标
	Point2f P0 = Point2f(1299,705);
	Point2f P1 = Point2f(1880, 690);
	Point2f P2 = Point2f(1892, 1282);
	Point2f P3 = Point2f(1309, 1296);
	vector<Point2f> checkerboard_pixel_points;
	vector<Point3f> world_points;
	checkerboard_pixel_points.push_back(P0);
	checkerboard_pixel_points.push_back(P1);
	checkerboard_pixel_points.push_back(P2);
	checkerboard_pixel_points.push_back(P3);

	cb.PixelPoint2WorldPoint(ccbi2.cameraMatrix, ccbi2.rvecsMat, ccbi2.tvecsMat, checkerboard_pixel_points, world_points);
	//图片上画出像素转世界坐标位置
	Mat img_cali_color1;
	cvtColor(img_cali, img_cali_color1, COLOR_GRAY2BGR);
	for (int i = 0; i < world_points.size(); i++)
	{
		cv::circle(img_cali_color1, checkerboard_pixel_points[i], 8, Scalar(0, 255, 0), 2, 8);
		string temp_xy = format("X: %.2f Y:%.2f", world_points[i].x, world_points[i].y);
		putText(img_cali_color1, temp_xy, Point(int(checkerboard_pixel_points[i].x-50), int(checkerboard_pixel_points[i].y-30)), FONT_HERSHEY_SIMPLEX, 1.5, Scalar(255, 255, 0),2, 8, 0);
	}
	imwrite("image_point.png", img_src_color1);
	end = clock();		//程序结束用时
	double endtime = (double)(end - start) / CLOCKS_PER_SEC;
	cout << "Total time:" << endtime * 1000 << "ms" << endl;	//ms为单位
	imwrite("calibcheck.png", img_cali_color);
	imwrite("uncalibcheck.png", img_src_color);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

GitHub 加速计划 / opencv31 / opencv
77.38 K
55.71 K
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:2 个月前 )
c3747a68 Added Universal Windows Package build to CI. 5 天前
9b635da5 - 5 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐