1. 引入
参考1中介绍了相似图片搜索的基本原理,借助milvus(参考2)这样的相似性搜索引擎,我们可以非常快速的实现相似性搜索。
但实现搜索之前,需要把图片转换为特征向量。本文介绍的均值哈希,就是图片的一种特征。
2. 均值哈希的计算过程
- 读入图片并转换为灰度图
import numpy as np
import cv2
img = cv2.imread('Alyson_Hannigan_200512.jpg', cv2.IMREAD_GRAYSCALE)# IMREAD_GRAYSCALE, IMREAD_COLOR
图片来自于参考4。
- 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,得到的哈希值长度也不同。
- 求取灰度值均值
ave = np.mean(img2)
- 得到二进制哈希值
遍历灰度图中的每一个像素,如果像素值大于灰度均值,则置为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位的哈希值。
- 二进制字符串转换为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. 均值哈希的优缺点
- 优点
- 简单、计算快
- 等比例缩放后,图片的均值哈希值几乎不变
- 因为最终resize后,均值与各个像素值都几乎不变
- 线性增加或减少亮度,图片的均值哈希值都不变
- 因为各个像素值与均值的差值都几乎不变
- 缺点
非线性的对图片增加或减少亮度,会导致均值哈希值有较大的变化。这里说的非线性,就是指不对所有像素值进行相同倍数的增加/减少亮度,而是比如对[0,120]灰度值的增加50,对[121,255]的减少20,这样的变化,导致各个像素值与均值的差值变化很大。比如对图片进行伽马矫正后,其均值哈希值就变化很大了。
5. 总结
均值哈希算法,average hash,又叫aHash,是最简单的感知哈希算法。
本文给出了计算过程源码,也分析了其优缺点。
本文后续还将继续发布更复杂的哈希算法过程。
关于更多的相似图片搜索方法,见参考3. 本文用到的方法和更多细节,见参考4.