图片相似度对比

文章给出了两种方法,可以计算两张图片的相似度
参考文章: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)

  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值