繁体   English   中英

用 OpenCV + Python 拼接四个图像

[英]Stitching four images with OpenCV + Python

目标:

在过去的两周里,我一直在试图弄清楚如何转换以下图像:

在此处输入图像描述

看起来像这样的一个(可能不完全匹配,因为这张图片是在不同的时间拍摄的):

在此处输入图像描述

镜头校正(必要?):

我注意到的第一件事是,简单地切片图像并覆盖四个部分并不能完美地工作,因为某些线条的曲率不匹配。 例如,中场线在第二个切片中向左弯曲,在第三个切片中向右弯曲。 这种弯曲看起来像桶形失真,所以我尝试使用参数化镜头校正 function(将 k1、k2 和 k3 传递给 OpenCV)和lensfun 由于 lensfun 数据库不包括我的相机品牌或 model(它是一台 AXIS 相机),而且我不知道镜头的品牌或 model(它是作为相机的一部分制造的),我编写了一个小脚本来转储测试图像使用各种具有各种参数的镜头,然后浏览了数千张 output 图像,直到我找到一个看起来有相对直线的镜头:

在此处输入图像描述

此校正是使用“Samyang 12mm f/2.8 Fish-Eye ED AS NCS”镜头和 lensfun 中的“Canon EOS 10D”相机完成的。 它可能并不完美,但我认为它已经足够接近第二步了。

一旦镜头畸变得到纠正,第二个问题是两个切片中的同一条线指向不同的方向,这应该通过简单的透视变换来纠正。 因此,我开始了漫长的探索,以找出适合这种透视变换的参数。

失败的尝试:

1.使用SciPy

我首先编写了一个成本 function 来判断给定参数集的“质量”(重叠像素应该匹配)并应用 SciPy 的求解器来解决这个问题。 我对我的成本 function 进行了一些调整(应用高斯模糊,缩小图像,灰度图像,使用 Sobel 算子获得渐变,在重叠后只查看“接缝”两侧的像素而不是整个重叠区域等),但它总是找不到一个好的解决方案。 大多数时候,结果看起来都比原始相机图像差:

在此处输入图像描述

2. 使用数学

当失败时,我尝试应用数学来计算正确的透视变换。 我知道相机的 FOV(来自规格表),我知道图像宽度和高度,我知道传感器尺寸(来自规格表),并使用 protractor 我测量了镜头之间的角度。 然后,我使用针孔 model计算了图像平面上点的预期 (x,y) 值以及校正它们所需的变换。 结果看起来比 SciPy 好,但仍然令人沮丧。

在此处输入图像描述

3. 使用 OpenCV 的Stitcher

在此之后,我尝试使用 OpenCV 的内置Stitcher class。 然而,由于图像之间的重叠不足,它未能将切片 2 和 3 拼接在一起(大约 10% 的时间它甚至无法将切片 1 和 2 拼接在一起,大概是因为 RANSAC 的不确定性)。 即使它确实成功了,针迹也不是那么好:

在此处输入图像描述

4.使用ORB和OpenCV的findHomography

最近我尝试使用带有掩码的 ORB(仅在重叠区域中寻找特征)和 OpenCV 的findHomography function 来创建自定义版本的 Stitcher。 虽然比赛看起来很有希望,但最终的缝合仍然不是最理想的:

在此处输入图像描述

我开始怀疑我的方法(切片 -> 镜头正确 -> 透视变换 -> 叠加)有缺陷,并且有更好的方法来做到这一点。

5.更新ORB/ findHomography

我更新了我的特征检测,以消除 Y 坐标差异很大的任何匹配项(例如,将桌子的白色与灯光的白色匹配)。 这样做之后,我的匹配特征数量从 ~110 下降到 ~55,但单应性得到了显着改善。 这是切片 1/2 和 2/3 的更新结果:

在此处输入图像描述 在此处输入图像描述

直到有人告诉我这一切都错了,我将继续采用以下附加步骤来执行此策略:

  1. 切片图像
  2. 镜头校正每一片
  3. 透视变换切片 2 或 3,使边线水平,中线垂直
  4. 使用 ORB + 匹配过滤 + findHomography 迭代对齐然后拼接相邻切片

最终,当一切都说完了,我想尝试计算从输入像素到 output 像素的映射,这样我们就不会每帧都做所有这些复杂的工作(镜头校正、ORB、findHomography 等)。 我们将为每个摄像机执行一次,将映射保存到某个文件中,然后我们可以使用cv2.remap将输入视频实时 map 输入到 output 视频逐帧

笔记:

我发布的第二张显示“预期输出”的图像直接来自有问题的相机。 它可以配置为以 30 fps 的速度返回第一张图像,或以 10 fps 的速度返回第二张图像。 我们希望在功能更强大的计算机上执行离机拼接,这样我们就可以获得 30 fps 但仍然有单张图像。

AXIS 提供了一个 SDK 用于离机拼接,但是这个 SDK 仅适用于 Windows,我们的大部分技术堆栈是 Linux 和我们的大多数开发机器是 Mac 我已经使用 Windows 计算机尝试查看他们提供的拼接 SDK,但是我没有运气让它编译和运行。 他们的示例代码不断抛出错误,我从来没有运气让 Visual Studio 或 C++ 为我玩得很好。

我的建议是训练一个自动编码器。 使用第一张图像作为输入,第二张图像作为 output,就像在去噪自动编码器中一样:

自动编码器

请注意,如果您在中间层创建的瓶颈太小,您可能会失去分辨率。

去噪

此外,变分自动编码器呈现一个潜在向量,但遵循相同的原理工作。

VAE

您可以调整此代码:

denoise = Sequential()
denoise.add(Convolution2D(20, 3,3,
                        border_mode='valid',
                        input_shape=input_shape))
denoise.add(BatchNormalization(mode=2))
denoise.add(Activation('relu'))
denoise.add(UpSampling2D(size=(2, 2)))
denoise.add(Convolution2D(20, 3, 3,
                            init='glorot_uniform'))
denoise.add(BatchNormalization(mode=2))
denoise.add(Activation('relu'))
denoise.add(Convolution2D(20, 3, 3,init='glorot_uniform'))
denoise.add(BatchNormalization(mode=2))
denoise.add(Activation('relu'))
denoise.add(MaxPooling2D(pool_size=(3,3)))
denoise.add(Convolution2D(4, 3, 3,init='glorot_uniform'))
denoise.add(BatchNormalization(mode=2))
denoise.add(Activation('relu'))
denoise.add(Reshape((28,28,1)))
sgd = SGD(lr=learning_rate,momentum=momentum, decay=decay_rate, nesterov=False)

denoise.compile(loss='mean_squared_error', optimizer=sgd,metrics = ['accuracy'])
denoise.summary()

denoise.fit(x_train_noisy, x_train,
                nb_epoch=50,
                batch_size=30,verbose=1)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM