相似图片检测:dHash的Python实现

基本概念

在某些情况下,我们需要检测图片之间的相似性,我们可能需要对图片进行去重、标记盗版等操作。
感知哈希算法是一类算法的总称,包括aHash、pHash、dHash。
·aHash:平均值哈希。速度比较快,但不精确。
·pHash:感知哈希。精确度较高,但速度慢。
·dHash:差异值哈希。精确度较高且速度非常快。

一、相似图片检测步骤

1.分别计算两张图片的dHash值
2.通过dHash值计算两张图片的汉明距离(Hamming Distance),通过汉明距离的大小,判断两张图片的相似度。

二、dHash计算

1.缩放图片
原图的分辨率一般非常高,一张240240的图片,就有57,600个像素点,每一个像素点保存一个RGB的值,信息量非常大。因此,将图片缩放,隐藏细节部分。建议缩放为98,宽度为9是有利于我们转换为hash值。

image1=np.array(image1.resize((9, 8), Image.LANCZOS).convert('L'), 'f')
image2=np.array(image2.resize((9, 8), Image.LANCZOS).convert('L'), 'f')

在image.resize中加上Image.LANCZOS参数,会对所有可以影响输出像素的输入像素进行高质量重采样滤波。

2.灰度化
将RGB图像转换为一个0到255的整数表示的灰度值,这样将三维化的比较简化为了一维的比较。上述代码中convert(‘L’)将图像转换为灰度图像。
具体转换方法参考博文

3.差异计算
差异值是通过计算每行相邻像素的强度对比得出的。我们的图片为9*8的分辨率,那么就有8行,每行9个像素。差异值是每行分别计算的,也就是第二行的第一个像素不会与第一行的任何像素比较。每一行有9个像素,那么就会产生8个差异值,所以8行像素共可以得出64个值,因此此时哈希值为长度是64的0-1序列。
如果前一个像素的颜色强度大于第二个像素,那么差异值就设置为True(也就是1),如果不大于第二个像素,就设置为False(也就是0)。

def dHash(image):
    image_new=image
    #计算均值
    avreage = np.mean(image_new)
    hash=[]
    #每行前一个像素大于后一个像素为1,相反为0,生成哈希
    for i in range(8):
        for j in range(8):
            if image[i,j]>image[i,j+1]:
                hash.append(1)
            else:
                hash.append(0)
    return hash

计算汉明距离

汉明距离表示将不同的地方修改成相同的时候需要多少个步骤。
dHash中的汉明距离是通过计算差异值的修改位数。我们的差异值是用0、1表示的,可以看做二进制。二进制0110与1111的汉明距离为2。
我们将hash列表逐一进行比较,累加不同的位数,最后计算出的位数即为汉明距离。

#计算汉明距离
def Hamming_distance(hash1,hash2):
    num = 0
    for index in range(len(hash1)):
        if hash1[index] != hash2[index]:
            num += 1
    return num

一般来说,汉明距离小于5,基本就是同一张图片。大家可以根据自己的实际情况,判断汉明距离临界值为多少。

完整代码

from PIL import Image
import os
import numpy as np
import time

#差异哈希算法
def dHash(image):
    image_new=image
    #计算均值
    avreage = np.mean(image_new)
    hash=[]
    #每行前一个像素大于后一个像素为1,相反为0,生成哈希
    for i in range(8):
        for j in range(8):
            if image[i,j]>image[i,j+1]:
                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__":
    image1 = Image.open('0008.png')
    image2 = Image.open('00010.png')
    #缩小尺寸并灰度化
    start = time.time()
    image1=np.array(image1.resize((9, 8), Image.LANCZOS).convert('L'), 'f')
    image2=np.array(image2.resize((9, 8), Image.LANCZOS).convert('L'), 'f')
    hash1 = dHash(image1)
    hash2 = dHash(image2)
    dist = Hamming_distance(hash1, hash2)
    end = time.time()
    #将距离转化为相似度
    similarity = 1 - dist * 1.0 / 64
    print('dist is '+'%d' % dist)
    print('similarity is ' +'%f' % similarity)
    print('time is  '+ '%f'%(end-start))
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值