opencv3.1.0 特征点检测与图像匹配(features2d、xfeatures2d)

    xiaoxiao2023-06-01  1

    特征检测与匹配,在物体检测,视觉跟踪,三维重建等领域都有广泛的应用。所以学习features2d、xfeatures2d中函数的使用,很有必要。

    1、得到特征点与特征点描述(SIFT SURF ORB  AKAZE)

    (1)SIFT

    #include <opencv2\xfeatures2d\nonfree.hpp> vector<KeyPoint> key_points; Mat descriptor; Ptr<Feature2D> sift = xfeatures2d::SIFT::create(0, 3, 0.04, 10); sift->detectAndCompute(image, noArray(), key_points, descriptor);

    (2)SURF(可以认为是尺度不变特征变换sift的加速版)

    #include <opencv2\xfeatures2d\nonfree.hpp> Ptr<Feature2D> surf = xfeatures2d::SURF::create(); surf->detectAndCompute(image, noArray(), key_points, descriptor);

    (3)ORB(实际来看,速度很快,但效果并不一定好)

    #include <opencv2\features2d\features2d.hpp> Ptr<ORB> orb = ORB::create(5000); orb->detectAndCompute(image, noArray(), key_points, descriptor);

    (4)AKAZE(与ORB在同一个hpp中)

    #include <opencv2\features2d\features2d.hpp> Ptr<AKAZE> akaze = AKAZE::create(); akaze->detectAndCompute(image, noArray(), key_points, descriptor);

    2、特征点匹配的几种方法

    (1)与ORB结合使用,效果较好

    void match_features_knn(Mat& query, Mat& train, vector<DMatch>& matches) { flann::Index flannIndex(query,flann::LshIndexParams(12,20,2),cvflann::FLANN_DIST_HAMMING); Mat matchindex(train.rows,2,CV_32SC1); Mat matchdistance(train.rows, 2, CV_32FC1); flannIndex.knnSearch(train, matchindex, matchdistance,2,flann::SearchParams()); //根据劳氏算法 for (int i = 0; i < matchdistance.rows; i++) { if (matchdistance.at<float>(i, 0) < 0.6*matchdistance.at<float>(i, 1)) { DMatch dmatches(matchindex.at<int>(i, 0),i, matchdistance.at<float>(i, 0)); matches.push_back(dmatches); } } } (2)个人感觉这种方法,效果与暴力匹配法没啥区别,但是被注释掉的方法,效果不好

    void match_features_FLANN(Mat& query, Mat& train, vector<DMatch>& matches) { FlannBasedMatcher matcher; /*vector<DMatch> match; matcher.match(query, train, match); double max_dist = 0; double min_dist = 100; for (int i = 0; i < match.size(); i++) { double dist = match[i].distance; if (dist < min_dist) min_dist = dist; if (dist > max_dist) max_dist = dist; } for (int i = 0; i < match.size(); i++) { if (match[i].distance < 2 * min_dist) matches.push_back(match[i]); }*/ vector<vector<DMatch>> knn_matches; 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]); } } (3)也叫暴力匹配法,此种方法结合sift、surf用的比较多

    void match_features(Mat& query, Mat& train, vector<DMatch>& matches) { vector<vector<DMatch>> knn_matches; BFMatcher matcher(NORM_L2); 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]); } } 看下面的效果图,会发现大部分点都是匹配正确的。但是,依然有少部分点匹配的明显不正确。

    3、进一步匹配(寻找源图与目标图像之间的透视变换)

    bool refineMatchesWithHomography(const std::vector<cv::KeyPoint>& queryKeypoints,const std::vector<cv::KeyPoint>& trainKeypoints, float reprojectionThreshold,std::vector<cv::DMatch>& matches,cv::Mat& homography) { const int minNumberMatchesAllowed = 8; if (matches.size() < minNumberMatchesAllowed) return false; // Prepare data for cv::findHomography std::vector<cv::Point2f> srcPoints(matches.size()); std::vector<cv::Point2f> dstPoints(matches.size()); for (size_t i = 0; i < matches.size(); i++) { srcPoints[i] = trainKeypoints[matches[i].trainIdx].pt; dstPoints[i] = queryKeypoints[matches[i].queryIdx].pt; //srcPoints[i] = trainKeypoints[i].pt; //dstPoints[i] = queryKeypoints[i].pt; } // Find homography matrix and get inliers mask std::vector<unsigned char> inliersMask(srcPoints.size()); homography = cv::findHomography(srcPoints,dstPoints,CV_FM_RANSAC,reprojectionThreshold,inliersMask); std::vector<cv::DMatch> inliers; for (size_t i = 0; i<inliersMask.size(); i++) { if (inliersMask[i]) inliers.push_back(matches[i]); } matches.swap(inliers); return matches.size() > minNumberMatchesAllowed; } 效果如下所示(没有发现匹配不对的点)

    转载请注明原文地址: https://ju.6miu.com/read-1262202.html
    最新回复(0)