python+opencv判断两个图像是否相似(附代码)

一、涉及到的知识点
opencv的安装见我的另一篇文章python3.7下的opencv安装
图像算法参考了这篇文章
1、 直方图(histogram)中的bins应如何理解
计算颜色直方图需要将颜色空间划分成若干个小的颜色区间,每个小区间成为直方图的一个bin。这个过程称为颜色量化(color quantization)。然后,通过计算颜色落在每个小区间内的像素数量可以得到颜色直方图。颜色量化有许多方法,例如向量量化、聚类方法或者神经网络方法。最为常用的做法是将颜色空间的各个分量(维度)均匀地进行划分。相比之下,聚类算法则会考虑到图像颜色特征在整个空间中的分布情况,从而避免出现某些bin中的像素数量非常稀疏的情况,使量化更为有效。另外,如果图像是RGB格式而直方图是HSV空间中的,我们可以预先建立从量化的RGB空间到量化的HSV空间之间的查找表(look-up table),从而加快直方图的计算过程。
上述的颜色量化方法会产生一定的问题。设想两幅图像的颜色直方图几乎相同,只是互相错开了一个bin,这时如果我们采用L1距离或者欧拉距离计算两者的相似度,会得到很小的相似度值。为了克服这个缺陷,需要考虑到相似但不相同的颜色之间的相似度。一种方法是采用二次式距离。另一种方法是对颜色直方图事先进行平滑过滤,即每个bin中的像素对于相邻的几个bin也有贡献。这样,相似但不相同颜色之间的相似度对直方图的相似度也有所贡献。
选择合适的颜色小区间(即直方图的bin)数目和颜色量化方法与具体应用的性能和效率要求有关。一般来说,颜色小区间的数目越多,直方图对颜色的分辨能力就越强。然而,bin的数目很大的颜色直方图不但会增加计算负担,也不利于在大型图像库中建立索引。而且对于某些应用来说,使用非常精细的颜色空间划分方法不一定能够提高检索效果,特别是对于不能容忍对相关图像错漏的那些应用。另一种有效减少直方图bin的数目的办法是只选用那些数值最大(即像素数目最多)的bin来构造图像特征,因为这些表示主要颜色的bin能够表达图像中大部分像素的颜色。
实验证明这种方法并不会降低颜色直方图的检索效果。事实上,由于忽略了那些数值较小的bin,颜色直方图对噪声的敏感程度降低了,有时会使检索效果更好。
2、cv.resize
cv2.resize(src,dsize,dst=None,fx=None,fy=None,interpolation=None)
scr:原图
dsize:输出图像尺寸
fx:沿水平轴的比例因子
fy:沿垂直轴的比例因子
interpolation:插值方法
interpolation – 插值方法。共有5种:
1)INTER_NEAREST – 最近邻插值法
2)INTER_LINEAR – 双线性插值法(默认)
3)INTER_AREA – 基于局部像素的重采样(resampling using pixel area relation)。对于图像抽取(image decimation)来说,这可能是一个更好的方法。但如果是放大图像时,它和最近邻法的效果类似。
4)INTER_CUBIC – 基于4×4像素邻域的3次插值法
5)INTER_LANCZOS4 – 基于8×8像素邻域的Lanczos插值
3、cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]]) #返回hist
第一个参数必须用方括号括起来。
第二个参数是用于计算直方图的通道,这里使用灰度图计算直方图,所以就直接使用第一个通道;
第三个参数是Mask,这里没有使用,所以用None。
第四个参数是histSize,表示这个直方图分成多少份(即多少个直方柱)。第二个例子将绘出直方图,到时候会清楚一点。
第五个参数是表示直方图中各个像素的值,[0.0, 256.0]表示直方图能表示像素值从0.0到256的像素。
最后是两个可选参数,由于直方图作为函数结果返回了,所以第六个hist就没有意义了(待确定) 最后一个accumulate是一个布尔值,用来表示直方图是否叠加。
二、算法设计
1、 简介
在图像识别中,常用的特征包括颜色特征、纹理特征、形状特征和空间关系特征等。本需求为判断图像是否相似,且需要发现细微差别,拟采用颜色特征。图像的颜色特征的表征方法包括颜色直方图、统计直方图、颜色集、 颜色矩 、聚合向量、 相关图 、直方图计算法。本方案采用颜色直方图方法。对图像进行处理使用的是opencv库。
2、 读取图片数据(数据预处理)
开始的时候考虑了常用设计方法使用cv2.resize对图像进行尺寸统一,方案一采用指定标准尺寸的方法,此方法误差最大,因为对每个图像都进行了像素补全,无疑增加了大量的新增像素。而后又采用了image2依照image1尺寸(image1.shape>image2.shape)进行补全的方法,精度较方案一有提升,但是依然存在新增干扰像素的问题。cv2.resize在补全图像像素时具有多种插值方法,在有些场景是非常有益的,但是在本需求中多此一举,还导致评判产生误差。在此方案中不统一图像尺寸,后续会采用归一化法解决尺寸问题。
3、 提取图像特征
颜色特征是人们去区别和感受不一样的事物能够体现出来的最为基础的视觉特征。在许多情况下,颜色是用来表达图像的最简单和最有效的特征,它更加体现出鲁棒性,一般情况下在平移,旋转,噪声,图像质量下降,尺寸 ,分辨率和方向不敏感,显示出非常强的鲁棒性。
颜色特征的提取都是在某个颜色空间中进行的。常用的色彩空间分别 RGB,CIELAB 和 HSV。 通常使用的颜色特征提取方法包括颜色直方图、累计直方图、颜色矩、颜色集和颜色聚合向量等方法。
(1)颜色直方图
基于颜色特征的图像检索技术里面使用的较为频繁的用来表示特征的就是颜色直方图,它所拥有的好处是不受图像旋转和平移变化的影响。但是它也有不足的地方,就是没有表现出颜色空间分布信息。
它表达出的是不一样的颜色在整个图像里面所占有的百分比。如果已知一个数字图像,计算出每一种颜色在这个图像里面占有的像素的数量,把第几个颜色的这个颜色值当作颜色直方图中的横坐标,把这个颜色出现的像素总点数占整个图像的总像素点数的比例当作颜色直方图中的纵坐标。
图像特征的统计直方图在数学表达上来看是一个 1-D 的离散函数,即:
​​《python+opencv判断两个图像是否相似(附代码)》
式中: k-图像的特征取值
L-特征可取值个数,是图像中具有特征值为 k 的像像素个数
N-图像像素的总数
(2)累计直方图
在图像里面的颜色特征并不能够去获得每一个可能的颜色值得情况下,上述方法所获得的颜色直方图里面将会有许多的零值。那么这些零值将会对直方图的相交运算造成一定的影响。为了解决上面所提到的问题,学者们从颜色直方图演化的基础上演化出了累计直方图。
累计直方图也是一个 1-D 的离散函数,即:
​​《python+opencv判断两个图像是否相似(附代码)》
式中:k-图像的特征取值
L-特征可取值个数,是图像中具有特征值为 k 的像素的个数
N-图像像素的总数
(3)本方案利用opencv中的calcHist()方法
获取其直方图数据,返回的结果是一个列表,使用matplotlib,画出了这两张图的直方图数据图 。
​​《python+opencv判断两个图像是否相似(附代码)》
图1 milk1
​​《python+opencv判断两个图像是否相似(附代码)》
图2 milk2
​​《python+opencv判断两个图像是否相似(附代码)》
图3 milk1与milk2对比图
​​《python+opencv判断两个图像是否相似(附代码)》
图 4 颜色直方图(红线为milk1,蓝线为milk2)
4、 相似度计算
想要实现效果良好的图像检索,其中非常关键的一点就是判断出待检索的目标图像和数据库里面的图像间的相似度。很明显地,选取一种比较好的特征相似度计算法则对于图像检索的速度和精确度的影响都是特别大的。常用的相似度计算方法包括欧氏距离、马氏距离、直方图相交法和二次式距离等。
(1) 欧氏距离
当下,很大的一部分的图像检索系统的相似度计算都是使用到欧式距离函数来进行衡量的,欧式距离是最常见的距离测度量函数,日常理解的距离就可以用欧式距离来度量。欧式距离具体定义如下:
​​《python+opencv判断两个图像是否相似(附代码)》
欧式距离的优点是容易操作,有很明白的物理的含义,计算它的复杂度较小。但是,由于采用欧式距离时提前设想了图像特征的每一个分量相互是正交的并且是没有关联的,在并且维数上来说它们所占的重要程度的比例是差不多一样的,所以想要很好地去仿效人们所拥有的所有感知中包含的视觉内容是具有一定难度的。
(2) 计算重合度的方法
​​《python+opencv判断两个图像是否相似(附代码)》
其中gi和si是分别指两条曲线的第i个点,最后计算得出的结果就是就是其相似程度。这种方法有一个明显的弱点,就是他是按照颜色的全局分布来看的,无法描述颜色的局部分布和色彩所处的位置。假如一张图片以蓝色为主,内容是一片蓝天,而另外一张图片也是蓝色为主,但是内容却是一个女生穿了蓝色裙子,那么这个算法也很可能认为这两张图片的相似的。缓解这个弱点有一个方法就是利用Image的crop方法把图片等分,然后再分别计算其相似度,最后综合考虑。
(3) 计算颜色直方图百分比差异度
因为在数据预处理时本方案没有将图像尺寸统一化,所以需要将图像总像素的因素考虑进去。先计算出image1和image2的总像素个数pix1和pix2。通过统计两个图像的不同灰度值在图像中的占比之间的差异来表征图像的差异程度diff:
​​《python+opencv判断两个图像是否相似(附代码)》
其中:​​《python+opencv判断两个图像是否相似(附代码)》为image1在灰度值为i时的直方图函数值(即像素个数)。
5、实验结果
本方案采用方案一为计算颜色直方图百分比差异度的方法,上述图像计算出的差异度为0.00203224,方案二为利用crop方法把图像等分后再进行差异度比较的方法获得的差异度为0.00028889。从这个结果可以看出,若要尽可能发现图像相似,则可采用弱化差异的方案二,但是我们的需求为尽可能发现差异,故采用方案一。
三、讨论
图像特征非常多,识别方法也是多张多样,本方案只是针对该需求设计了一个简洁的方案,有兴趣深入探讨的欢迎留言一起讨论。

    原文作者:Illyasviel_s
    原文地址: https://blog.csdn.net/qq_38293122/article/details/90296270
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