OpenCV stereoCalibrate返回高RMS误差

vhipe2zx  于 2023-03-13  发布在  其他
关注(0)|答案(5)|浏览(353)

我在使用OpenCV计算立体声对的校正时遇到了一些问题:stereoCalibrate返回一个高rms错误,我得到了错误的校正对。我尝试了我的校正程序和opencv提供的stereo_calib.cpp。它们都返回类似的rms错误。另外,我用opencv/sample/cpp中的样本立体对运行了我的程序,我得到了正确校正的图像。所以我相信问题出在我拍摄立体照片的方式上,有可能吗?
我使用HTC Evo 3D(一款3D智能手机)的立体摄像头拍摄棋盘图案。我试图改变用作输入的图片数量和设置,但我得到的最小立体校准rms约为1. 5,校正后的图像完全错误。
有什么“建议”的方法来拍摄一组照片进行校准吗?谢谢,安德里亚

ohfgkhjo

ohfgkhjo1#

检查检测到的棋盘图案对(例如drawChessboardCorners)。在某些情况下,两幅图像中的点的顺序不同(见图;在顶部图像中,图案从右到左识别,在底部图像中,图案从左到右识别)。如果是这种情况,则点不再彼此对应。这导致stereoCalibrate中的高平均重投影误差。当使用calibrateCamera单独检查每个摄像机的图像时,对于本征函数,rms可能同时非常低,因为立体图像中的不同顺序在这里并不重要。

我通过检查找到的棋盘图案并删除以不同顺序检测到图案的图像对来解决这个问题。在我的例子中,这将rms从15(只有一个或几个错误的图像对)提高到小于1。在图像对经常损坏或使用更高分辨率的图像(像素更多)的情况下,我猜误差会更高。
另一个解决方案是使用ArUco和ChArUco模式,其中的顺序不应该是模糊的,但是我还没有测试过这种方法。

vybvopom

vybvopom2#

查看这里的常见错误指南,看看你是否犯过这些常见错误中的任何一个。
http://www.cvlibs.net/software/calibration/mistakes.php
此外,在校准立体摄影机时,您可能希望首先单独校准每个摄影机,然后根据其预先估计的摄影机矩阵将其作为立体对进行校准。
另一个替代工具箱,以及cvlibs(上面的链接),在这里:
http://www.vision.caltech.edu/bouguetj/calib_doc/
干杯

1rhkuytd

1rhkuytd3#

我拍摄了9张12x18角棋盘的校准图片,禁止鱼眼镜头k3=0,并将找到的角细化到子像素位置。在分辨率为640x480时,最小误差约为0.2。我建议在opencv文档中查找cornerSubpix()、TermCritiria和stereocalibrate()的标志。代码如下所示:

namedWindow( "Webcaml", CV_WINDOW_AUTOSIZE );
namedWindow( "Webcamr", CV_WINDOW_AUTOSIZE );
int successes=0;
int n_boards=9;
while(successes<n_boards)
{
    video_l.read( frame_l );
    video_r.read( frame_r );
    if( framenumber++ % board_dt == 0 && framenumber != 0)
    {
        bool patternfoundl = findChessboardCorners( frame_l, Size( board_w, board_h ), corners_l, CV_CALIB_CB_FILTER_QUADS + CV_CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_FAST_CHECK );
        bool patternfoundr = findChessboardCorners( frame_r, Size( board_w, board_h ), corners_r, CV_CALIB_CB_FILTER_QUADS + CV_CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_FAST_CHECK );
        if(patternfoundl && patternfoundr)
        {
            cvtColor(frame_l,frame_l_grey,CV_RGB2GRAY);
            cvtColor(frame_r,frame_r_grey,CV_RGB2GRAY);
            cornerSubPix(frame_l_grey,corners_l,Size(6,6),Size(-1,-1),TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,50000000000,0.0000000000001));
            cornerSubPix(frame_r_grey,corners_r,Size(6,6),Size(-1,-1),TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,50000000000,0.0000000000001));
        }
        drawChessboardCorners( frame_l, Size( board_w, board_h ), corners_l, patternfoundl );
        drawChessboardCorners( frame_r, Size( board_w, board_h ), corners_r, patternfoundr );
        imshow( "Webcaml", frame_l );
        imshow( "Webcamr", frame_r );
        if( corners_l.size() == (board_w*board_h) && corners_r.size() == (board_w*board_h) )
        {
            cornervector_l.push_back( corners_l );
            cornervector_r.push_back( corners_r );
            point3dvector.push_back( point3d );
            successes++;
            int c = cvWaitKey( 1000 );
        }
    }
    else
    {
        imshow( "Webcaml", frame_l);
        imshow( "Webcamr", frame_r);
    }
    char c = cvWaitKey( 1 );
    if( c == 27 )break;
}
destroyAllWindows();
rms_l = calibrateCamera( point3dvector, cornervector_l, Size( video_r.get( CV_CAP_PROP_FRAME_WIDTH ), video_r.get( CV_CAP_PROP_FRAME_HEIGHT )),
                        intrinsics_l, distortion_l, rvecs_l, tvecs_l, CV_CALIB_FIX_K3 , cvTermCriteria( CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,150000000000000000,DBL_EPSILON ) );
