Image Stitching with OpenCV and Python
在本教程中,您将学习如何使用Python,OpenCV和cv2.createStitcher和cv2.Stitcher_create函数执行图像拼接。
使用今天的代码,您将可以将多张图像拼接在一起,从而创建出拼接图像的全景图。
就在不到两年前,我发布了有关图像拼接和全景图构建的两个指南:
这两个教程都涵盖了典型图像拼接算法的基础知识,该算法至少需要四个关键步骤:
- 从两个输入图像中检测关键点(DoG,Harris等)并提取局部不变描述符(SIFT,SURF等)
- 在图像之间匹配描述符
- 使用RANSAC算法通过匹配的特征向量估计单应矩阵(homography matrix)
- 使用从步骤#3获得的单应性矩阵应用翘曲变换(warping transformation)
但是,我最初的实现最大的问题是它们不能处理两个以上的输入图像。
在今天的教程中,我们将重新讨论OpenCV的图像拼接,包括如何将两个以上的图像拼接在一起成为全景图像。
第一部分将简要回顾OpenCV的图像拼接算法,该算法通过cv2.createStitcher和cv2.Stitcher_create函数嵌入OpenCV库本身。
从那里,我们将审查我们的项目结构,并实现可用于图像拼接的Python脚本。
我们将回顾第一个脚本的结果,注意其局限性,然后实施第二个Python脚本,该脚本可用于在美学上使图像拼接效果更加令人满意。
最后,我们将检查第二个脚本的结果,并再次注意任何限制或缺点。
OpenCV的图像拼接算法
今天我们将在此处使用的算法类似于Brown和Lowe在2007年的论文《具有不变特征的自动全景图像拼接》中提出的方法。
Automatic Panoramic Image Stitching with Invariant Features
与以前的对图像输入顺序敏感的图像拼接算法不同,Brown and Lowe方法更健壮,使其对以下内容不敏感:
- 图像顺序
- 图像方向
- 光照变化
- 实际上不是全景图的一部分的有噪声图像
此外,通过使用增益补偿和图像融合来产生更加美观的输出全景图像。
对该算法进行完整,详细的介绍超出了本文的范围,因此,如果您有兴趣了解更多信息,请参阅原始出版物。
cv2.createStitcher and cv2.Stitcher_create
OpenCV已经通过cv2.createStitcher(OpenCV 3.x)和cv2.Stitcher_create(OpenCV 4)函数实现了类似于Brown和Lowe论文的方法。
OpenCV 3.x的cv2.createStitcher的功能签名:
createStitcher(...)
createStitcher([, try_use_gpu]) -> retval
请注意,此函数只有一个参数try_gpu,可用于改善整个图像拼接管道。 OpenCV的GPU支持有限,而且我永远无法使该参数正常工作,因此我建议始终将其保留为False。
OpenCV 4的cv2.Stitcher_create函数具有类似的签名:
Stitcher_create(...)
Stitcher_create([, mode]) -> retval
. @brief Creates a Stitcher configured in one of the stitching
. modes.
.
. @param mode Scenario for stitcher operation. This is usually
. determined by source of images to stitch and their transformation.
. Default parameters will be chosen for operation in given scenario.
. @return Stitcher class instance.
要执行实际的图像拼接,我们需要调用.stitch方法:
OpenCV 3.x:
stitch(...) method of cv2.Stitcher instance
stitch(images[, pano]) -> retval, pano
OpenCV 4.x:
stitch(...) method of cv2.Stitcher instance
stitch(images, masks[, pano]) -> retval, pano
. @brief These functions try to stitch the given images.
.
. @param images Input images.
. @param masks Masks for each input image specifying where to
. look for keypoints (optional).
. @param pano Final pano.
. @return Status code.
此方法接受输入图像列表,然后尝试将它们拼接成全景图,然后将输出的全景图图像返回给调用函数。
status变量指示图像拼接是否成功,并且可以是四个变量之一:
- OK = 0:图像拼接成功。
- ERR_NEED_MORE_IMGS = 1:如果您收到此状态码,则需要更多输入图像来构建全景图。
通常,如果在输入图像中没有检测到足够的关键点,则会发生此错误。 - ERR_HOMOGRAPHY_EST_FAIL = 2:当RANSAC单应性估计失败时,会发生此错误。
同样,您可能需要更多图像,或者图像没有足够的可区分的独特纹理/对象来精确匹配关键点。 - ERR_CAMERA_PARAMS_ADJUST_FAIL = 3:我之前从未遇到过此错误,所以我对此不太了解,但是要点在于,这与无法从输入图像中正确估计相机的内在/外在特性有关。
如果遇到此错误,则可能需要参考OpenCV文档,甚至需要深入研究OpenCV C ++代码。
现在,我们已经回顾了cv2.createStitcher,cv2.Stitcher_create和.stitch方法,让我们继续实际使用OpenCV和Python实现图像拼接。
基本图像拼接结果
但是全景周围的黑色区域呢? 那些是什么?
这些区域从执行构建全景所需的透视扭曲开始。
有一种方法可以消除它们……但是我们将需要在下一部分中实现一些其他逻辑。
使用OpenCV和Python更好的图像拼接器
我们的第一个图像拼接脚本是一个良好的开端,但是全景图本身周围的黑色区域并不是我们所谓的“美观”。
更重要的是,您不会从内置于iOS,Android等的流行图像拼接应用程序中看到这样的输出图像。
因此,我们将对脚本进行一些修改,并包括一些其他逻辑以创建更美观的全景图。
我将再次重申此方法是一种破解。
我们将审查基本的图像处理操作,包括阈值,轮廓提取,形态学操作等,以便获得所需的结果。
据我所知,OpenCV的Python绑定无法为我们提供手动提取全景图的最大内部矩形区域所需的信息。 如果有,请在评论中让我知道。
所有这些代码都与我们之前的脚本相同,但有一个例外。
--crop命令行参数已添加。 在终端中为该参数提供1时,我们将继续进行裁剪操作。
下一步是我们开始实现其他功能的地方:
局限和缺点
在上一教程中,我演示了如何构建实时全景图和图像拼接算法-本教程基于以下事实:我们手动执行关键点检测,特征提取和关键点匹配,从而使我们能够使用所用的单应性矩阵将我们的两个输入图像扭曲成全景图。
而且,尽管OpenCV内置的cv2.createStitcher和cv2.Stitcher_create函数能够构造准确,美观的全景图,但该方法的主要缺点之一是,它抽象了对单应性矩阵的所有访问。
实时全景图构建的一种假设是,场景本身在内容方面变化不大。
一旦我们计算了初始单应性估计,我们只需要偶尔重新计算矩阵即可。
无需执行全面的关键点匹配和RANSAC估计,就可以在构建全景图时极大地提高了速度,因此,如果无法访问原始的单应性矩阵,采用OpenCV的内置图像拼接算法并对其进行实时转换将是一个挑战。
总结
在今天的教程中,您学习了如何使用OpenCV和Python执行多个图像拼接。
使用OpenCV和Python,我们能够将多个图像拼接在一起并创建全景图像。
我们输出的全景图像不仅在缝合位置上准确,而且在美学上也令人愉悦。
但是,使用OpenCV的内置图像拼接类的最大缺点之一是,它抽象了许多内部计算,包括由此产生的单应性矩阵本身。
如果您尝试执行实时图像拼接,如我们在前一篇文章中所做的那样,则可能会发现缓存单应性矩阵并且仅偶尔执行关键点检测,特征提取和特征匹配是有益的。
跳过这些步骤并使用缓存的矩阵执行透视变形可以减少管道的计算负担,并最终加快实时图像拼接算法的速度,但是不幸的是,OpenCV的cv2.createStitcher Python绑定无法为我们提供对原始矩阵。
网友评论