点击上方“小白学视觉”,选择加"星标"或“置顶

重磅干货,第一时间送达

图像拼接是计算机视觉中最成功的应用之一。如今,很难找到不包含此功能的手机或图像处理API。在本文中,我们将讨论如何使用Python和OpenCV进行图像拼接。也就是,给定两张共享某些公共区域的图像,目标是“缝合”它们并创建一个全景图像场景。当然也可以是给定多张图像,但是总会转换成两张共享某些公共区域图像拼接的问题,因此本文以最简单的形式进行介绍。

本文主要的知识点包含一下内容:

  • 关键点检测

  • 局部不变描述符(SIFT,SURF等)

  • 特征匹配

  • 使用RANSAC进行单应性估计

  • 透视变换

我们需要拼接的两张图像如下:

特征检测与提取

给定上述一对图像,我们希望将它们缝合以创建全景场景。重要的是要注意,两个图像都需要有一些公共区域。当然,我们上面给出的两张图像时比较理想的,有时候两个图像虽然具有公共区域,但是同样还可能存在缩放、旋转、来自不同相机等因素的影响。但是无论哪种情况,我们都需要检测图像中的特征点。

关键点检测

最初的并且可能是幼稚的方法是使用诸如Harris Corners之类的算法来提取关键点。然后,我们可以尝试基于某种相似性度量(例如欧几里得距离)来匹配相应的关键点。众所周知,角点具有一个不错的特性:角点不变。这意味着,一旦检测到角点,即使旋转图像,该角点仍将存在。

但是,如果我们旋转然后缩放图像怎么办?在这种情况下,我们会很困难,因为角点的大小不变。也就是说,如果我们放大图像,先前检测到的角可能会变成一条线!

总而言之,我们需要旋转和缩放不变的特征。那就是更强大的方法(如SIFT,SURF和ORB)。

关键点和描述符

诸如SIFT和SURF之类的方法试图解决角点检测算法的局限性。通常,角点检测器算法使用固定大小的内核来检测图像上的感兴趣区域(角)。不难看出,当我们缩放图像时,该内核可能变得太小或太大。为了解决此限制,诸如SIFT之类的方法使用高斯差分(DoD)。想法是将DoD应用于同一图像的不同缩放版本。它还使用相邻像素信息来查找和完善关键点和相应的描述符。

首先,我们需要加载2个图像,一个查询图像和一个训练图像。最初,我们首先从两者中提取关键点和描述符。通过使用OpenCV detectAndCompute()函数,我们可以一步完成它。请注意,为了使用detectAndCompute(),我们需要一个关键点检测器和描述符对象的实例。它可以是ORB,SIFT或SURF等。此外,在将图像输入给detectAndCompute()之前,我们将其转换为灰度。

def detectAndDescribe(image, method=None):"""Compute key points and feature descriptors using an specific method"""assert method is not None, "You need to define a feature detection method. Values are: 'sift', 'surf'"# detect and extract features from the imageif method == 'sift':descriptor = cv2.xfeatures2d.SIFT_create()elif method == 'surf':descriptor = cv2.xfeatures2d.SURF_create()elif method == 'brisk':descriptor = cv2.BRISK_create()elif method == 'orb':descriptor = cv2.ORB_create()# get keypoints and descriptors(kps, features) = descriptor.detectAndCompute(image, None)return (kps, features)

我们为两个图像都设置了一组关键点和描述符。如果我们使用SIFT作为特征提取器,它将为每个关键点返回一个128维特征向量。如果选择SURF,我们将获得64维特征向量。下图显示了使用SIFT,SURF,BRISK和ORB得到的结果。

使用ORB和汉明距离检测关键点和描述符

使用SIFT检测关键点和描述符

使用SURF检测关键点和描述符

使用BRISK和汉明距离检测关键点和描述符

特征匹配

如我们所见,两个图像都有大量特征点。现在,我们想比较两组特征,并尽可能显示更多相似性的特征点对。使用OpenCV,特征点匹配需要Matcher对象。在这里,我们探索两种方式:暴力匹配器(BruteForce)和KNN(k最近邻)。

BruteForce(BF)Matcher的作用恰如其名。给定2组特征(来自图像A和图像B),将A组的每个特征与B组的所有特征进行比较。默认情况下,BF Matcher计算两点之间的欧式距离。因此,对于集合A中的每个特征,它都会返回集合B中最接近的特征。对于SIFT和SURF,OpenCV建议使用欧几里得距离。对于ORB和BRISK等其他特征提取器,建议使用汉明距离。我们要使用OpenCV创建BruteForce Matcher,一般情况下,我们只需要指定2个参数即可。第一个是距离度量。第二个是是否进行交叉检测的布尔参数。具体代码如下:

