用Python实现OpenCV特征提取与图像检索demo
“拍立淘”“一键识花”“街景匹配”……不知道大家在使用这些神奇的功能的时候,有没有好奇过它们背后的技术原理?其实这些技术都离不开最基本的图像检索技术。本篇文章我们就将对这一技术的原理进行介绍,并通过一个简单的Python脚本来实现一个最基本的图像检索demo。
图像特征
首先我们需要明白图像特征是什么以及它的使用方法。
图像特征是一种简单的图像模式,基于这种模式我们可以描述我们在图像上所看到的内容。 例如,在一张跟猫有关的图片中,猫咪的眼睛就可以作为这幅图像的特征。特征在(包括但不限于)计算机视觉中的主要作用是将视觉信息转换为向量空间表示。这种向量空间表示让我们可以利用数学运算对其进行处理,例如通过计算寻找相似向量(这可以用来寻找相似图像或图像中的相似目标)。
如何从图像中获取特征?
从图像中获取特征的方法有两种,第一种是通过提取图像描述符实现(白盒算法);第二种通过基于神经网络的方法实现(黑盒算法)。本文主要介绍第一种方法。
特征提取的算法有很多,最常用的有:SURF、ORB、SIFT、BRIEF等。这些算法大多是基于图像梯度的。为了简化安装需求,本教程使用的是KAZE描述符,因为其他描述符在python的基础OpenCV库中没有提供。
下面是特征提取器的实现代码:
OpenCV中的大多数特征提取算法的python接口都相同,所以如果你想要使用SIFT特征,只需要用SIFT_create替换KAZE_create就行。
首先,程序会用extract_features检测图像上的关键点(局部模式的中心点)。 因为关键点数量随图像的不同有所不同,因此我们需要添加一些规则,以确保所得到的特征向量大小始终相同(这是因为在计算时,我们无法对维度不同的向量进行比较,所以必须保证相同的大小)。
然后是根据关键点构建向量描述符,每个描述符的大小为64,我们有32个这样的描述符,所以我们的特征向量是2048维。
batch_extractor是在所有的图像中批量运行特征提取器,并将特征向量保存在pickled文件中以供后续使用。
现在我们来建立类Matcher,它会将待搜索图像和数据库中的图像进行匹配。
这里要加载前一步得到的特征向量,并从它们中创建一个大矩阵,然后计算待搜索图像的特征向量和特征向量数据库之间的余弦距离,然后输出最近的前N个结果。
当然,这仅仅是一个demo,在实际计算中,还可以用一些算法来快速计算数百万图像间的余弦距离。你可以使用简单且运行速度相当快的Annoy Index(在1M图像中搜索约需2ms)。
现在把它们放在一起运行一下:
大家可以在我的 github上下载源码,或者在Google Colab上运行(Google Colab是一种提供GPU在线计算的免费服务):
https://colab.research.google.com/drive/1BwdSConGugBlGzPLLkXHTz2ahkdzEhQ9
总结
在运行上述代码的过程中,你可能会发现搜索到的相似图像并不总能达到我们想象中的那种相似程度。这是因为我们所用的这种算法是上下文无关(context-unaware)的,所以该算法在寻找相同(即使是被修改过的)图像方面表现更好,而不是在相似图像方面。如果是要寻找上下文相关的相似图像,那就要使用卷积神经网络了,我的下一篇文章会对这方面的知识进行详细介绍。