python - 使用 ORB 的 OpenCV 图像对齐

标签 python opencv image-processing image-registration

我需要精确对齐两张图片。为此,我使用了增强相关系数 (ECC)。除了旋转很多的图像外,这给了我很好的结果。例如,如果引用图像(基本图像)和测试图像(我想对齐)旋转 90 度,ECC 方法不起作用,根据 findTransformECC() 的文档,这是正确的上面写着

Note that if images undergo strong displacements/rotations, an initial transformation that roughly aligns the images is necessary (e.g., a simple euclidean/similarity transform that allows for the images showing the same image content approximately).

所以我不得不使用基于特征点的对齐方法来做一些粗略的对齐。我尝试了 SIFT 和 ORB,但我都面临同样的问题。它适用于某些图像,而对于其他图像,生成的变换会在错误的一侧移动或旋转。

这些是输入图像: Reference image Image to be aligned

我认为问题是由错误匹配引起的,但如果我只使用 10 个距离较小的关键点,在我看来它们都是很好的匹配(我使用 100 个关键点时结果完全相同)

这是匹配的结果: enter image description here

这是结果: Result

如果您比较旋转后的图像,它会向右移动并上下颠倒。 我错过了什么?

这是我的代码:

        # 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)

最佳答案

这个问题的答案既平凡又令人恼火。假设这与我遇到的问题相同(我认为是):

问题与解释 大多数相机使用包含“方向”值的 EXIF 标签保存图像。从 OpenCV 3.2 开始,当使用 cv.imread() 加载图像时,会自动读入该方向标签,并根据该标签调整图像方向(共有 8 种可能的方向,包括 90* 旋转、镜像和翻转).某些图像查看应用程序(例如 Linux Mint Cinnamon 中的图像查看器和 Adob​​e Photoshop)将显示沿 EXIF Orientation 标签方向旋转的图像。其他应用程序(例如 QGIS 和 OpenCV < 3.2)会忽略该标签。如果您的图像 1 有一个方向标签,图像 2 有一个方向标签,并且您在 OpenCV 中使用 ORB 执行对齐(我没有为此尝试过 SIFT),则您对齐的图像 2 将以正确的方向(图片 1) 在读取 EXIF 方向标签的应用程序中打开时。但是,如果您在忽略 EXIF 方向标签的应用程序中打开两个图像,那么它们将不会显示为具有相同的方向。当一张图片有方向标签而另一张没有时,这个问题变得更加明显。

一种可能的解决方案 在将图像读入 OpenCV 之前删除 EXIF 方向标签。现在,从 OpenCV 3.4(也许是 3.3?)开始,有一个选项可以忽略标签来加载图像,但是完成后,它们将作为灰度(1 channel )加载,如果您需要颜色 ,这将无济于事cv.imread('image.jpg',128) 其中 128 表示“忽略方向”。因此,我在 python 中使用 pyexiv2 从我的图像中删除有问题的 EXIF 方向标签:

import pyexiv2
image = path_to_image
imageMetadata = pyexiv2.ImageMetadata(image)
imageMetadata.read()
try:
    del imageMetadata['Exif.Image.Orientation']
    imageMetadata.write()
except:
    continue

关于python - 使用 ORB 的 OpenCV 图像对齐,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42924629/

相关文章:

python - 提取并重命名 zip 文件夹

python - 如何捕捉 IndentationError

python - 绕过 'important information page'时进行网络爬行

c - 使用 ffmpeg api 或 C 代码处理 .raw 文件图像

python - 如何将数据框中的序列拟合到多类问题? |凯拉斯 | Pandas |值错误 : setting an array element with a sequence

c++ - 调试断言失败 OpenCv is_block_type_valid(header->_block_use)

java - 如何使用 Java API 在 opencv 中创建轨迹栏

c++ - 当画面中出现蓝色时,图像处理失败。可能是什么原因?

Java - 分析图像的黑暗程度

python - 在 PIL 中使用 Image.point() 方法来操作像素数据