def createMatcher(method,crossCheck):"Create and return a Matcher Object"if method == 'sift' or method == 'surf':bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=crossCheck)elif method == 'orb' or method == 'brisk':bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=crossCheck)return bf

交叉检查布尔参数表示这两个特征是否具有相互匹配才视为有效。换句话说,对于被认为有效的一对特征(f1,f2),f1需要匹配f2,f2也必须匹配f1作为最接近的匹配。此过程可确保提供更强大的匹配功能集,这在原始SIFT论文中进行了描述。

但是,对于要考虑多个候选匹配的情况,可以使用基于KNN的匹配过程。KNN不会返回给定特征的单个最佳匹配,而是返回k个最佳匹配。需要注意的是,k的值必须由用户预先定义。如我们所料,KNN提供了更多的候选功能。但是,在进一步操作之前,我们需要确保所有这些匹配对都具有鲁棒性。

比率测试

为了确保KNN返回的特征具有很好的可比性,SIFT论文的作者提出了一种称为比率测试的技术。一般情况下,我们遍历KNN得到匹配对,之后再执行距离测试。对于每对特征(f1,f2),如果f1和f2之间的距离在一定比例之内,则将其保留,否则将其丢弃。同样,必须手动选择比率值。

本质上,比率测试与BruteForce Matcher的交叉检查选项具有相同的作用。两者都确保一对检测到的特征确实足够接近以至于被认为是相似的。下面2个图显示了BF和KNN Matcher在SIFT特征上的匹配结果。我们选择仅显示100个匹配点以清晰显示。

使用KNN和SIFT的定量测试进行功能匹配

在SIFT特征上使用暴力匹配器进行特征匹配

需要注意的是,即使做了多种筛选来保证匹配的正确性,也无法完全保证特征点完全正确匹配。尽管如此,Matcher算法仍将为我们提供两幅图像中最佳(更相似)的特征集。接下来,我们利用这些点来计算将两个图像的匹配点拼接在一起的变换矩阵。

这种变换称为单应矩阵。简而言之,单应性是一个3x3矩阵,可用于许多应用中,例如相机姿态估计,透视校正和图像拼接。它将点从一个平面(图像)映射到另一平面。

估计单应性

随机采样一致性(RANSAC)是用于拟合线性模型的迭代算法。与其他线性回归器不同,RANSAC被设计为对异常值具有鲁棒性。

像线性回归这样的模型使用最小二乘估计将最佳模型拟合到数据。但是,普通最小二乘法对异常值非常敏感。如果异常值数量很大,则可能会失败。RANSAC通过仅使用数据中的一组数据估计参数来解决此问题。下图显示了线性回归和RANSAC之间的比较。需要注意数据集包含相当多的离群值。

我们可以看到线性回归模型很容易受到异常值的影响。那是因为它试图减少平均误差。因此,它倾向于支持使所有数据点到模型本身的总距离最小的模型。包括异常值。相反,RANSAC仅将模型拟合为被识别为点的点的子集。

这个特性对我们的用例非常重要。在这里,我们将使用RANSAC来估计单应矩阵。事实证明,单应矩阵对我们传递给它的数据质量非常敏感。因此,重要的是要有一种算法(RANSAC),该算法可以从不属于数据分布的点中筛选出明显属于数据分布的点。

估计了单应矩阵后,我们需要将其中一张图像变换到一个公共平面上。在这里,我们将对其中一张图像应用透视变换。透视变换可以组合一个或多个操作,例如旋转,缩放,平移或剪切。我们可以使用OpenCV warpPerspective()函数。它以图像和单应矩阵作为输入。

# Apply panorama correction
width = trainImg.shape[1] + queryImg.shape[1]
height = trainImg.shape[0] + queryImg.shape[0]result = cv2.warpPerspective(trainImg, H, (width, height))
result[0:queryImg.shape[0], 0:queryImg.shape[1]] = queryImgplt.figure(figsize=(20,10))
plt.imshow(result)plt.axis('off')
plt.show()

生成的全景图像如下所示。如我们所见,结果中包含了两个图像中的内容。另外,我们可以看到一些与照明条件和图像边界边缘效应有关的问题。理想情况下,我们可以执行一些处理技术来标准化亮度,例如直方图匹配,这会使结果看起来更真实和自然一些。

下载1:OpenCV-Contrib扩展模块中文版教程

在「小白学视觉」公众号后台回复:扩展模块中文教程即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。

下载2:Python视觉实战项目52讲

在「小白学视觉」公众号后台回复:Python视觉实战项目即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。

下载3:OpenCV实战项目20讲

在「小白学视觉」公众号后台回复:OpenCV实战项目20讲即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。

交流群

欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~

