Результаты определения ключевых точек 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());
}

Обе эти реализации:

  1. Загрузите изображения в память в том формате, в котором они им нужны.
  2. Определите ключевые точки и дескрипторы на каждом изображении.
  3. Ищите совпадения между изображениями.

Журналы консоли 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++.

Я пытаюсь выяснить, откуда это неравенство. Мои реализации не совпадают?

0 ответов

Другие вопросы по тегам