1

我正在尝试计算 2 张图像的基本矩阵(同一台相机拍摄的静态场景的不同照片)。

我使用findFundamentalMat计算了它,并使用结果来计算其他矩阵(基本、旋转等)。结果显然是错误的。因此,我试图确定计算出的基本矩阵的准确性。

使用极线约束方程,我计算了基本矩阵误差。错误非常高(比如几百个)。我不知道我的代码有什么问题。我真的很感激任何帮助。特别是:在基本矩阵计算中我有什么遗漏吗?我计算错误的方式对吗?

此外,我以非常不同的匹配数运行代码。通常有很多异常值。例如,在超过 80 个匹配项的情况下,只有 10 个内点。

Mat img_1 = imread( "imgl.jpg", CV_LOAD_IMAGE_GRAYSCALE );
Mat img_2 = imread( "imgr.jpg", CV_LOAD_IMAGE_GRAYSCALE );
if( !img_1.data || !img_2.data )
{ return -1; }

//-- Step 1: Detect the keypoints using SURF Detector

int minHessian = 1000;
SurfFeatureDetector detector( minHessian );
std::vector<KeyPoint> keypoints_1, keypoints_2;

detector.detect( img_1, keypoints_1 );
detector.detect( img_2, keypoints_2 );

//-- Step 2: Calculate descriptors (feature vectors)

SurfDescriptorExtractor extractor;
Mat descriptors_1, descriptors_2;
extractor.compute( img_1, keypoints_1, descriptors_1 );
extractor.compute( img_2, keypoints_2, descriptors_2 );

//-- Step 3: Matching descriptor vectors with a brute force matcher

BFMatcher matcher(NORM_L1, true);
std::vector< DMatch > matches;
matcher.match( descriptors_1, descriptors_2, matches );

vector<Point2f>imgpts1,imgpts2;
for( unsigned int i = 0; i<matches.size(); i++ )
{
    // queryIdx is the "left" image
    imgpts1.push_back(keypoints_1[matches[i].queryIdx].pt);
    // trainIdx is the "right" image
    imgpts2.push_back(keypoints_2[matches[i].trainIdx].pt);
}

//-- Step 4: Calculate Fundamental matrix

Mat f_mask;
Mat F =  findFundamentalMat  (imgpts1, imgpts2, FM_RANSAC, 0.5, 0.99, f_mask);

//-- Step 5: Calculate Fundamental matrix error

//Camera intrinsics
double data[] = {1189.46 , 0.0, 805.49,
                0.0, 1191.78, 597.44,
                0.0, 0.0, 1.0};
Mat K(3, 3, CV_64F, data);
//Camera distortion parameters
double dist[] = { -0.03432, 0.05332, -0.00347, 0.00106, 0.00000};
Mat D(1, 5, CV_64F, dist);

//working with undistorted points
vector<Point2f> undistorted_1,undistorted_2;
vector<Point3f> line_1, line_2;
undistortPoints(imgpts1,undistorted_1,K,D);
undistortPoints(imgpts2,undistorted_2,K,D);
computeCorrespondEpilines(undistorted_1,1,F,line_1);
computeCorrespondEpilines(undistorted_2,2,F,line_2);

double f_err=0.0;
double fx,fy,cx,cy;
fx=K.at<double>(0,0);fy=K.at<double>(1,1);cx=K.at<double>(0,2);cy=K.at<double>(1,2);
Point2f pt1, pt2;
int inliers=0;
//calculation of fundamental matrix error for inliers
for (int i=0; i<f_mask.size().height; i++)
    if (f_mask.at<char>(i)==1)
    {
        inliers++;
        //calculate non-normalized values
        pt1.x = undistorted_1[i].x * fx + cx;
        pt1.y = undistorted_1[i].y * fy + cy;
        pt2.x = undistorted_2[i].x * fx + cx;
        pt2.y = undistorted_2[i].y * fy + cy;
        f_err += = fabs(pt1.x*line_2[i].x +
                pt1.y*line_2[i].y + line_2[i].z)
                + fabs(pt2.x*line_1[i].x +
                pt2.y*line_1[i].y + line_1[i].z);
    }

double AvrErr = f_err/inliers;
4

2 回答 2

0

我认为问题在于您仅基于蛮力匹配器计算了基本矩阵,您应该对这些对应点进行更多优化,例如比率测试和对称测试。我建议你准备好第 233 页,来自《OpenCV2 计算机视觉应用程序编程手册》第 9 章。它解释得很好!

