目标:
在过去的两个星期里,我一直在努力想方设法将以下图像转换为:
对于长成这样的(可能与实际情况不完全匹配,因为此图像是在不同时间拍摄的):
镜头校正(必要性):
我注意到的第一件事是,简单地将图像切片并覆盖四个部分不会完美地起作用,因为某些线条的曲率不匹配。例如,中场线在第二个切片中向左弯曲,在第三个切片中向右弯曲。这种弯曲看起来像桶形畸变,因此我尝试使用参数化的镜头校正函数(将k1、k2和k3传递给OpenCV)以及使用lensfun。由于lensfun数据库不包括我的相机品牌或型号(它是AXIS相机),而且我不知道镜头的品牌或型号(它是作为相机的一部分制造的),所以我编写了一个小脚本,使用各种镜头和各种参数转储测试图像,然后浏览成千上万的输出图像,直到找到看起来有相对直线的图像为止:
这个修正是使用“Samyang 12mm f/2.8 Fish-Eye ED AS NCS”镜头和“Canon EOS 10D”相机在lensfun中完成的。它可能不是完美的,但我认为足够接近了,可以继续进行第二步。一旦镜头畸变被纠正,第二个问题就是同一行在两个切片中指向不同方向,应该通过简单的透视变换来纠正。所以我开始长时间寻找透视变换的正确参数。
失败的尝试:
1. 使用SciPy
我首先编写了一个成本函数来判断给定参数集的“质量”(重叠像素应该匹配),并应用SciPy的求解器来找出它。我对成本函数进行了几次调整(应用高斯模糊、缩小图像、灰度化图像、使用Sobel算子获得梯度、只查看“接缝”两侧的像素而不是整个重叠区域等),但它总是无法找到一个好的解决方案。大多数情况下,结果看起来比原始相机图像更糟糕:
2. 使用数学
当尝试失败后,我尝试应用数学来计算适当的透视变换。我知道相机的视场角(从规格说明书中得知),我知道图像的宽度和高度,我知道传感器的大小(从规格说明书中得知),并使用量角器测量了镜头之间的角度。使用针孔模型,我计算出了图像平面上点的预期(x,y)值以及需要进行的变换来进行纠正。结果看起来比SciPy好,但仍然不太理想。
3. 使用OpenCV的Stitcher
接下来,我尝试使用OpenCV内置的Stitcher
类。然而,由于图像之间的重叠区域不足,它无法将第2和第3张图像拼接在一起(即使有10%的时间它甚至不能将第1和第2张图像拼接在一起,可能是由于RANSAC的非确定性本质)。即使成功拼接,拼接效果也不太好:
4. 使用ORB和OpenCV的findHomography
最近,我尝试使用带有掩码的ORB(仅在重叠区域寻找特征)和OpenCV的findHomography
函数创建一个自定义版本的拼接器。虽然匹配看起来很有前途,但拼接的结果仍然不够理想:
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++为我工作。