如何匹配SIFT中的关键点?

时间:2016-03-11 07:55:07

标签: image-processing

如何匹配SIFT中的关键点?

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

让I1是原始图像,I2是45度旋转图像。

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

即。 128x130和128x104。

我计算了I1的一个关键点与I2的所有关键点之间的欧几里德距离。所以我得到了尺寸为128x104的欧几里德距离矩阵。

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

1 个答案:

答案 0 :(得分:1)

由于你已经计算了关键点之间的距离,为了匹配它们,按欧几里德距离的递增顺序对它们进行排序,并且只考虑那些常数* min_distance的关键点[即:在某些%年龄选择已排序的距离]为'良好匹配'。

OpenCV中还有BruteForceMatcher,KNNMatch和FlannBasedMatcher(下面的URL) 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上找到资源。