You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 10:15:01