Improve matching of feature points with OpenCV

后端 未结 3 1925
你的背包
你的背包 2020-12-02 05:12

I want to match feature points in stereo images. I\'ve already found and extracted the feature points with different algorithms and now I need a good matching. In this case

相关标签:
3条回答
  • 2020-12-02 05:27

    An alternate method of determining high-quality feature matches is the ratio test proposed by David Lowe in his paper on SIFT (page 20 for an explanation). This test rejects poor matches by computing the ratio between the best and second-best match. If the ratio is below some threshold, the match is discarded as being low-quality.

    std::vector<std::vector<cv::DMatch>> matches;
    cv::BFMatcher matcher;
    matcher.knnMatch(descriptors_1, descriptors_2, matches, 2);  // Find two nearest matches
    vector<cv::DMatch> good_matches;
    for (int i = 0; i < matches.size(); ++i)
    {
        const float ratio = 0.8; // As in Lowe's paper; can be tuned
        if (matches[i][0].distance < ratio * matches[i][1].distance)
        {
            good_matches.push_back(matches[i][0]);
        }
    }
    
    0 讨论(0)
  • 2020-12-02 05:30

    By comparing all feature detection algorithms I found a good combination, which gives me a lot more matches. Now I am using FAST for feature detection, SIFT for feature extraction and BruteForce for the matching. Combined with the check, whether the matches is inside a defined region I get a lot of matches, see the image:


    (source: codemax.de)

    The relevant code:

    Ptr<FeatureDetector> detector;
    detector = new DynamicAdaptedFeatureDetector ( new FastAdjuster(10,true), 5000, 10000, 10);
    detector->detect(leftImageGrey, keypoints_1);
    detector->detect(rightImageGrey, keypoints_2);
    
    Ptr<DescriptorExtractor> extractor = DescriptorExtractor::create("SIFT");
    extractor->compute( leftImageGrey, keypoints_1, descriptors_1 );
    extractor->compute( rightImageGrey, keypoints_2, descriptors_2 );
    
    vector< vector<DMatch> > matches;
    Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce");
    matcher->knnMatch( descriptors_1, descriptors_2, matches, 500 );
    
    //look whether the match is inside a defined area of the image
    //only 25% of maximum of possible distance
    double tresholdDist = 0.25 * sqrt(double(leftImageGrey.size().height*leftImageGrey.size().height + leftImageGrey.size().width*leftImageGrey.size().width));
    
    vector< DMatch > good_matches2;
    good_matches2.reserve(matches.size());  
    for (size_t i = 0; i < matches.size(); ++i)
    { 
        for (int j = 0; j < matches[i].size(); j++)
        {
            Point2f from = keypoints_1[matches[i][j].queryIdx].pt;
            Point2f to = keypoints_2[matches[i][j].trainIdx].pt;
    
            //calculate local distance for each possible match
            double dist = sqrt((from.x - to.x) * (from.x - to.x) + (from.y - to.y) * (from.y - to.y));
    
            //save as best match if local distance is in specified area and on same height
            if (dist < tresholdDist && abs(from.y-to.y)<5)
            {
                good_matches2.push_back(matches[i][j]);
                j = matches[i].size();
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-02 05:48

    Besides ratio test, you can:

    Only use symmetric matches:

    void symmetryTest(const std::vector<cv::DMatch> &matches1,const std::vector<cv::DMatch> &matches2,std::vector<cv::DMatch>& symMatches)
    {
        symMatches.clear();
        for (vector<DMatch>::const_iterator matchIterator1= matches1.begin();matchIterator1!= matches1.end(); ++matchIterator1)
        {
            for (vector<DMatch>::const_iterator matchIterator2= matches2.begin();matchIterator2!= matches2.end();++matchIterator2)
            {
                if ((*matchIterator1).queryIdx ==(*matchIterator2).trainIdx &&(*matchIterator2).queryIdx ==(*matchIterator1).trainIdx)
                {
                    symMatches.push_back(DMatch((*matchIterator1).queryIdx,(*matchIterator1).trainIdx,(*matchIterator1).distance));
                    break;
                }
            }
        }
    }
    

    and since its a stereo image use ransac test:

    void ransacTest(const std::vector<cv::DMatch> matches,const std::vector<cv::KeyPoint>&keypoints1,const std::vector<cv::KeyPoint>& keypoints2,std::vector<cv::DMatch>& goodMatches,double distance,double confidence,double minInlierRatio)
    {
        goodMatches.clear();
        // Convert keypoints into Point2f
        std::vector<cv::Point2f> points1, points2;
        for (std::vector<cv::DMatch>::const_iterator it= matches.begin();it!= matches.end(); ++it)
        {
            // Get the position of left keypoints
            float x= keypoints1[it->queryIdx].pt.x;
            float y= keypoints1[it->queryIdx].pt.y;
            points1.push_back(cv::Point2f(x,y));
            // Get the position of right keypoints
            x= keypoints2[it->trainIdx].pt.x;
            y= keypoints2[it->trainIdx].pt.y;
            points2.push_back(cv::Point2f(x,y));
        }
        // Compute F matrix using RANSAC
        std::vector<uchar> inliers(points1.size(),0);
        cv::Mat fundemental= cv::findFundamentalMat(cv::Mat(points1),cv::Mat(points2),inliers,CV_FM_RANSAC,distance,confidence); // confidence probability
        // extract the surviving (inliers) matches
        std::vector<uchar>::const_iterator
        itIn= inliers.begin();
        std::vector<cv::DMatch>::const_iterator
        itM= matches.begin();
        // for all matches
        for ( ;itIn!= inliers.end(); ++itIn, ++itM)
        {
            if (*itIn)
            { // it is a valid match
                goodMatches.push_back(*itM);
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题