相似图片搜索中的均值哈希(aHash)

831 阅读3分钟

原文:blog.csdn.net/ybdesire/ar…

1. 引入

参考1中介绍了相似图片搜索的基本原理,借助milvus(参考2)这样的相似性搜索引擎,我们可以非常快速的实现相似性搜索。

但实现搜索之前,需要把图片转换为特征向量。本文介绍的均值哈希,就是图片的一种特征。

2. 均值哈希的计算过程

  1. 读入图片并转换为灰度图
import numpy as np
import cv2
img = cv2.imread('Alyson_Hannigan_200512.jpg', cv2.IMREAD_GRAYSCALE)# IMREAD_GRAYSCALE, IMREAD_COLOR

图片来自于参考4。

  1. resize图像大小

需要讲图片统一转换为固定的size,这样不同大小的图片才能得到固定size的哈希值

img2 = cv2.resize(img, (8, 8), interpolation=cv2.INTER_AREA)

resize这里使用不同的interpolation方法,得到的结果也会有些区别,可选值为

  • INTER_NEAREST – a nearest-neighbor interpolation.
  • INTER_LINEAR – a bilinear interpolation (used by default)
  • INTER_AREA – resampling using pixel area relation. ...
  • INTER_CUBIC – a bicubic interpolation over 4×4 pixel neighborhood.
  • INTER_LANCZOS4 – a Lanczos interpolation over 8×8 pixel neighborhood.

这里统一将图片大小固定为8x8,调整这个size,得到的哈希值长度也不同。

  1. 求取灰度值均值
ave = np.mean(img2)
  1. 得到二进制哈希值

遍历灰度图中的每一个像素,如果像素值大于灰度均值,则置为1,否则置为0.

hash_bin = ''
for i in range(img2.shape[0]):
    for j in range(img2.shape[1]):
        value = img2[i][j]
        if value>ave:
            hash_bin+='1'
        else:
            hash_bin+='0'
print(hash_bin)#1110011111000111110010111100001011000100111101001111100011101000
print(len(hash_bin))#64

从这里可以看到,因为图片大小被固定为8x8,则最终有64位的哈希值。

  1. 二进制字符串转换为16进制字符串

使用下面的程序,可以将“二进制字符串转换为16进制字符串”:

hash_hex = format(int(hash_bin, 2),'x')# bin to hex
hash_hex.rjust(16,'0')# fixed to 16 hex values with zero pending
print(hash_hex)# e7c7cbc2c4f4f8e8
print(len(hash_hex))# 16

最终计算得到的“e7c7cbc2c4f4f8e8”,就是均值哈希值。

可以根据欧氏距离等距离计算方式,和其他图片的均值哈希进行对比,找到最相似(距离最近)的图片。

3. 两个均值哈希值的距离计算

如下代码,给定两个哈希值16进制字符串,计算其汉明距离:

# hex string 
ahash_hex_1 = "e7c7cbc2c4f4f8e8"
ahash_hex_2 = "8a0303f6df3ec8cd"
scale = 16
# convert hex to binary 
ahash_bin_1 = bin(int(ahash_hex_1, scale)).zfill(64) # fixed 64 bit for this paper
ahash_bin_2 = bin(int(ahash_hex_2, scale)).zfill(64) 
# binary difference calculation
diff = 0
for i in range(len(ahash_bin_1)):
    b1 = ahash_bin_1[i]
    b2 = ahash_bin_2[i]
    if b1!=b2:
        diff+=1
print(diff) #27       

从这里可以得到,两个哈希值的区别(距离)为27。

4. 均值哈希的优缺点

  1. 优点
  • 简单、计算快
  • 等比例缩放后,图片的均值哈希值几乎不变
    • 因为最终resize后,均值与各个像素值都几乎不变
  • 线性增加或减少亮度,图片的均值哈希值都不变
    • 因为各个像素值与均值的差值都几乎不变
  1. 缺点

非线性的对图片增加或减少亮度,会导致均值哈希值有较大的变化。这里说的非线性,就是指不对所有像素值进行相同倍数的增加/减少亮度,而是比如对[0,120]灰度值的增加50,对[121,255]的减少20,这样的变化,导致各个像素值与均值的差值变化很大。比如对图片进行伽马矫正后,其均值哈希值就变化很大了。

5. 总结

均值哈希算法,average hash,又叫aHash,是最简单的感知哈希算法。

本文给出了计算过程源码,也分析了其优缺点。

本文后续还将继续发布更复杂的哈希算法过程。

关于更多的相似图片搜索方法,见参考3. 本文用到的方法和更多细节,见参考4.

6. 参考

  1. www.ruanyifeng.com/blog/2011/0…
  2. milvus.io/
  3. www.ruanyifeng.com/blog/2013/0…
  4. www.hackerfactor.com/blog/index.…