特征匹配——误匹配剔除

暴力匹配

暴力匹配是指依次查找(穷举搜索)第一组中每个描述符与第二组中哪个描述符最接近。当然初始的暴力匹配得到的误匹配很多。我们可以通过交叉匹配过滤的方法对误匹配进行一定程度的剔除。

这种技术的思想是用查询集来匹配训练描述符,反之亦然。只返回在这两个匹配中同时出现的匹配。当有足够多的匹配时,这种技术在离群值数目极少的情况下通常会产生最佳效果。

在cv::BFMatcher类中可进行交叉匹配。为了能进行交叉检测实验,要创建cv::BFMatcher类的实例,需将构造函数的第二个参数设置为true:

cv::BFMatcher matcher2( NORM_HAMMING, true);

如果不设置第二个参数,则是正常的暴力匹配算法。

代码1:

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace std;
using namespace cv;

int main( int argc, char** argv)
{
    if ( argc != 3 )
    {
        cout<<"usage: feature_extraction img1 img2"<<endl;
        return 1;
    }

    Mat img1 = imread( argv[1], CV_LOAD_IMAGE_COLOR );
    Mat img2 = imread( argv[2], CV_LOAD_IMAGE_COLOR );

    //
    std::vector<KeyPoint> keypoints_1, keypoints_2;
    Mat descriptors_1, descriptors_2;
    Ptr<ORB> orb = ORB::create( 500, 1.2f, 8, 31, 0, 2, ORB::HARRIS_SCORE,31,20 );

    //
    orb->detect(img1, keypoints_1);
    orb->detect(img2, keypoints_2);

    //
    orb->compute(img1, keypoints_1, descriptors_1);
    orb->compute(img2, keypoints_2, descriptors_2);

    //
    BFMatcher matcher1( NORM_HAMMING );
    vector<DMatch> matches1;
    matcher1.match(descriptors_1, descriptors_2, matches1);

    //cv::Ptr<cv::DescriptorMatcher> matcher(new cv::BFMatcher(cv::NORM HAMMING, true));    //use in opencv2.x
    BFMatcher matcher2( NORM_HAMMING, true);
    vector<DMatch> matches2;
    matcher2.match(descriptors_1, descriptors_2, matches2);

    Mat img_match1;
    Mat img_match2;
    drawMatches(img1, keypoints_1, img2, keypoints_2, matches1, img_match1 );
    drawMatches(img1, keypoints_1, img2, keypoints_2, matches2, img_match2 );

    imshow("BFMatcher", img_match1);
    imshow("jiao cha match", img_match2);

    waitKey(0);

    return 0;
}

比率测试

对于误匹配的剔除还可以通过比率测试的方法来解决。可用KNN匹配,最初的K为2,即对每个匹配返回两个最近邻描述符。仅当第一个匹配与第二个匹配之间的距离比率足够大时(比率的阈值通常为2左右),才认为这是一个匹配。

此函数有三个输入,Mat& query, Mat& train, vector<DMatch>& matches

分别是要匹配的两幅图像的描述子,和匹配

比率测试的阈值设置为0.6

扫描二维码关注公众号,回复: 2559504 查看本文章

代码2:

void match_features(Mat& query, Mat& train, vector<DMatch>& matches)
{
    vector<vector<DMatch>> knn_matches;
    BFMatcher matcher(NORM_HAMMING);
    matcher.knnMatch(query, train, knn_matches, 2);

    //?????Ratio Test????ƥ??ľ??
    float min_dist = FLT_MAX;
    for (int r = 0; r < knn_matches.size(); ++r)
    {
        //Ratio Test
        if (knn_matches[r][0].distance > 0.6*knn_matches[r][1].distance)
            continue;

        float dist = knn_matches[r][0].distance;
        if (dist < min_dist) min_dist = dist;
    }

    matches.clear();
    for (size_t r = 0; r < knn_matches.size(); ++r)
    {
        //???????Ratio Test?ĵ?ƥ????????
        if (
            knn_matches[r][0].distance > 0.6*knn_matches[r][1].distance ||
            knn_matches[r][0].distance > 5 * max(min_dist, 10.0f)
            )
            continue;

        //????????
        matches.push_back(knn_matches[r][0]);
    }
}

基本矩阵F估计

cv::findFundamentalMat函数,函数的原型为:

Mat cv::findFundamentalMat     (     InputArray      points1,
        InputArray      points2,
        int      method = FM_RANSAC,
        double      ransacReprojThreshold = 3.,
        double      confidence = 0.99,
        OutputArray      mask = noArray() 
    )

通过两张图像的对应点来计算基本矩阵F。

Parameters

points1 Array of N points from the first image. The point coordinates should be floating-point (single or double precision).
points2 Array of the second image points of the same size and format as points1 .
method Method for computing a fundamental matrix.
  • CV_FM_7POINT for a 7-point algorithm. N=7
  • CV_FM_8POINT for an 8-point algorithm. N≥8
  • CV_FM_RANSAC for the RANSAC algorithm. N≥8
  • CV_FM_LMEDS for the LMedS algorithm. N≥8
ransacReprojThreshold Parameter used only for RANSAC. It is the maximum distance from a point to an epipolar line in pixels, beyond which the point is considered an outlier and is not used for computing the final fundamental matrix. It can be set to something like 1-3, depending on the accuracy of the point localization, image resolution, and the image noise.
confidence Parameter used for the RANSAC and LMedS methods only. It specifies a desirable level of confidence (probability) that the estimated matrix is correct.
mask The epipolar geometry is described by the following equation:

 

vector<Point2f> points1;
    vector<Point2f> points2;
    KeyPointsToPoints(keypoints_1, keypoints_2, points1, points2, matches1);
    

    //compute F
    Mat mask;
    vector<uchar> status(keypoints_1.size());
    Mat F = findFundamentalMat(points1, points2, FM_RANSAC, 3, 0.99, status);

    vector<DMatch> new_matches;
    cout << "F keeping " << countNonZero(status) << " / " << status.size() << endl;  
    for (unsigned int i = 0; i < status.size(); i++)
    {
        if (status[i])
        {


            if (matches1.size() <= 0)
            {
                new_matches.push_back(DMatch(matches1[i].queryIdx,matches1[i].trainIdx,matches1[i].distance));
            }
            else
            {
                new_matches.push_back(matches1[i]);
            }
        }
    }

    cout << matches1.size() << " matches before, " << new_matches.size() << " new matches after Fundamental Matrix\n";

猜你喜欢

转载自blog.csdn.net/weixin_41284198/article/details/81210323