3

我最近一直在尝试使用特征匹配来解决问题,利用 C++ 中 OpenCV 库提供的特征匹配算法。

现在有一个例子,ORB 给我的匹配比 SIFT 更好,这让我想知道。我认为 ORB 是一种尝试提供与 SIFT 相当的质量,同时需要更少的计算时间。这就是为什么我认为我的 SIFT 匹配可能做错了什么。但是,对于其他图像,效果很好。

我正在谈论的示例是二进制图像。以下是使用 SIFT 获得的结果:

在此处输入图像描述

这是使用 ORB 的结果:

在此处输入图像描述

第一个结果是使用 SIFT 特征检测器和 SIFT 描述符提取器获得的。对于匹配,我使用了具有 L2 范数的蛮力匹配器。对于第二个,我使用了 ORB 特征检测器和 ORB 描述符提取器以及蛮力匹配器,但具有汉明距离。

我通过使用 RANSAC 异常值过滤方法计算单应性来过滤这两种情况下的匹配,然后只保留选定的点对。

我试图摆弄描述符匹配器的参数,但结果并没有太大变化。

现在,您认为为什么 ORB 在这种情况下似乎表现更好有一个合理的解释吗?它可能更适合这种类型的图像吗?还是 SIFT 结果有问题?

编辑:一些代码:

void KeypointMatcher::computeMatches(cv::Mat image1, cv::Mat image2, FeatureDetectorType detectorType, DescriptorExtractorType extractorType, DescriptorMatcherType matcherType) {
    cv::Ptr<cv::FeatureDetector> detector;
    switch (detectorType) {
        case FeatureDetectorType::FAST:
            detector = cv::FeatureDetector::create("FAST");
            break;
        case FeatureDetectorType::STAR:
            detector = cv::FeatureDetector::create("STAR");
            break;
        case FeatureDetectorType::SIFT:
            detector = cv::FeatureDetector::create("SIFT");
            break;
        case FeatureDetectorType::SURF:
            detector = cv::FeatureDetector::create("SURF");
            break;
        case FeatureDetectorType::ORB:
            detector = cv::FeatureDetector::create("ORB");
            break;
        case FeatureDetectorType::BRISK:
            detector = cv::FeatureDetector::create("BRISK");
            break;
        case FeatureDetectorType::MSER:
            detector = cv::FeatureDetector::create("MSER");
            break;
        default:
            detector = cv::FeatureDetector::create("SIFT");
            break;
    }
    detector->detect(image1, _keypoints1);
    detector->detect(image2, _keypoints2);

    cv::Ptr<cv::DescriptorExtractor> extractor;
    switch (extractorType) {
        case DescriptorExtractorType::SIFT:
            extractor = cv::DescriptorExtractor::create("SIFT");
            break;
        case DescriptorExtractorType::SURF:
            extractor = cv::DescriptorExtractor::create("SURF");
            break;
        case DescriptorExtractorType::BRIEF:
            extractor = cv::DescriptorExtractor::create("BRIEF");
            break;
        case DescriptorExtractorType::BRISK:
            extractor = cv::DescriptorExtractor::create("BRISK");
            break;
        case DescriptorExtractorType::ORB:
            extractor = cv::DescriptorExtractor::create("ORB");
            break;
        case DescriptorExtractorType::FREAK:
            extractor = cv::DescriptorExtractor::create("FREAK");
            break;
        default:
            extractor = cv::DescriptorExtractor::create("SIFT");
            break;
    }
    extractor->compute(image1, _keypoints1, _descriptors1);
    extractor->compute(image2, _keypoints2, _descriptors2);

    if (!_descriptors1.empty() && !_descriptors2.empty()) {
        switch (matcherType) {
            case DescriptorMatcherType::BRUTE_FORCE:
                if (extractorType == DescriptorExtractorType::ORB || extractorType == DescriptorExtractorType::BRISK || extractorType == DescriptorExtractorType::BRIEF) {
                    _matcher = cv::DescriptorMatcher::create("BruteForce-Hamming"); 
                } else {
                    _matcher = cv::DescriptorMatcher::create("BruteForce");
                }
                break;
            case DescriptorMatcherType::FLANN:
                _matcher = cv::DescriptorMatcher::create("FlannBased");
                break;
            default:
                _matcher = cv::DescriptorMatcher::create("BruteForce");
                break;
        }

        _matcher->knnMatch(_descriptors1, _descriptors2, _matches, 2);
        if (_matches.size() > 0) {
            _matchesMask = std::vector<bool>(_matches.size(), true);
            _matched = true;
        } else {
            std::cout << "No matching features could be found." << std::endl;
        }
    } else {
        _matched = false;
        std::cout << "No descriptors could be extracted." << std::endl;
    }
}

void KeypointMatcher::homographyFilterMatches(OutlierFilter method) {
    if (!_matched) {
        std::cout << "Matching was not yet executed or no matches have been found." << std::endl;
        return;
    }
    std::vector<cv::Point2d> matchingPoints1, matchingPoints2;
    matchingPoints1.reserve(_matches.size());
    matchingPoints2.reserve(_matches.size());
    std::vector<int> indices;
    indices.reserve(_matches.size());
    for (int i = 0; i < _matchesMask.size(); ++i) {
        if (_matchesMask[i] == true) {
            matchingPoints1.push_back(_keypoints1[_matches[i][0].queryIdx].pt);
            matchingPoints2.push_back(_keypoints2[_matches[i][0].trainIdx].pt);
            indices.push_back(i);
        }
    }

    int meth;
    if (method == OutlierFilter::RANSAC) meth = cv::RANSAC; else meth = cv::LMEDS;
    cv::Mat mask;
    cv::findHomography(matchingPoints1, matchingPoints2, meth, 3, mask);
    for (int i = 0; i < mask.rows; ++i) {
        _matchesMask[indices[i]] = _matchesMask[indices[i]] && (mask.at<uchar>(i, 0) == 1);
    }
}

从主要方面:

cv::Mat image1 = cv::imread("G:/Desktop/thresholded1.png");
cv::Mat image2 = cv::imread("G:/Desktop/thresholded2.png");
hb::KeypointMatcher matcher;
matcher.computeMatches(image1, image2, hb::KeypointMatcher::FeatureDetectorType::SIFT, hb::KeypointMatcher::DescriptorExtractorType::SIFT);
matcher.homographyFilterMatches();

这是 sift 效果很好的另一种情况:

在此处输入图像描述

这是相同图像的两倍,但略微旋转和缩放。

4

0 回答 0