rms_r = calibrateCamera( point3dvector, cornervector_r, Size( video_r.get( CV_CAP_PROP_FRAME_WIDTH ), video_r.get( CV_CAP_PROP_FRAME_HEIGHT )),
                        intrinsics_r, distortion_r, rvecs_r, tvecs_r, CV_CALIB_FIX_K3 , cvTermCriteria( CV_TERMCRIT_ITER+CV_TERMCRIT_EPS,150000000000000000,DBL_EPSILON ) );
cout << "intrinsic_l       = " << endl << format(intrinsics_l,"C"     ) << endl << endl;
cout << "intrinsic_r       = " << endl << format(intrinsics_r,"C"     ) << endl << endl;
cout << "distortion_l        = " << endl << format(distortion_l,"C"     ) << endl << endl;
cout << "distortion_r        = " << endl << format(distortion_r,"C"     ) << endl << endl;
cout << "tvecs_l      = " << endl << format(tvecs_l[0],"C"     ) << endl << endl;
cout << "rvecs_l      = " << endl << format(rvecs_l[0],"C"     ) << endl << endl;
double rms_stereo = stereoCalibrate( point3dvector, cornervector_l, cornervector_r, intrinsics_l, distortion_l, intrinsics_r, distortion_r,
                                    Size( video_r.get( CV_CAP_PROP_FRAME_WIDTH ),video_r.get( CV_CAP_PROP_FRAME_HEIGHT )), R, T, E, F, 
                                    TermCriteria( TermCriteria::COUNT+TermCriteria::EPS, 150000000000000000,DBL_EPSILON ), CV_CALIB_FIX_K3+CV_CALIB_FIX_INTRINSIC);
Rodrigues(R, R);
cout << "R       = " << endl << format(R,"C"     ) << endl << endl;
cout << "T        = " << endl << format(T,"C"     ) << endl << endl;
cout << "E       = " << endl << format(E,"C"     ) << endl << endl;
cout << "F        = " << endl << format(F,"C"     ) << endl << endl;
cout << "RMS Fehler l,r,stereo: " << rms_l << rms_r << rms_stereo << endl;
stereoRectify( intrinsics_l, distortion_l, intrinsics_r, distortion_r, Size( video_r.get( CV_CAP_PROP_FRAME_WIDTH ),video_r.get( CV_CAP_PROP_FRAME_HEIGHT )), R, T,
                rectify_l, rectify_r, projection_l, projection_r, Q);
rjee0c15

rjee0c154#

Hi做了一些更多的研究,在OpenCV Answer上找到了这个帖子。手机似乎在调整固有矩阵,不断改变焦点,我无法进行很好的校准。

wvyml7n5

wvyml7n55#

在我的例子中,我从两个视频源中提取帧,我认为它们是同步的-然而,它们不是。在修复同步问题后,我的RMSE从超过20像素下降到~1像素。

相关问题