简述
前段时间写了篇博文 哈希算法实现图像相似度比较(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
实例演示
两张原图如下:
图一
图二
为了便于观察,将两个图像每行像素值平均值在折线图上进行描绘,更能直观的比较均值的波动性,既图像的相似度。
方差如下
演示程序完整代码如下
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()
以上仅个人见解,不足之处望大家批评指正!
如果觉得《pythonopencv人脸相似度_图像相似度算法的个人见解(pythonopencv)-Go语言中文社区...》对你有帮助,请点赞、收藏,并留下你的观点哦!