美文网首页
用感知哈希算法找到相似图像

用感知哈希算法找到相似图像

作者: Byte猫 | 来源:发表于2019-05-10 15:13 被阅读0次

    在谷歌图片搜索中, 用户可以上传一张图片, 谷歌显示因特网中与此图片相同或者相似的图片.



    实现这种功能的关键技术叫做"感知哈希算法"(Perceptual Hash Algorithm), 意思是为图片生成一个指纹(字符串格式), 两张图片的指纹越相似, 说明两张图片就越相似。
    感知哈希算法是一类算法的总称,包括aHash、pHash、dHash。顾名思义,感知哈希不是以严格的方式计算Hash值,而是以更加相对的方式计算哈希值,因为“相似”与否,就是一种相对的判定。

    • aHash:平均值哈希。速度比较快,但是常常不太精确。
    • pHash:感知哈希。精确度比较高,但是速度方面较差一些。
    • dHash:差异值哈希。精确度较高,且速度也非常快。

    感知哈希算法之dHash

    1、执行步骤

    step 1:缩小图像尺寸
    把图片缩放到非常小。这一步的作用是去除各种图片尺寸和图片比例的差异, 只保留结构、明暗等基本信息
    step 2:转为灰度图片
    缩放后的图片,细节已经被隐藏,信息量已经变少。但是还不够,因为它是彩色的,由RGB值组成。白色表示为(255,255,255),黑色表示为(0,0,0),值越大颜色越亮,越小则越暗。每种颜色都由3个数值组成,也就是红、绿、蓝的值 。如果直接使用RGB值对比颜色强度差异,相当复杂,因此我们转化为灰度值——只由一个0到255的整数表示灰度。这样的话就将三维的比较简化为了一维比较。
    step 3:差异计算
    差异值是通过计算每行相邻像素的强度对比得出的。我们的图片为9*8的分辨率,那么就有8行,每行9个像素。差异值是每行分别计算的,也就是第二行的第一个像素不会与第一行的任何像素比较。每一行有9个像素,那么就会产生8个差异值,这也是为何我们选择9作为宽度,因为8bit刚好可以组成一个byte,方便转换为16进制值。
    如果前一个像素的颜色强度大于第二个像素,那么差异值就设置为True(也就是1),如果不大于第二个像素,就设置为False(也就是0)。
    step 4:转换为hash值
    将差异值数组中每一个值看做一个bit,每8个bit组成为一个16进制值,将16进制值连接起来转换为字符串,就得出了最后的dHash值
    step 5:对比图片指纹
    得到图片的指纹后, 就可以对比不同的图片的指纹, 计算出64位中有多少位是不一样的. 如果不相同的数据位数不超过5, 就说明两张图片很相似, 如果大于10, 说明它们是两张不同的图片

    2、代码实现

    def dHash(image, hash_size = 8):
        '''
        感知hash算法
        '''
        image = image.convert('L').resize((hash_size+1, hash_size))
        pixels = list(image.getdata())
    
        # 比较相邻像素
        difference = []
        for row in range(hash_size):
            for col in range(hash_size):
                pixel_left = image.getpixel((col, row))
                pixel_right = image.getpixel((col + 1, row))
                difference.append(pixel_left > pixel_right)
        
        # 转化为16进制(每个差值为一个bit,每8bit转为一个16进制)
        decimal_value = 0
        hash_string = ""
        for index, value in enumerate(difference):    
            if value:  # value为0, 不用计算
                decimal_value += value * (2 ** (index % 8))   
            if index % 8 == 7:  # 每8位的结束        
                hash_string += str(hex(decimal_value)[2:].rjust(2, "0"))  # 不足2位以0填充。0xf=>0x0f        
                decimal_value = 0
    
        return hash_string
    

    距离比较见距离度量中的汉明距离
    另外两种感知hash算法

    相关文章

      网友评论

          本文标题:用感知哈希算法找到相似图像

          本文链接:https://www.haomeiwen.com/subject/nieaoqtx.html