文章给出了两种方法,可以计算两张图片的相似度
参考文章:https://blog.csdn.net/xundh/article/details/78255037
方法一:
from PIL import Image
import glob
import os
class CompareImage():
def calculate(self, image1, image2):
g = image1.histogram()
s = image2.histogram()
assert len(g) == len(s), "error"
data = []
for index in range(0, len(g)):
if g[index] != s[index]:
data.append(1 - abs(g[index] - s[index]) / max(g[index], s[index]))
else:
data.append(1)
return sum(data) / len(g)
def split_image(self, image, part_size):
pw, ph = part_size
w, h = image.size
sub_image_list = []
assert w % pw == h % ph == 0, "error"
for i in range(0, w, pw):
for j in range(0, h, ph):
sub_image = image.crop((i, j, i + pw, j + ph)).copy()
sub_image_list.append(sub_image)
return sub_image_list
def compare_image(self, file_image1, file_image2, size=(256, 256), part_size=(64, 64)):
'''
'file_image1'和'file_image2'是传入的文件路径
可以通过'Image.open(path)'创建'image1' 和 'image2' Image 对象.
'size' 重新将 image 对象的尺寸进行重置,默认大小为256 * 256 .
'part_size' 定义了分割图片的大小.默认大小为64*64 .
返回值是 'image1' 和 'image2'对比后的相似度,相似度越高,图片越接近,达到1.0说明图片完全相同。
'''
image1 = Image.open(file_image1)
image2 = Image.open(file_image2)
#调用"split_image"函数,把图片切割,并分别放在数组中
img1 = image1.resize(size).convert("RGB")
sub_image1 = self.split_image(img1, part_size)
img2 = image2.resize(size).convert("RGB")
sub_image2 = self.split_image(img2, part_size)
sub_data = 0
#把切割好的照片,从数组中一一对应的提出来,传入"calculate"函数,做直方图比较
for im1, im2 in zip(sub_image1, sub_image2):
sub_data += self.calculate(im1, im2)
x = size[0] / part_size[0]
y = size[1] / part_size[1]
pre = round((sub_data / (x * y)), 6)
# print(str(pre * 100) + '%')
if pre<0.3:
os.remove(fp[k])
print('Compare the image result is: ' + str(pre))
return pre
fp = glob.glob('img2/'+'/*jpg')
for k,i in enumerate(fp):
# print("对比原图为:",fp[0])
# print("对比对象为:",fp[k])
compare_image = CompareImage()
compare_image.compare_image(fp[0], fp[k])
方法二:
#encoding:utf-8
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 最简单的以灰度直方图作为相似比较的实现
def classify_gray_hist(image1,image2,size = (256,256)):
# 先计算直方图
# 几个参数必须用方括号括起来
# 这里直接用灰度图计算直方图,所以是使用第一个通道,
# 也可以进行通道分离后,得到多个通道的直方图
# bins 取为16
image1 = cv2.resize(image1,size)
image2 = cv2.resize(image2,size)
hist1 = cv2.calcHist([image1],[0],None,[256],[0.0,255.0])
hist2 = cv2.calcHist([image2],[0],None,[256],[0.0,255.0])
# 可以比较下直方图
plt.plot(range(256),hist1,'r')
plt.plot(range(256),hist2,'b')
#plt.show()
# 计算直方图的重合度
degree = 0
for i in range(len(hist1)):
if hist1[i] != hist2[i]:
degree = degree + (1 - abs(hist1[i]-hist2[i])/max(hist1[i],hist2[i]))
else:
degree = degree + 1
degree = degree/len(hist1)
return degree
# 计算单通道的直方图的相似值
def calculate(image1,image2):
hist1 = cv2.calcHist([image1],[0],None,[256],[0.0,255.0])
hist2 = cv2.calcHist([image2],[0],None,[256],[0.0,255.0])
# 计算直方图的重合度
degree = 0
for i in range(len(hist1)):
if hist1[i] != hist2[i]:
degree = degree + (1 - abs(hist1[i]-hist2[i])/max(hist1[i],hist2[i]))
else:
degree = degree + 1
degree = degree/len(hist1)
return degree
# 通过得到每个通道的直方图来计算相似度
def classify_hist_with_split(image1,image2,size = (256,256)):
# 将图像resize后,分离为三个通道,再计算每个通道的相似值
image1 = cv2.resize(image1,size)
image2 = cv2.resize(image2,size)
sub_image1 = cv2.split(image1)
sub_image2 = cv2.split(image2)
sub_data = 0
for im1,im2 in zip(sub_image1,sub_image2):
sub_data += calculate(im1,im2)
sub_data = sub_data/3
return sub_data
# 平均哈希算法计算
def classify_aHash(image1,image2):
image1 = cv2.resize(image1,(8,8))
image2 = cv2.resize(image2,(8,8))
gray1 = cv2.cvtColor(image1,cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(image2,cv2.COLOR_BGR2GRAY)
hash1 = getHash(gray1)
hash2 = getHash(gray2)
return Hamming_distance(hash1,hash2)
def classify_pHash(image1,image2):
image1 = cv2.resize(image1,(32,32))
image2 = cv2.resize(image2,(32,32))
gray1 = cv2.cvtColor(image1,cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(image2,cv2.COLOR_BGR2GRAY)
# 将灰度图转为浮点型,再进行dct变换
dct1 = cv2.dct(np.float32(gray1))
dct2 = cv2.dct(np.float32(gray2))
# 取左上角的8*8,这些代表图片的最低频率
# 这个操作等价于c++中利用opencv实现的掩码操作
# 在python中进行掩码操作,可以直接这样取出图像矩阵的某一部分
dct1_roi = dct1[0:8,0:8]
dct2_roi = dct2[0:8,0:8]
hash1 = getHash(dct1_roi)
hash2 = getHash(dct2_roi)
return Hamming_distance(hash1,hash2)
# 输入灰度图,返回hash
def getHash(image):
avreage = np.mean(image)
hash = []
for i in range(image.shape[0]):
for j in range(image.shape[1]):
if image[i,j] > avreage:
hash.append(1)
else:
hash.append(0)
return hash
# 计算汉明距离
def Hamming_distance(hash1,hash2):
num = 0
for index in range(len(hash1)):
if hash1[index] != hash2[index]:
num += 1
return num
if __name__ == '__main__':
img1 = cv2.imread('img2/t1.jpg')
#cv2.imshow('img1',img1)
img2 = cv2.imread('img2/t5.jpg')
#cv2.imshow('img2',img2)
degree = classify_gray_hist(img1,img2)
#degree = classify_hist_with_split(img1,img2)
#degree = classify_aHash(img1,img2)
#degree = classify_pHash(img1,img2)
print( degree)
#cv2.waitKey(0)