【问题标题】:How to match keypoints in SIFT ?如何匹配 SIFT 中的关键点?
【发布时间】:2016-03-16 08:22:58
【问题描述】:

如何匹配 SIFT 中的关键点?

我为图像中的每个关键点计算了 128 个大小的向量。

设,I1 为原始图像,I2 为 45 度旋转图像。

我得到了 I1 的 130 个关键点和 I2 的 104 个关键点。

即128x130 和 128x104。

我计算了 I1 的一个关键点和 I2 的所有关键点之间的欧式距离。所以我又得到了大小为 128x104 的欧几里得距离矩阵。

现在我需要从这个欧几里得距离矩阵中选择最近的关键点。如何从 128 x 104 大小的矩阵中选择最小距离 128 大小的向量?

【问题讨论】:

  • 通常人们使用 RANSAC 来匹配关键点。选择最小距离关键点是不够的,还需要找到/匹配相邻关键点的模式。它不是那么简单,并且涉及聚类分析和匹配...... RANSAC 统计地进行。由于我对该主题的了解非常有限,因此无法提供进一步的帮助。但至少你知道用谷歌搜索什么......

标签: image-processing


【解决方案1】:

由于您已经计算了关键点之间的距离,为了匹配它们,按照欧几里得距离的升序对它们进行排序,并且只考虑那些是常数 *min_distance 的关键点 [即:选择排序距离] 作为“良好匹配”。

OpenCV 中还有 BruteForceMatcher、KNNMatch 和 FlannBasedMatcher(网址如下) http://docs.opencv.org/2.4/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.html#feature-flann-matcher

http://docs.opencv.org/2.4/modules/features2d/doc/common_interfaces_of_descriptor_matchers.html#descriptormatcher-knnmatch

另外,看看这些问题和他们的回答。

1) Trying to match two images using sift in OpenCv, but too many matches

2)Efficient way for SIFT descriptor matching

为了完整起见,提供一些非常粗略的代码供大家参考。

If you have ;
class SIFTDemo
{
private:
    Mat image;
    vector<cv::KeyPoint> keypoints;
    Mat descriptors;
    Mat sift_output;
    vector<DMatch> matches;

public:
    SIFTDemo();
    ~SIFTDemo();
    SIFTDemo(Mat m);
    void extractSiftFeatures();
    vector <DMatch> FindMatchesEuclidian(SIFTDemo &m2);
};

Then one can have something like this;

void SIFTDemo::extractSiftFeatures()
{
    SIFT siftobject;
    siftobject.operator()(image, Mat(), keypoints, descriptors);
}

