【问题标题】:opencv stereo calibration resultopencv立体校准结果
【发布时间】:2017-10-18 02:44:02
【问题描述】:

好像我有两个网络摄像头,标记为cam1,cam2。我想校准它们以获得它们之间的转换。

我使用cv::stereoCalibrate()进行校准。

我得到cam1cam2的转换后,标记为R,T。我想检查校准结果的准确性。

所以我用cam1cam2拍了一张棋盘的照片,标记为pic1,pic2。我得到了cam1的外在参数cv::solvePnP()。我画了cam1 的世界坐标系由cv::projectPoints()pic1 中。

然后,我认为cam2的旋转矩阵=cam1的旋转矩阵*R。而cam2的平移矩阵=cam1的平移矩阵+T

我通过上面的思路计算了cam2的外在参数,并在pic2中通过cv::projectPoints()绘制了cam2的世界坐标系。

但是pic2的原点位置不对。

这是我使用的部分代码。

void check_res(const vector<string> &imgs_nm,const Mat &R,const Mat &T,const Mat &cam_c,const Mat &cam_h,const Mat &dist_c,const Mat &dist_h)
{
    int imgs_cnt=imgs_nm.size()/2;
    vector<Point3f> obj_pts;
    for(int i=0;i<boardDimensions.height;i++)
        for(int j=0;j<boardDimensions.width;j++)
            obj_pts.push_back(Point3f(i*CHESS_LEN,j*CHESS_LEN,0.f));
    for(int i=0;i<imgs_cnt;i++)
    {
        vector<Point2f> c_cners,h_cners;
        Mat imgc_gray,imgh_gray;
        Mat imgc=imread(imgs_nm[i*2],1);
        Mat imgc_rz=imgc.clone();

        bool c_found,h_found;
        c_found=HasChessBoard(imgc_rz,imgc_gray,c_cners);
        if(c_found)
            cv::cornerSubPix(imgc_gray, c_cners, cv::Size(11, 11), cv::Size(-1, -1),cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
        Mat imgh=imread(imgs_nm[i*2+1],1);
        h_found=HasChessBoard(imgh,imgh_gray,h_cners);
        if(h_found)
            cv::cornerSubPix(imgh_gray, h_cners, cv::Size(11, 11), cv::Size(-1, -1),cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
        Mat rvec_c,rvec_h,tvec_c,tvec_h;
        cv::solvePnP(obj_pts,c_cners,cam_c,dist_c,rvec_c,tvec_c);
        cv::solvePnP(obj_pts,h_cners,cam_h,dist_h,rvec_h,tvec_h);
        Mat rrvec_c,rrvec_h;
        cv::Rodrigues(rvec_c,rrvec_c);
        cv::Rodrigues(rvec_h,rrvec_h);
        Mat r1=rrvec_c*R;
        Mat t1=tvec_c+T;

        Mat img1=imgh.clone();
        draw_chess(imgh,rrvec_h,tvec_h,cam_h,dist_h);
        imshow("pic1",imgh);
        draw_chess(img1,r1,t1,cam_h,dist_h);
        imshow("pic2",img1);


        char resc=waitKey(0);
        if(resc=='q')
            exit(1);

    }
}

以下是我使用opencv中的样本测试的结果。

我不认为这是低校准精度,因为我使用opencv 的样本,而cv::stereoCalibrate() 返回的 rms 小于 1 像素。

感谢任何建议。 谢谢!

【问题讨论】:

    标签: c++ opencv camera-calibration stereo-3d


    【解决方案1】:

    公式是:

    • 相机 1 的姿势(在齐次矩阵中):

    • 从相机 1 到相机 2 的均匀变换:

    • 相机 2 的姿势:

    【讨论】:

    • 我已经用你的答案试了一下,结果显示几乎在同一位置。非常感谢!
    • 但是我虽然cam2的姿势=cam1的姿势* [ R | T ].Mark cam1的姿势=[ R1 | T1 ],cam2的姿势=@987654333 @,它们之间的变换=[ R | T ].世界坐标系的原点*[ R1 | T1 ]=cam1的相机坐标系的原点。然后我们将它与[ R | T ]相乘,所以我们将点转换为cam2' s坐标系的原点。不知道我错在哪里,请告诉我。
    • camera1帧中表示的点:X_c1 = (R_c1 | T_c1) . X_w;两个摄像头之间的转换:X_c2 = (c2_R_c1 | c2_T_c1) . X_c1;在camera2帧中表示的点:X_c2 = (c2_R_c1 | c2_T_c1) . (R_c1 | T_c1) . X_w剩下的就是矩阵乘法了。
    【解决方案2】:

    为了检查立体校准的准确性,我会考虑另一种方法:

    1. 使用函数stereoRectify获取相机的整流变换。使用从stereoCalibrate 获得的平移和旋转矩阵。
    2. 对每个摄像机执行一次initUndistortRectifyMap。使用
    3. 将您得到的结果用于remap 两个摄像头的图像。

    如果您的校准顺利,输出图像应该被校正且不失真。

    【讨论】:

    • 是的,您是对的。opencv 的示例代码使用与您相同的方法。两个摄像头之间的 R,T 来自您提到的方法。但是结果图像显示我可能犯了一些我不知道的错误。
    • 对不起,那我一定误解了你的问题。很高兴看到其他方法有效!
    • 没关系,答案可能对其他人有所帮助。感谢您的分享!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-12
    • 1970-01-01
    • 2014-07-30
    • 2015-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多