OpenCV Image Aligment с использованием ORB

Мне нужно точно выровнять два изображения. Для этого я использую Расширенный коэффициент корреляции (ECC). Что дает мне отличные результаты, за исключением изображений, которые часто вращаются. Например, если эталонное изображение (базовое изображение) и тестируемое изображение (которое я хочу выровнять) повернуты на 90 градусов, метод ECC не работает, что верно в соответствии с документацией findTransformECC(), в которой говорится

Обратите внимание, что если изображения подвергаются сильным смещениям / поворотам, необходимо первоначальное преобразование, которое приблизительно выравнивает изображения (например, простое евклидово преобразование / преобразование подобия, которое допускает изображения, показывающие примерно одинаковое содержание изображения).

Поэтому я должен использовать метод выравнивания на основе характерных точек, чтобы выполнить грубое выравнивание. Я попробовал и SIFT и ORB, и я столкнулся с той же самой проблемой с обоими. Он хорошо работает для некоторых изображений, а для других результирующее преобразование смещено или повернуто на неправильную сторону.

Это входные изображения: Эталонное изображение Изображение для выравнивания

Я думал, что проблема вызвана неправильными совпадениями, но если я использую только 10 ключевых точек с меньшим расстоянием, мне кажется, что все они являются хорошими совпадениями (у меня точно такой же результат, когда я использую 100 ключевых точек)

Это результат соответствия:

Это результат: Результат

Если вы сравните повернутое изображение, оно сместится вправо и вверх ногами. Что мне не хватает?

Это мой код:

        # Initiate detector
    orb = cv2.ORB_create()

    # find the keypoints with ORB
    kp_base = orb.detect(base_gray, None)
    kp_test = orb.detect(test_gray, None)

    # compute the descriptors with ORB
    kp_base, des_base = orb.compute(base_gray, kp_base)
    kp_test, des_test = orb.compute(test_gray, kp_test)

    # Debug print
    base_keypoints = cv2.drawKeypoints(base_gray, kp_base, color=(0, 0, 255), flags=0, outImage=base_gray)
    test_keypoints = cv2.drawKeypoints(test_gray, kp_test, color=(0, 0, 255), flags=0, outImage=test_gray)

    output.debug_show("Base image keypoints",base_keypoints, debug_mode=debug_mode,fxy=fxy,waitkey=True)
    output.debug_show("Test image keypoints",test_keypoints, debug_mode=debug_mode,fxy=fxy,waitkey=True)

    # find matches
    # create BFMatcher object
    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
    # Match descriptors.
    matches = bf.match(des_base, des_test)
    # Sort them in the order of their distance.
    matches = sorted(matches, key=lambda x: x.distance)


    # Debug print - Draw first 10 matches.
    number_of_matches = 10
    matches_img = cv2.drawMatches(base_gray, kp_base, test_gray, kp_test, matches[:number_of_matches], flags=2, outImg=base_gray)
    output.debug_show("Matches", matches_img, debug_mode=debug_mode,fxy=fxy,waitkey=True)

    # calculate transformation matrix
    base_keypoints = np.float32([kp_base[m.queryIdx].pt for m in matches[:number_of_matches]]).reshape(-1, 1, 2)
    test_keypoints = np.float32([kp_test[m.trainIdx].pt for m in matches[:number_of_matches]]).reshape(-1, 1, 2)
    # Calculate Homography
    h, status = cv2.findHomography(base_keypoints, test_keypoints)
    # Warp source image to destination based on homography
    im_out = cv2.warpPerspective(test_gray, h, (base_gray.shape[1], base_gray.shape[0]))
    output.debug_show("After rotation", im_out, debug_mode=debug_mode, fxy=fxy)

0 ответов

Ответ на эту проблему является и мирским и раздражающим. Предполагая, что это та же самая проблема, с которой я столкнулся (я думаю, что это так):

Проблема и объяснение Изображения сохраняются большинством камер с тегами EXIF, которые содержат значение "Ориентация". Начиная с OpenCV 3.2, этот тег ориентации автоматически считывается, когда изображение загружается с помощью cv.imread(), и изображение ориентируется на основе тега (существует 8 возможных ориентаций, которые включают в себя поворот на 90*, отражение и отражение). Некоторые приложения для просмотра изображений (такие как Image Viewer в Linux Mint Cinnamon и Adobe Photoshop) отображают изображения, повернутые в направлении тега ориентации EXIF. Другие приложения (такие как QGIS и OpenCV < 3.2) игнорируют тег. Если ваше изображение 1 имеет тег ориентации, а изображение 2 имеет тег ориентации, и вы выполняете выравнивание с помощью ORB (я не пробовал SIFT для этого) в OpenCV, выровненное изображение 2 будет отображаться с правильной ориентацией (ориентация Изображение 1) при открытии в приложении, которое читает тег EXIF ​​Orientation. Однако если вы откроете оба изображения в приложении, которое игнорирует тег EXIF ​​Orientation, они не будут иметь одинаковую ориентацию. Эта проблема становится еще более заметной, когда одно изображение имеет тег ориентации, а другое - нет.

Одно из возможных решений Удалите теги EXIF ​​Orientation перед чтением изображений в OpenCV. Теперь, начиная с OpenCV 3.4 (может быть 3.3?), Есть возможность загружать изображения, игнорирующие тег, но когда это сделано, они загружаются в градациях серого (1 канал), что бесполезно, если вам НУЖЕН цвет cv.imread('image.jpg',128) где 128 означает "игнорировать ориентацию). Итак, я использую pyexiv2 в python, чтобы удалить неправильный тег EXIF ​​Orientation из моих изображений:

import pyexiv2
image = path_to_image
imageMetadata = pyexiv2.ImageMetadata(image)
imageMetadata.read()
try:
    del imageMetadata['Exif.Image.Orientation']
    imageMetadata.write()
except:
    continue
Другие вопросы по тегам