Я недавно пытался решить проблему, используя сопоставление функций, используя алгоритмы сопоставления функций, предоставляемые библиотеками OpenCV в C ++.
Теперь есть один пример, когда 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();
Вот еще один случай, когда просеивание работает хорошо:
Это два раза одно и то же изображение, но слегка повернутое и масштабированное.
Задача ещё не решена.