我最近一直在尝试使用特征匹配来解决问题,利用 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 效果很好的另一种情况:
这是相同图像的两倍,但略微旋转和缩放。