vector<DMatch> SIFTDemo::FindMatchesEuclidian(SIFTDemo &m2)
{
    // Calculate euclidian distance between keypoints to find best matching   pairs.
    // create two dimensional vector for storing euclidian distance
    vector< vector<float> > vec1, unsortedvec1;
    for (int i=0; i<this->keypoints.size(); i++)
    {
        vec1.push_back(vector<float>()); // Add an empty row
        unsortedvec1.push_back(vector<float>());
    }

    // create vector of DMatch for storing matxhes point
    vector<DMatch> matches1;
    DMatch dm1;

    // loop through keypoints1.size
    for (int i=0; i<this->keypoints.size(); i++)
    {
        // get 128 dimensions in a vector
        vector<float> k1;
        for(int x=0; x<128; x++)
        {
            k1.push_back((float)this->descriptors.at<float>(i,x));
        }

        // loop through keypoints2.size
        for (int j=0; j<m2.keypoints.size(); j++)
        {
            double temp=0;
            // calculate euclidian distance
            for(int x=0; x<128; x++)
            {
                temp += (pow((k1[x] - (float)m2.descriptors.at<float>(j,x)), 2.0));
            }
            vec1[i].push_back((float)sqrt(temp)); // store distance for each keypoints in image2
            unsortedvec1[i] = vec1[i];
        }
        sort(vec1[i].begin(),vec1[i].end()); // sort the vector distances to get shortest distance

        // find position of the shortest distance
        int pos = (int)(find(unsortedvec1[i].begin(), unsortedvec1[i].end(), vec1[i][0]) - unsortedvec1[i].begin());

        // assign that matchin feature to DMatch variable dm1
        dm1.queryIdx = i;
        dm1.trainIdx = pos;
        dm1.distance = vec1[i][0];
        matches1.push_back(dm1);
        this->matches.push_back(dm1);
        //cout << pos << endl;
    }

    // craete two dimensional vector for storing euclidian distance
    vector<vector<float>> vec2, unsortedvec2;
    for (int i=0; i<m2.keypoints.size(); i++)
    {
        vec2.push_back(vector<float>()); // Add an empty row
        unsortedvec2.push_back(vector<float>());
    }

    // create vector of DMatch for storing matxhes point
    vector<DMatch> matches2;
    DMatch dm2;
    // loop through keypoints2.size
    for (int i=0; i<m2.keypoints.size(); i++)
    {
        // get 128 dimensions in a vector
        vector<float> k1;
        for(int x=0; x<128; x++)
        {
            k1.push_back((float)m2.descriptors.at<float>(i,x));
        }

        // loop through keypoints1.size
        for (int j=0; j<this->keypoints.size(); j++)
        {
            double temp=0;
            // calculate euclidian distance
            for(int x=0; x<128; x++)
            {
                temp += (pow((k1[x] - (float)this->descriptors.at<float>(j,x)), 2.0));
            }
            vec2[i].push_back((float)sqrt(temp)); // store distance for each keypoints in image1
            unsortedvec2[i] = vec2[i];
        }
        sort(vec2[i].begin(),vec2[i].end()); // sort the vector distances to get shortest distance

        // find position of the shortest distance
        int pos = (int)(find(unsortedvec2[i].begin(), unsortedvec2[i].end(), vec2[i][0]) - unsortedvec2[i].begin());

        // assign that matchin feature to DMatch variable
        dm2.queryIdx = i;
        dm2.trainIdx = pos;
        dm2.distance = vec2[i][0];
        matches2.push_back(dm2);
        m2.matches.push_back(dm2);

        //cout << pos << endl;
    }

    // Ref : http://docs.opencv.org/2.4/doc/tutorials/features2d/feature_flann_matcher/feature_flann_matcher.html#feature-flann-matcher
    //-- Quick calculation of max and min distances between keypoints1
    double max_dist = 0;
    double min_dist = 500.0;
    for( int i = 0; i < matches1.size(); i++ )
    {
        double dist = matches1[i].distance;
        if( dist < min_dist ) min_dist = dist;
        if( dist > max_dist ) max_dist = dist;
    }

    // Draw only "good" matches1 (i.e. whose distance is less than 2*min_dist ) 
    vector<DMatch> good_matches1;
    for( int i = 0; i < matches1.size(); i++ )
    {
        if( matches1[i].distance <= 2*min_dist )
        {
            good_matches1.push_back( matches1[i]);
        }
    }

    // Quick calculation of max and min distances between keypoints2 but not used
    for( int i = 0; i < matches2.size(); i++ )
    {
        double dist = matches2[i].distance;
        if( dist < min_dist ) min_dist = dist;
        if( dist > max_dist ) max_dist = dist;
    }

    // Draw only "good" matches by comparing that (ft1 gives ft2) and (ft2 gives ft1)
    vector<DMatch> good_matches;
    for(unsigned int i=0; i<good_matches1.size(); i++)
    {
        // check ft1=ft2 and ft2=ft1
        if(good_matches1[i].queryIdx == matches2[good_matches1[i].trainIdx].trainIdx)
            good_matches.push_back(good_matches1[i]);
    }
    return good_matches;
}

最后,正如评论中提到的,还请查看 RANSAC 来执行此操作。不要深入研究,不要让答案更长,但你可以在网上和 SO 上找到资源。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-06-18
    • 2015-03-24
    • 2011-10-21
    • 1970-01-01
    • 1970-01-01
    • 2019-11-05
    • 1970-01-01
    • 2018-03-18
    相关资源
    最近更新 更多