OpenCV stereoCalibrate返回高RMS错误

时间:2014-05-23 10:13:51

标签: opencv stereo-3d

在使用OpenCV计算立体声对的整流时,我遇到了一些问题:stereoCalibrate返回高均方根误差,我获得了不良的整流对。 我尝试了我的整改程序和opencv提供的stereo_calib.cpp。它们都返回类似的rms错误。另外,我使用opencv / sample / cpp中的示例立体声对运行我的程序,我得到了正确的纠正图像。所以我认为问题在于我采用立体图像的方式,是否可能?

我使用Htc Evo 3D(3D智能手机)的立体相机拍摄棋盘图案。我试图更改用作输入的数字和图片集,但我得到的最小的stereoCalibration rms大约为1.5,经过校正的图像完全错误。
有什么"建议"采取一组图片进行校准的方法? 谢谢,Andrea

4 个答案:

答案 0 :(得分:1)

我拍摄了12张18角球棋盘的9张校准照片,禁止鱼眼镜头k3 = 0,并将找到的角点细化为亚像素位置。在640x480分辨率下,最小实现误差为0.2。我建议在opencv doc中查找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);

答案 1 :(得分:0)

查看此处的常见错误指南,看看您是否发现了这些常见错误。

http://www.cvlibs.net/software/calibration/mistakes.php

另外,在校准立体相机时,您可能需要首先校准它上面的每个相机,然后根据预先估计的相机矩阵将它们校准为立体声相机。

另一个替代工具箱,以及cvlibs(上面的链接),在这里:

http://www.vision.caltech.edu/bouguetj/calib_doc/

欢呼声

答案 2 :(得分:0)

您做了更多研究,发现this post on OpenCV answer。 手机似乎调整内在矩阵连续改变焦点,我无法做出良好的校准。

答案 3 :(得分:0)

检查检测到的棋盘图案对(例如,使用drawChessboardCorners)。在某些情况下,两个图像中点的顺序不同(请参见图;在顶部图像中,从右到左识别出图案,在底部图像中从左到右识别出图案)。在这种情况下,这些点不再相互对应。这导致stereoCalibrate中的平均投影误差较高。当用calibrateCamera分别检查每个摄像机的图像时,内部特性的均方根值可能同时很低,因为立体图像中的不同顺序在这里无关紧要。

enter image description here

我通过检查找到的棋盘图案并移除了以不同顺序检测到图案的图像对来解决了这个问题。在我的情况下,这将均方根值从15(仅一对或几对错误)提高到小于1。如果对更频繁地损坏,或者使用更高分辨率的图像(具有更多像素)时,误差会更高,我猜。

另一种解决方案可能是使用ArUco和ChArUco模式,这些模式的顺序不应该模棱两可,但我尚未测试这种方法。