Результаты определения ключевых точек SURF и сопоставления FLANN между изображениями сильно различаются для библиотек C++ и Python OpenCV
Я реализовал рабочий процесс сопоставления ключевых точек между изображениями в Python, и я нахожусь в процессе преобразования его в Objective C++ для использования в проекте iOS. Я использую OpenCV 3.4 на обеих платформах. Хотя я сопоставляю свой код, результаты кажутся совершенно другими.
Реализация Python:
def simple(source_image_name, sample_image_name):
surf = cv2.xfeatures2d.SURF_create(400, nOctaves=3, nOctaveLayers=4, extended=False, upright=True)
source_image = cv2.imread(source_image_name, 0)
# Detect keypoints in source image
source_keypoints, source_descriptors = surf.detectAndCompute(source_image, None)
print("source keypoints: " + str(len(source_keypoints)))
sample_image = cv2.imread(sample_image_name, 0)
# Detect keypoints in sample image
sample_keypoints, sample_descriptors = surf.detectAndCompute(sample_image, None)
print("sample keypoints: " + str(len(sample_keypoints)))
# Find matches between the images
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict()
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(source_descriptors, sample_descriptors, k=2)
print("matches: " + str(len(matches)))
# Filter to good matches
good_matches = []
for match1, match2 in matches:
if match1.distance < match2.distance * 0.75:
good_matches.append(match1)
print("good matches: " + str(len(good_matches)))
Цель реализации C++:
+ (void)simpleWithSourceImage:(UIImage *)sourceImage sampleImage:(UIImage *)sampleImage {
Ptr<SURF> surf = cv::xfeatures2d::SURF::create(400, 3, 4, false, true);
cv::Mat sourceImageMat;
UIImageToMat(sourceImage, sourceImageMat);
std::vector<KeyPoint> sourceKeypoints;
cv::Mat sourceDescriptors;
//Detect keypoints in source image
surf->detectAndCompute(sourceImageMat, noArray(), sourceKeypoints, sourceDescriptors);
NSLog(@"source keypoints: %lu", sourceKeypoints.size());
cv::Mat sampleImageMat;
UIImageToMat(sampleImage, sampleImageMat);
std::vector<KeyPoint> sampleKeypoints;
cv::Mat sampleDescriptors;
//Detect keypoints in sample image
surf->detectAndCompute(sampleImageMat, noArray(), sampleKeypoints, sampleDescriptors);
NSLog(@"sample keypoints: %lu", sampleKeypoints.size());
//Find matches between the images
FlannBasedMatcher matcher(new cv::flann::KDTreeIndexParams(5));
std::vector<std::vector<DMatch>> matches;
matcher.knnMatch(sampleDescriptors, sourceDescriptors, matches, 2);
NSLog(@"matches: %lu", matches.size());
//Filter to good matches
std::vector<DMatch> goodMatches;
for (int i = 0; i < matches.size(); i++) {
std::vector<DMatch> match = matches[i];
if (match[0].distance < match[1].distance * 0.75) {
DMatch goodMatch = match[0];
goodMatches.push_back(goodMatch);
}
}
NSLog(@"good matches: %lu", goodMatches.size());
}
Обе эти реализации:
- Загрузите изображения в память в том формате, в котором они им нужны.
- Определите ключевые точки и дескрипторы на каждом изображении.
- Ищите совпадения между изображениями.
Журналы консоли Python:
source keypoints: 16133
sample keypoints: 18265
matches: 16133
good matches: 3785
Журналы консоли C++:
source keypoints: 16281
sample keypoints: 18040
matches: 18040
good matches: 558
Хотя им были даны одни и те же изображения, количество обнаруженных ключевых точек немного отличается на обоих изображениях. Возможно, это связано с тем, как они считывают изображения. Небольшая разница, составляющая около 1%, не является большой проблемой.
Однако совпадения имеют большую разницу, примерно с разницей в 11%, хотя на самом деле это выше для C++. И тогда количество удачных совпадений для C++ намного меньше - разница 86%.
Я посмотрел в matches
разница немного больше...
Python соответствует:
match 1 average: 0.220831272634
distance average: 0.840705045962
C++ соответствует:
match 1 average: 0.298346
distance average: 0.924873
Таким образом, среднее значение совпадения 1 заметно выше для результатов C++, а среднее расстояние между первым совпадением и вторым совпадением намного ближе.
Я попытался изменить этот исходный код - для загрузки файлов изображений, чтобы это:
NSFileHandle* sourceHandle = [NSFileHandle fileHandleForReadingAtPath:sourceImageName];
NSData *sourceData = [sourceHandle readDataToEndOfFile];
v::Mat sourceImageMat = cv::imdecode(cv::Mat(1, [sourceData length], CV_8UC1, (void*)sourceData.bytes), CV_LOAD_IMAGE_UNCHANGED);
Это повлияло на результаты, но не повлияло на вывод - совпадения в C++ все еще намного ниже, с большим расстоянием и близким расстоянием между результатами:
source keypoints: 16116
sample keypoints: 18253
matches: 18253
good matches: 518
match 1 average: 0.299299
distance average: 0.925706
Я также попытался посмотреть на среднее значение совпадения 2 для кода Python, и среднее значение составило 0,26 - все еще ниже, чем среднее значение по математике 1 для кода C++. Другими словами, вторые лучшие результаты для Python были в среднем лучше, чем лучшие совпадения для C++.
Я пытаюсь выяснить, откуда это неравенство. Мои реализации не совпадают?