图像相似度算法的个人见解(python&opencv)

简述

前段时间写了篇博文 哈希算法实现图像相似度比较(Python&OpenCV) ,使用简单的哈希算法进行图像相似度判断。但是在实践中该算法达不到预期的效果:

  • 图像缩放8*8大小,图片信息内容严重丢失
  • 64位Hash值对比,计算出结果在[0,64]之内,很难大程度区分图像特征

因为存在以上问题,所以想自己尝试改进一下算法,尽可能提高算法的准确性。

算法逻辑

缩放图片

将需要处理的图片所放到指定尺寸,缩放后图片大小由图片的信息量和复杂度决定。譬如,一些简单的图标之类图像包含的信息量少,复杂度低,可以缩放小一点。风景等复杂场景信息量大,复杂度高就不能缩放太小,容易丢失重要信息。根据自己需求,弹性的缩放。在效率和准确度之间维持平衡。

灰度处理

通常对比图像相似度和颜色关系不是很大,所以处理为灰度图,减少后期计算的复杂度。如果有特殊需求则保留图像色彩。

计算平均值

此处开始,与传统的哈希算法不同:分别依次计算图像每行像素点的平均值,记录每行像素点的平均值。每一个平均值对应着一行的特征。

计算方差

对得到的所有平均值进行计算方差,得到的方差就是图像的特征值。方差可以很好的反应每行像素特征的波动,既记录了图片的主要信息。

比较方差

经过上面的计算之后,每张图都会生成一个特征值(方差)。到此,比较图像相似度就是比较图像生成方差的接近成程度。
一组数据方差的大小可以判断稳定性,多组数据方差的接近程度可以反应数据波动的接近程度。我们不关注方差的大小,只关注两个方差的差值的大小。方差差值越小图像越相似!

代码实现

使用python&Opencv对上述算法进行实现

获取图像每行像素平均值

#获取每行像素平均值  
def getdiff(img):
    #定义边长
    Sidelength=30
    #缩放图像
    img=cv2.resize(img,(Sidelength,Sidelength),interpolation=cv2.INTER_CUBIC)
    #灰度处理
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    #avglist列表保存每行像素平均值
    avglist=[]
    #计算每行均值,保存到avglist列表
    for i in range(Sidelength):
        avg=sum(gray[i])/len(gray[i])
        avglist.append(avg)
    #返回avglist平均值   

计算图像特征值(方差)

#计算方差
def getss(list):
    #计算平均值
    avg=sum(list)/len(list)
    #定义方差变量ss,初值为0
    ss=0
    #计算方差
    for l in list:
        ss+=(l-avg)*(l-avg)/len(list)   
    #返回方差
    return ss

实例演示

两张原图如下:
图一
图像相似度算法的个人见解(python&opencv)_第1张图片
图二
图像相似度算法的个人见解(python&opencv)_第2张图片

为了便于观察,将两个图像每行像素值平均值在折线图上进行描绘,更能直观的比较均值的波动性,既图像的相似度。
图像相似度算法的个人见解(python&opencv)_第3张图片

方差如下

图像相似度算法的个人见解(python&opencv)_第4张图片
演示程序完整代码如下

import cv2
import matplotlib.pyplot as plt 

#计算方差
def getss(list):
    #计算平均值
    avg=sum(list)/len(list)
    #定义方差变量ss,初值为0
    ss=0
    #计算方差
    for l in list:
        ss+=(l-avg)*(l-avg)/len(list)   
    #返回方差
    return ss

#获取每行像素平均值  
def getdiff(img):
    #定义边长
    Sidelength=30
    #缩放图像
    img=cv2.resize(img,(Sidelength,Sidelength),interpolation=cv2.INTER_CUBIC)
    #灰度处理
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    #avglist列表保存每行像素平均值
    avglist=[]
    #计算每行均值,保存到avglist列表
    for i in range(Sidelength):
        avg=sum(gray[i])/len(gray[i])
        avglist.append(avg)
    #返回avglist平均值   
    return avglist

#读取测试图片
img1=cv2.imread("F:\\test\\walk01.jpg")
diff1=getdiff(img1)
print('img1:',getss(diff1))

#读取测试图片
img11=cv2.imread("F:\\test\\walk03.jpg")
diff11=getdiff(img11)
print('img11:',getss(diff11))


x=range(30)  

plt.figure("avg")  
plt.plot(x,diff1,marker="*",label="$walk01$") 
plt.plot(x,diff11,marker="*",label="$walk03$") 
plt.title("avg")
plt.legend()
plt.show()


cv2.waitKey(0)
cv2.destroyAllWindows()

以上仅个人见解,不足之处望大家批评指正!

你可能感兴趣的:(计算机视觉)