ChAruco板图像边缘角点无法插值,如何调整参数解决?
ChAruco板边缘角点插值异常的解决方法
问题背景
使用ChAruco板的核心优势之一是角点插值功能,能有效提升相机校准精度,但当前存在图像边缘角点无法正常插值的问题。
测试图像:
异常输出结果:
原使用代码:
cv::Ptr<cv::aruco::Dictionary> charuco_dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_50); cv::Ptr<cv::aruco::DetectorParameters> charuco_params = cv::aruco::DetectorParameters::create(); cv::Ptr<cv::aruco::CharucoBoard> board = cv::aruco::CharucoBoard::create(7, 5, 35.0 / 1000, 26.0 / 1000, charuco_dictionary); std::vector<int> image_ids, marker_ids; vector<vector<cv::Point2f>> image_point, marker_point, rejected; cv::Mat charuco_chess_corners, charuco_chess_corners_id; cv::Mat input = cv::imread("image.png", cv::IMREAD_ANYCOLOR); cv::flip(input, input, 1); cv::aruco::detectMarkers(input, charuco_dictionary, marker_point, marker_ids, charuco_params, rejected); cv::aruco::refineDetectedMarkers(input, board, marker_point, marker_ids, rejected); if (!marker_ids.empty()) { cv::aruco::interpolateCornersCharuco(marker_point, marker_ids, input, board, charuco_chess_corners, charuco_chess_corners_id, cv::noArray(), cv::noArray(), 0); } cv::Mat out_color; cv::cvtColor(input, out_color, cv::COLOR_GRAY2RGB); cv::aruco::drawDetectedCornersCharuco(out_color, charuco_chess_corners, charuco_chess_corners_id); cv::imshow("test", out_color); cv::waitKey(0); return 0;
解决方案
边缘角点插值失败的核心原因是默认参数对边缘标记点的检测阈值过高,以及插值时未启用边缘角点支持。可通过以下3个关键调整解决:
1. 调整标记点检测参数,提升边缘标记点检出率
修改DetectorParameters的参数,降低边缘标记点的检测门槛:
charuco_params->adaptiveThreshConstant = 7; // 降低自适应阈值常数,适配低对比度区域 charuco_params->minMarkerPerimeterRate = 0.02; // 允许识别被裁切的小尺寸边缘标记 charuco_params->maxMarkerPerimeterRate = 4.0; // 放宽最大周长限制 charuco_params->polygonalApproxAccuracyRate = 0.03; // 降低多边形近似精度,适配边缘变形的标记
2. 启用插值函数的边缘角点支持
interpolateCornersCharuco的最后一个参数minMarkers默认设为0时,仅被单个标记点包围的边缘角点不会被插值。将其改为1,允许这类边缘角点参与插值:
cv::aruco::interpolateCornersCharuco(marker_point, marker_ids, input, board, charuco_chess_corners, charuco_chess_corners_id, cv::noArray(), cv::noArray(), 1); // 修改minMarkers为1
3. 优化标记点精炼步骤
在refineDetectedMarkers中启用从候选的rejected标记中找回边缘有效点:
cv::aruco::refineDetectedMarkers(input, board, marker_point, marker_ids, rejected, cv::noArray(), cv::noArray(), charuco_params, true); // 最后一个参数设为true,启用rejected标记精炼
修改后的完整代码
cv::Ptr<cv::aruco::Dictionary> charuco_dictionary = cv::aruco::getPredefinedDictionary(cv::aruco::DICT_4X4_50); cv::Ptr<cv::aruco::DetectorParameters> charuco_params = cv::aruco::DetectorParameters::create(); // 调整检测参数 charuco_params->adaptiveThreshConstant = 7; charuco_params->minMarkerPerimeterRate = 0.02; charuco_params->maxMarkerPerimeterRate = 4.0; charuco_params->polygonalApproxAccuracyRate = 0.03; cv::Ptr<cv::aruco::CharucoBoard> board = cv::aruco::CharucoBoard::create(7, 5, 35.0 / 1000, 26.0 / 1000, charuco_dictionary); std::vector<int> image_ids, marker_ids; vector<vector<cv::Point2f>> image_point, marker_point, rejected; cv::Mat charuco_chess_corners, charuco_chess_corners_id; cv::Mat input = cv::imread("image.png", cv::IMREAD_ANYCOLOR); cv::flip(input, input, 1); cv::aruco::detectMarkers(input, charuco_dictionary, marker_point, marker_ids, charuco_params, rejected); // 优化精炼步骤 cv::aruco::refineDetectedMarkers(input, board, marker_point, marker_ids, rejected, cv::noArray(), cv::noArray(), charuco_params, true); if (!marker_ids.empty()) { // 启用边缘角点插值 cv::aruco::interpolateCornersCharuco(marker_point, marker_ids, input, board, charuco_chess_corners, charuco_chess_corners_id, cv::noArray(), cv::noArray(), 1); } cv::Mat out_color; cv::cvtColor(input, out_color, cv::COLOR_GRAY2RGB); cv::aruco::drawDetectedCornersCharuco(out_color, charuco_chess_corners, charuco_chess_corners_id); cv::imshow("test", out_color); cv::waitKey(0); return 0;
原理说明
- 降低检测参数阈值:让OpenCV能识别到被图像边缘裁切、对比度较低的标记点;
- 修改
minMarkers为1:ChAruco的边缘角点仅由单个标记点的两个角支撑,默认0要求至少两个标记点,因此无法插值; - 启用rejected标记精炼:从初始检测被排除的候选标记中找回边缘的有效标记,为插值提供更多支撑点。
内容的提问来源于stack exchange,提问作者Zhu Mengxi
相关产品推荐
相关产品推荐

