使用cv::calibrateCamera()函数时出现运行时错误求助
解决OpenCV Charuco相机校准运行时错误
错误原因分析
- 校准标志使用不当:你设置了
CALIB_USE_INTRINSIC_GUESS | CALIB_FIX_PRINCIPAL_POINT,但未初始化cameraMatrix。CALIB_USE_INTRINSIC_GUESS要求必须提前给相机矩阵提供合理初始值,否则OpenCV内部矩阵运算会触发错误。 - 点集不匹配:你每次将完整Charuco板的3D点集合
objPoints加入allObjectPoints,但对应的图像点currentCharucoCorners只是当前帧检测到的部分角点,两者数量、索引完全不对应。正确做法是使用board.matchImagePoints生成的currentObjectPoints和currentImagePoints,这两个集合是一一对应的检测点对。 - 冗余检测器创建:循环内重复创建
ArucoDetector和CharucoDetector,虽不直接引发错误,但会降低性能,建议移到循环外初始化。
修复后的代码
#include <opencv2/opencv.hpp> #include <opencv2/calib3d.hpp> #include "opencv2/objdetect/aruco_detector.hpp" int main() { cv::VideoCapture inputVideo; inputVideo.open(0); if (!inputVideo.isOpened()) { std::cout << "Cannot open the web cam" << std::endl; return -1; } // 创建Charuco板 const cv::Size sizeCharuco(7,5); cv::aruco::CharucoBoard board = cv::aruco::CharucoBoard::CharucoBoard(sizeCharuco, 0.033, 0.011, cv::aruco::getPredefinedDictionary(cv::aruco::DICT_6X6_250)); cv::Size imageSize; std::vector<std::vector<cv::Point2f>> allImagePoints; std::vector<std::vector<cv::Point3f>> allObjectPoints; // 调整校准标志:无初始相机矩阵时,禁用CALIB_USE_INTRINSIC_GUESS int calibrationFlags = 0; // 若后续有初始矩阵,可恢复以下标志并初始化cameraMatrix // int calibrationFlags = cv::CALIB_FIX_PRINCIPAL_POINT; int counter = 0; // 检测器初始化移至循环外 cv::aruco::ArucoDetector arucoDetector(board.getDictionary(), cv::aruco::DetectorParameters()); cv::aruco::CharucoDetector charucoDetector(board); while (counter < 100) { counter++; cv::Mat image, imgCopy; inputVideo >> image; if (image.empty()) break; imageSize = image.size(); std::vector<std::vector<cv::Point2f>> currectMarkerCorners, rejectedImg; std::vector<int> currentMarkerIds; arucoDetector.detectMarkers(image, currectMarkerCorners, currentMarkerIds, rejectedImg); image.copyTo(imgCopy); if (!currentMarkerIds.empty()) { cv::aruco::drawDetectedMarkers(imgCopy, currectMarkerCorners, currentMarkerIds); std::vector<cv::Point2f> currentCharucoCorners; std::vector<int> currentCharucoIds; std::vector<cv::Point3f> currentObjectPoints; std::vector<cv::Point2f> currentImagePoints; charucoDetector.detectBoard(image, currentCharucoCorners, currentCharucoIds); board.matchImagePoints(currentCharucoCorners, currentCharucoIds, currentObjectPoints, currentImagePoints); if (!currentCharucoIds.empty()) { cv::aruco::drawDetectedCornersCharuco(image, currentCharucoCorners, currentCharucoIds); // 添加匹配后的点对,而非全量对象点 allObjectPoints.push_back(currentObjectPoints); allImagePoints.push_back(currentImagePoints); } } cv::imshow("out", image); cv::imshow("out2", imgCopy); char key = (char)cv::waitKey(30); if (key == 27) break; } cv::Mat cameraMatrix, distCoeffs; std::vector<cv::Mat> rvecs, tvecs; if (!allObjectPoints.empty() && !allImagePoints.empty()) { std::cout << imageSize << std::endl; // 若使用CALIB_USE_INTRINSIC_GUESS,需提前初始化cameraMatrix: // cameraMatrix = cv::Mat::eye(3, 3, CV_64F); // cameraMatrix.at<double>(0,0) = imageSize.width; // 初始fx猜测 // cameraMatrix.at<double>(1,1) = imageSize.width; // 初始fy猜测 // cameraMatrix.at<double>(0,2) = imageSize.width / 2.0; // cx // cameraMatrix.at<double>(1,2) = imageSize.height / 2.0; // cy double repError = cv::calibrateCamera(allObjectPoints, allImagePoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, calibrationFlags); std::cout << "Reprojection error: " << repError << std::endl; // 保存校准结果 cv::FileStorage fs("calibration.yml", cv::FileStorage::WRITE); fs << "cameraMatrix" << cameraMatrix; fs << "distCoeffs" << distCoeffs; fs.release(); } else { std::cout << "not possible to calibrate" << std::endl; } cv::destroyAllWindows(); return 0; }
额外注意事项
- 采集至少10-20张不同角度的Charuco板图像(覆盖相机视野不同区域),校准结果才会准确。
- 若需使用
CALIB_USE_INTRINSIC_GUESS,按代码注释方式初始化cameraMatrix,提供合理的内参初始值。 - 校准完成后可通过
cv::projectPoints验证重投影误差,确保结果可靠。
内容的提问来源于stack exchange,提问作者Beatrice Hammerschmidt
相关产品推荐
相关产品推荐