使用OpenCV进行图像全景拼接相关推荐

  1. opencv图像拼接_使用OpenCV进行图像全景拼接

    点击上方"AI小白学视觉",选择加"星标"或"置顶"重磅干货,第一时间送达 图像拼接是计算机视觉中最成功的应用之一.如今,很难找到不包含此功 ...

  2. python全景图像拼接_Python+OpenCV实现图像的全景拼接

    本文实例为大家分享了Python+OpenCV实现图像的全景拼接的具体代码,供大家参考,具体内容如下 环境:python3.5.2 + openCV3.4 1.算法目的 将两张相同场景的场景图片进行全 ...

  3. opencv图像全景拼接

    2019-8 最近小弟准备稍微写下自己的毕业设计的内容(如各位大佬赶时间不想听的话,直接划到下边吧),本人是个毕业于广东广州普通二本的学生,去年考研没上岸(学校没保研资格...,不过复习也有点浪),今 ...

  4. OpenCV C++案例实战十二《图像全景拼接》

    OpenCV C++案例实战十二<图像全景拼接> 前言 一.OpenCV Stitcher 1.功能源码 2.效果 二.图像全景拼接 1.特征检测 2.计算单应性矩阵 3.透视变换 4.图 ...

  5. 可以使用的图像全景拼接opencv

    引自:基于Python和OpenCV实现图像的全景拼接_半濠春水的博客-CSDN博客_python opencv 图片合成 使用环境opencv4.5.4.58,python3.6,numpy1.19 ...

  6. Python,OpenCV骨架化图像并显示(skeletonize)

    Python,OpenCV骨架化图像并显示(skeletonize) 1. 效果图 2. 源码 参考: 1. 效果图 自己画一张图,原图 VS 骨架效果图如下: opencv logo原图 VS 骨架 ...

  7. 使用Python,OpenCV制作图像Mask——截取ROIs及构建透明的叠加层

    使用Python,OpenCV制作图像Mask--截取ROIs及构建透明的叠加层 1. 效果图 2. 源码 参考 这篇博客将介绍如何使用OpenCV制作Mask图像掩码.使用位运算和图像掩码允许我们只 ...

  8. 使用Python,OpenCV实现图像和实时视频流中的人脸模糊和马赛克

    使用Python,OpenCV实现图像和实时视频流中的人脸模糊和人脸马赛克 1. 效果图 2. 原理 2.1 什么是人脸模糊,如何将其用于人脸匿名化? 2.2 执行人脸模糊/匿名化的步骤 3. 源码 ...

  9. 使用Python和OpenCV检测图像中的条形码

    使用Python和OpenCV检测图像中的条形码 1. 效果图 2. 算法的步骤 3. 源码 参考 这篇博客将介绍使用计算机视觉和图像处理技术进行条形码检测的必要步骤,并演示使用Python编程语言和 ...

最新文章

  1. vs调试程序缺少 msvcp140d.dll 解决方法
  2. vs2015使用GIt连接git.oschina.net/
  3. SQL Server 中常见的十张系统表
  4. 字典数(前缀树)的实现
  5. mysql加锁语法_MySql 加锁问题
  6. webx学习(四)——ResourceLoadingService
  7. 一般技术书籍出版版税多少_如何为您的技术书籍寻找出版商
  8. java中的保留n位小数
  9. 从IBM SCE+落地中国看IDC的转型
  10. windows 系列机器查看tcp 配置
  11. 1000多页的pdf算法题整理完成,字节算法面试手册来了
  12. boolean到底占几个字节?
  13. 家用电冰箱3C认证检测标准
  14. ios如何设置系统定位服务器地址,iOS开发之iOS10.0之后如何从APP进入系统定位服务设置界面...
  15. dota2中断与服务器连接,dota2断开服务器连接
  16. word安全模式解除
  17. Linux安装显卡驱动
  18. noob_臭代码-Java Noob的自白
  19. VLAN的接口类型与TAG帧
  20. 世界上有10种人,一种是懂二进制的人,一种是不懂二进制的人。

热门文章

  1. 一览群智胡健:在中国完全照搬Palantir模式,这不现实
  2. 图灵奖得主LeCun力推无监督学习:要重视基于能量的学习方法
  3. 自动驾驶人的福音!Lyft公开Level 5部署平台Flexo细节
  4. AI假新闻满天飞,打假神器GROVER帮你看清一切
  5. BERT拿下最佳长论文奖!NAACL 2019最佳论文奖公布
  6. 去中心化已成大势所趋,手机的中枢地位岌岌可危?
  7. 国内最牛的Java面试八股,真offer收割机!
  8. 面试官:Java中 serialVersionUID 的作用是什么?举个例子说明
  9. 求你了,不要再在对外接口中使用枚举类型了!
  10. 在滴滴和头条干了 2 年后端开发,太真实了…