3

私は最近、C++ の OpenCV ライブラリによって提供される機能マッチング アルゴリズムを利用して、機能マッチングを使用して問題を解決しようとしています。

ここで、ORB が SIFT よりも優れた一致をもたらす例が 1 つあります。ORB は SIFT に匹敵する品質を実現しながら、必要な計算時間を短縮しようとする試みだと思いました。そのため、SIFT マッチングで何か間違ったことをしたのではないかと考えました。ただし、他の画像ではうまく機能します。

私が話している例は、バイナリ イメージです。SIFT で得られた結果は次のとおりです。

ここに画像の説明を入力

ORB を使用した結果は次のとおりです。

ここに画像の説明を入力

最初の結果は、SIFT 特徴検出器と SIFT 記述子抽出器で得られました。マッチングには、L2 ノルムのブルート フォース マッチャーを使用しました。2 つ目は、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 がうまく機能する別のケースを次に示します。

ここに画像の説明を入力

これは同じ画像の 2 倍ですが、わずかに回転およびスケーリングされています。

4

0 に答える 0