于 2014-02-18T12:23:57.007 回答
0
  • 鉴于我们得到了固有矩阵 K 和失真矩阵 D,我们应该在将图像点馈送到 findFundamentalMat 之前对图像点进行不失真处理,并且以后应该对未失真的图像坐标进行处理(即用于计算误差)。我发现这个简单的改变将任何图像点对的最大误差从 176.0f 降低到 0.2,并且内点数从 18 个增加到 77 个。

  • 我还尝试将其之前的未失真图像点标准化为 findFundamentalMat,这将任何图像点对的最大误差降低到几乎为零,尽管它不会进一步增加内点的数量。

    const float kEpsilon = 1.0e-6f;
    
    float sampsonError(const Mat &dblFMat, const Point2f &pt1, const Point2f &pt2)
    {
    
    
        Mat m_pt1(3, 1 , CV_64FC1 );//m_pt1(pt1);
        Mat m_pt2(3, 1 , CV_64FC1 );
        m_pt1.at<double>(0,0) = pt1.x; m_pt1.at<double>(1,0) = pt1.y; m_pt1.at<double>(2,0) = 1.0f;
        m_pt2.at<double>(0,0) = pt2.x; m_pt2.at<double>(1,0) = pt2.y; m_pt2.at<double>(2,0) = 1.0f;
    
        assert(dblFMat.rows==3 && dblFMat.cols==3);
        assert(m_pt1.rows==3 && m_pt1.cols==1);
        assert(m_pt2.rows==3 && m_pt2.cols==1);
        Mat dblFMatT(dblFMat.t());
        Mat dblFMatp1=(dblFMat * m_pt1);
        Mat dblFMatTp2=(dblFMatT * m_pt2);
        assert(dblFMatp1.rows==3 && dblFMatp1.cols==1);
        assert(dblFMatTp2.rows==3 && dblFMatTp2.cols==1);
    
        Mat numerMat=m_pt2.t() * dblFMatp1;
        double numer=numerMat.at<double>(0,0);
        if (numer < kEpsilon)
        {
            return 0;
    
        } else {
            double denom=dblFMatp1.at<double>(0,0) + dblFMatp1.at<double>(1,0) +  dblFMatTp2.at<double>(0,0) + dblFMatTp2.at<double>(1,0);
            double ret=(numer*numer)/denom;
            return (numer*numer)/denom;
        }
    }
    
    #define UNDISTORT_IMG_PTS 1
    #define NORMALIZE_IMG_PTS 1
    
    int filter_imgpts_pairs_with_epipolar_constraint(
        const vector<Point2f> &raw_imgpts_1,
        const vector<Point2f> &raw_imgpts_2,
        int imgW,
        int imgH
    )
    {
    
    #if UNDISTORT_IMG_PTS
        //Camera intrinsics
        double data[] = {1189.46 , 0.0, 805.49,
                        0.0, 1191.78, 597.44,
                        0.0, 0.0, 1.0};
        Mat K(3, 3, CV_64F, data);
        //Camera distortion parameters
        double dist[] = { -0.03432, 0.05332, -0.00347, 0.00106, 0.00000};
        Mat D(1, 5, CV_64F, dist);
    
    
        //working with undistorted points
        vector<Point2f> unnormalized_imgpts_1,unnormalized_imgpts_2;
        undistortPoints(raw_imgpts_1,unnormalized_imgpts_1,K,D);
        undistortPoints(raw_imgpts_2,unnormalized_imgpts_2,K,D);
    
    #else
        vector<Point2f> unnormalized_imgpts_1(raw_imgpts_1);
        vector<Point2f> unnormalized_imgpts_2(raw_imgpts_2);
    #endif
    
    
    
    #if NORMALIZE_IMG_PTS
    
        float c_col=imgW/2.0f;
        float c_row=imgH/2.0f;
        float multiply_factor= 2.0f/(imgW+imgH);
    
        vector<Point2f> final_imgpts_1(unnormalized_imgpts_1);
        vector<Point2f> final_imgpts_2(unnormalized_imgpts_2);
    
        for( auto iit=final_imgpts_1.begin(); iit != final_imgpts_1.end(); ++ iit)
        {
            Point2f &imgpt(*iit);
            imgpt.x=(imgpt.x - c_col)*multiply_factor;
            imgpt.y=(imgpt.y - c_row)*multiply_factor;
        }
        for( auto iit=final_imgpts_2.begin(); iit != final_imgpts_2.end(); ++ iit)
        {
            Point2f &imgpt(*iit);
            imgpt.x=(imgpt.x - c_col)*multiply_factor;
            imgpt.y=(imgpt.y - c_row)*multiply_factor;
        }
    
    #else
    
        vector<Point2f> final_imgpts_1(unnormalized_imgpts_1);
        vector<Point2f> final_imgpts_2(unnormalized_imgpts_2);
    #endif
    
        int algorithm=FM_RANSAC;
        //int algorithm=FM_LMEDS;
    
    
        vector<uchar>status;
    
        Mat F =  findFundamentalMat  (final_imgpts_1, final_imgpts_2, algorithm, 0.5, 0.99, status);
        int n_inliners=std::accumulate(status.begin(), status.end(), 0);
    
    
    
        assert(final_imgpts_1.size() == final_imgpts_2.size());
        vector<float> serr;
        for( unsigned int i = 0; i< final_imgpts_1.size(); i++ )
        {
            const Point2f &p_1(final_imgpts_1[i]);
            const Point2f &p_2(final_imgpts_2[i]);
            float err= sampsonError(F, p_1, p_2);
            serr.push_back(err);
        }
        float max_serr=*max_element(serr.begin(), serr.end());
        cout << "found " << raw_imgpts_1.size() << "matches " << endl;
        cout << " and " << n_inliners << " inliners" << endl;
        cout << " max sampson err" << max_serr << endl;
        return 0;
    }
    
于 2018-05-28T19:11:24.793 回答