【发布时间】:2020-03-10 16:16:01
【问题描述】:
目标:
在过去的两周里,我一直在试图弄清楚如何转换以下图像:
看起来像这样的一张(可能不完全匹配,因为这张图片是在不同的时间拍摄的):
镜头校正(需要吗?):
我注意到的第一件事是,简单地切片图像并覆盖四个部分并不能完美地工作,因为某些线条的曲率不匹配。例如,中场线在第二个切片中向左弯曲,在第三个切片中向右弯曲。这种弯曲看起来像barrel distortion,所以我尝试使用参数化镜头校正功能(将 k1、k2 和 k3 传递给 OpenCV)和使用lensfun。由于 lensfun 数据库不包括我的相机品牌或型号(它是 AXIS 相机),并且我不知道镜头的品牌或型号(它是作为相机的一部分制造的),我编写了一个小脚本来转储测试图像使用具有各种参数的各种镜头,然后浏览了 数千张 输出图像,直到我找到一个看起来有相对直线的镜头:
此校正是在 lensfun 中使用“Samyang 12mm f/2.8 Fish-Eye ED AS NCS”镜头和“Canon EOS 10D”相机完成的。它可能不是完美,但我认为它已经足够接近,可以继续进行第二步了。
镜头畸变校正后,第二个问题是两个切片中的同一条线指向不同的方向,应该通过简单的透视变换来校正。因此,我开始了漫长的探索,以找出适合这种透视变换的参数。
尝试失败:
1。使用 SciPy
我首先编写了一个成本函数来判断给定参数集的“质量”(重叠像素应该匹配),然后应用 SciPy 的求解器来解决这个问题。我对成本函数进行了一些调整(应用高斯模糊、缩小图像、灰度缩放图像、使用 Sobel 算子获得渐变、重叠后只查看“接缝”两侧的像素而不是整个重叠区域等),但它总是找不到一个好的解决方案。结果在大多数情况下看起来都比原始相机图像差:
2。使用数学
当失败时,我尝试将数学应用于计算正确的透视变换。我知道相机的 FOV(来自规格表),我知道图像宽度和高度,我知道传感器尺寸(来自规格表),并使用量角器测量了镜头之间的角度。然后,我使用pinhole model 计算了图像平面上点的预期 (x,y) 值以及校正它们所需的变换。结果看起来比 SciPy 好,但仍然令人沮丧。
3。使用 OpenCV 的 Stitcher
在此之后,我尝试使用 OpenCV 的内置 Stitcher 类。然而,由于图像之间的重叠不足,它未能将切片 2 和 3 拼接在一起(大约 10% 的时间它甚至无法将切片 1 和 2 拼接在一起,大概是因为 RANSAC 的不确定性)。即使它确实成功了,针迹也不是那么好:
4。使用 ORB 和 OpenCV 的 findHomography
最近我尝试使用带有掩码的 ORB(仅在重叠区域中寻找特征)和 OpenCV 的 findHomography 函数来创建自定义版本的 Stitcher。虽然比赛看起来很有希望,但最终的针迹仍然不是最理想的:
我开始怀疑我的方法(切片 -> 镜头正确 -> 透视变换 -> 叠加)有缺陷,有更好的方法来做到这一点。
5。更新 ORB / findHomography
我更新了特征检测以消除 Y 坐标差异很大的任何匹配项(例如,将桌子的白色与灯光的白色匹配)。这样做之后,我的匹配特征数量从 ~110 下降到 ~55,但单应性得到了显着改善。这是切片 1/2 和 2/3 的更新结果:
在有人告诉我这一切都错了之前,我将继续执行此策略,并添加以下步骤:
- 切片图像
- 镜头校正每个切片
- 透视变换切片 2 或 3,使边线水平,中线垂直
- 使用 ORB + 匹配过滤 + findHomography 迭代对齐然后缝合相邻切片
最终,当一切都说完了,我想尝试计算从输入像素到输出像素的映射,这样我们就不会每帧都做所有这些复杂的工作(镜头校正、ORB、findHomography 等)。我们将为每个摄像机执行一次,将映射保存到某个文件中,然后我们可以使用 cv2.remap 将输入视频逐帧实时映射到输出视频
注意:
我发布的第二张显示“预期输出”的图片直接来自相关相机。它可以配置为以 30 fps 的速度返回第一张图像,或以 10 fps 的速度返回第二张图像。我们希望在功能更强大的计算机上执行离机拼接,这样我们可以获得 30 fps 的速度,但仍然拥有单张图像。
AXIS 提供了一个用于离机拼接的 SDK,但该 SDK 仅适用于 Windows,我们的大部分技术堆栈都是 Linux,我们的大多数开发机器都是 Mac OS。我已经使用 Windows 计算机尝试查看他们提供的拼接 SDK,但是我没有运气让它编译和运行。他们的示例代码不断抛出错误,我从来没有让 Visual Studio 或 C++ 为我很好地发挥作用。
【问题讨论】: