首页 > 解决方案 > 多光谱图像的图像对齐失败与 ECC

问题描述

我正在尝试将 RGB 图像与 IR 图像(单通道)对齐。目标是创建一个 4 通道图像 R、G、B、IR。为了做到这一点,我 按照这个非常简洁的指南cv2.findTransformECC中的描述使用。代码现在没有改变,除了第 13 行,Motion 设置为 Euclidian,因为我想在将来处理旋转。我正在使用 Python。

为了验证软件的工作原理,我使用了指南中的图像。它工作得很好,所以我想如上所述关联来自多个光谱的卫星图像。不幸的是,我在这里遇到了问题。

有时算法会收敛(经过多年),有时会因为无法收敛而立即崩溃,有时它会“找到”明显错误的解决方案。在附件中,您会发现从人类的角度来看,这两张图像很容易匹配,但算法失败了。图像不会以任何方式旋转,它们只是不完全相同的图像(检查边界),因此预计会发生平移运动。图片来自奥地利的新西德勒湖,来源是 Sentinelhub。

编辑:“有时”我指的是使用来自 Sentinel 的不同图像。一对图像始终具有相同的结果。

我知道 ECC 不是基于功能的,这可能会在这里造成问题。

我还读到它在某种程度上取决于初始扭曲矩阵。

我的问题是:

  1. 我用cv2.findTransformECC错了吗?
  2. 有一个更好的方法吗?
  3. 我应该尝试“蒙特卡洛”初始矩阵直到它收敛吗?(这感觉不对)
  4. 您是否建议使用基于特征的算法?
  5. 如果是这样,是否有可用的,或者我必须自己实现这个?

谢谢您的帮助!

标签: pythonopencvimage-processingimage-stitching

解决方案


您是否建议使用基于特征的算法?

当然。有许多特征检测算法。我通常选择 SIFT,因为它提供了良好的匹配结果,并且运行时间非常快。

import cv2 as cv
import numpy as np

# read the images
ir = cv.imread('ir.jpg', cv.IMREAD_GRAYSCALE)
rgb = cv.imread('rgb.jpg', cv.IMREAD_COLOR)

descriptor = cv.SIFT.create()
matcher = cv.FlannBasedMatcher()

# get features from images
kps_ir, desc_ir = descriptor.detectAndCompute(ir, mask=None)
gray = cv.cvtColor(rgb, cv.COLOR_BGR2GRAY)
kps_color, desc_color = descriptor.detectAndCompute(gray, mask=None)

# find the corresponding point pairs
if (desc_ir is not None and desc_color is not None and len(desc_ir) >=2 and len(desc_color) >= 2):
    rawMatch = matcher.knnMatch(desc_color, desc_ir, k=2)
matches = []
# ensure the distance is within a certain ratio of each other (i.e. Lowe's ratio test)
ratio = 0.75
for m in rawMatch:
    if len(m) == 2 and m[0].distance < m[1].distance * ratio:
        matches.append((m[0].trainIdx, m[0].queryIdx))

# convert keypoints to points
pts_ir, pts_color = [], []
for id_ir, id_color in matches:
    pts_ir.append(kps_ir[id_ir].pt)
    pts_color.append(kps_color[id_color].pt)
pts_ir = np.array(pts_ir, dtype=np.float32)
pts_color = np.array(pts_color, dtype=np.float32)

# compute homography
if len(matches) > 4:
    H, status = cv.findHomography(pts_ir, pts_color, cv.RANSAC)

warped = cv.warpPerspective(ir, H, (rgb.shape[1], rgb.shape[0]))
warped = cv.cvtColor(warped, cv.COLOR_GRAY2BGR)

# visualize the result
winname = 'result'
cv.namedWindow(winname, cv.WINDOW_KEEPRATIO)
alpha = 5
# res = cv.addWeighted(rgb, 0.5, warped, 0.5, 0)
res = None
def onChange(alpha):
    global rgb, warped, res, winname
    res = cv.addWeighted(rgb, alpha/10, warped, 1 - alpha/10, 0)
    cv.imshow(winname, res)
onChange(alpha)
cv.createTrackbar('alpha', winname, alpha, 10, onChange)
cv.imshow(winname, res)
cv.waitKey()
cv.destroyWindow(winname)

结果(α=8)

结果 alpha=8

编辑:似乎 SIFT 不是最好的选择,因为它在其他一些例子中失败了。示例图像在另一个问题中。

在这种情况下,我建议使用 SURF。它是一种专利算法,因此它不附带最新的 OpenCV PIP 安装。您可以安装以前版本的 OpenCV 或从源代码构建它。

descriptor = cv.xfeatures2d.SURF_create()

结果(α=8)

SURF 单应性结果

Edit2:现在很明显,完成这项任务的关键是选择正确的特征描述符。最后一点,我建议选择合适的运动模型。在这种情况下,仿射变换比单应性更适合。

H, _ = cv.estimateAffine2D(pts_ir, pts_color)
H = np.vstack((H, [0, 0, 1]))

仿射变换结果:

SURF 仿射结果


推荐阅读