python - 多光谱图像的图像对齐失败与 ECC
问题描述
我正在尝试将 RGB 图像与 IR 图像(单通道)对齐。目标是创建一个 4 通道图像 R、G、B、IR。为了做到这一点,我 按照这个非常简洁的指南cv2.findTransformECC
中的描述使用。代码现在没有改变,除了第 13 行,Motion 设置为 Euclidian,因为我想在将来处理旋转。我正在使用 Python。
为了验证软件的工作原理,我使用了指南中的图像。它工作得很好,所以我想如上所述关联来自多个光谱的卫星图像。不幸的是,我在这里遇到了问题。
有时算法会收敛(经过多年),有时会因为无法收敛而立即崩溃,有时它会“找到”明显错误的解决方案。在附件中,您会发现从人类的角度来看,这两张图像很容易匹配,但算法失败了。图像不会以任何方式旋转,它们只是不完全相同的图像(检查边界),因此预计会发生平移运动。图片来自奥地利的新西德勒湖,来源是 Sentinelhub。
编辑:“有时”我指的是使用来自 Sentinel 的不同图像。一对图像始终具有相同的结果。
我知道 ECC 不是基于功能的,这可能会在这里造成问题。
我还读到它在某种程度上取决于初始扭曲矩阵。
我的问题是:
- 我用
cv2.findTransformECC
错了吗? - 有一个更好的方法吗?
- 我应该尝试“蒙特卡洛”初始矩阵直到它收敛吗?(这感觉不对)
- 您是否建议使用基于特征的算法?
- 如果是这样,是否有可用的,或者我必须自己实现这个?
谢谢您的帮助!
解决方案
您是否建议使用基于特征的算法?
当然。有许多特征检测算法。我通常选择 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)
编辑:似乎 SIFT 不是最好的选择,因为它在其他一些例子中失败了。示例图像在另一个问题中。
在这种情况下,我建议使用 SURF。它是一种专利算法,因此它不附带最新的 OpenCV PIP 安装。您可以安装以前版本的 OpenCV 或从源代码构建它。
descriptor = cv.xfeatures2d.SURF_create()
结果(α=8)
Edit2:现在很明显,完成这项任务的关键是选择正确的特征描述符。最后一点,我建议选择合适的运动模型。在这种情况下,仿射变换比单应性更适合。
H, _ = cv.estimateAffine2D(pts_ir, pts_color)
H = np.vstack((H, [0, 0, 1]))
仿射变换结果:
推荐阅读
- java - 将 maven Shade 与 Proguard 混合
- javascript - 当我的屏幕第二次加载时,反应本机组件接收道具不加载
- c# - 从 bakcground 线程调用 UI 线程上的许多方法
- java - 方法覆盖总是运行时多态性吗?
- bootstrap-modal - 将外部内容插入引导模式
- android - android中的动态表格布局,其中行应该在下一次迭代开始之前被清除
- r - 从每一行产生一个矩阵(tidyverse)
- pdf - Flutter 创建具有不同页面大小和字体大小的 pdf 文件
- image-processing - 镜头畸变
- angularjs - AngularFire 错误 - 客户端无权访问所需数据