概述
一般情况下, 图片相似算法分为三种
- 均值Hash算法
- 差异值hash算法
- 感知hash算法
其实三个算法差不多. 我们以均值hash算法为例, 算法的步骤如下:
- 缩放为n*n的图片
- 去色, 获取灰度图
- 得到hash指纹
- 比较hash指纹的汉明距离, 得到相似值
上面算法的不同, 主要是得到hash指纹的算法不同
均值hash算法
我们举例说明. 原图如下:
![804209a011c5aa4e7033f792e64d9f50.png](https://i-blog.csdnimg.cn/blog_migrate/5bb62d4a5e7889934d29350345ee4f59.jpeg)
缩放为8*8的图片
代码:
img = cv2.resize(img, (8, 8), interpolation=cv2.INTER_CUBIC)复制代码
缩放结果
![3270f72ea078b4a4fff8483cbe498bfb.png](https://i-blog.csdnimg.cn/blog_migrate/e4ffac0265dbb89d78c504b26d81d87e.jpeg)
去色
代码
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)复制代码
结果:
![f32698aca545134a57994b6621982132.png](https://i-blog.csdnimg.cn/blog_migrate/8f073965e1f8ee04518215b3056cd3ee.jpeg)
计算灰度平均值
# 计算灰度平均值 for i in range(8): for j in range(8): s = s + gray_img[i, j] avg = s / 64复制代码
计算结果为176
计算Hash指纹
计算方法为, 如果该点灰度值大于平均灰度值, 这为1, 否则为0, 代码如下:
# 如果值大于灰度值, 则为1, 否则为0. 生成hash指纹 for i in range(8): for j in range(8): if gray_img[i, j] > avg: hash_str = hash_str + '1' else: hash_str = hash_str + '0'复制代码
计算汉明距离
汉明距离: 在信息论中,两个等长字符串之间的汉明距离(英语:Hamming distance)是两个字符串对应位置的不同字符的个数。 代码:
def cmp_hash(hash_1, hash_2): # 计算汉明距离 n = 0 if len(hash_1) != len(hash_2): return -1 for i in range(len(hash_1)): if hash_1[i] != hash_2[i]: n = n + 1 return n复制代码
差异值hash算法
前面缩放, 置灰, 计算汉明距离等和平均值hash算法一样, 区别在于计算hash指纹的算法不同. 该处算法为: 如果前一个像素大于后一个像素的灰度值, 则为1, 否则为0. 完整的算法如下:
# 差值感应hashdef b_hash(img): # 缩放到8*8的图片 img = cv2.resize(img, (9, 8), interpolation=cv2.INTER_CUBIC) # 得到灰度图 gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) hash_str = '' # 如果前一个像素比后一个大, 则为1, 否则为0. 生成hash指纹 for i in range(8): for j in range(8): if gray_img[i, j] > gray_img[i, j + 1]: hash_str = hash_str + '1' else: hash_str = hash_str + '0' return hash_str复制代码
感知Hash算法
前面两种比较图片相似的算法很好理解. 感应Hash算法的思想与之不同. 我们换一种角度来看待一张图片. 一个图片其实就是二维的信息图谱, 有各种频率的变化, 频率高的地方代表颜色的变换比较大, 例如轮廓部分. 我们可以利用DCT变换(离散余弦变换)得到频域图. 比较低频部分(为什么要比较低频部分?) 是否相似就可以了.
原图还是上面的原图. 我们先进行缩放, 缩放为32*32的部分
![e90542b730363eb936b1e27ccef5ae69.png](https://i-blog.csdnimg.cn/blog_migrate/c30bad559c3fa502a9120dcc9c8d37e3.jpeg)
灰度处理
![d86605e9aa45bf964fd8c4918c7bfc10.png](https://i-blog.csdnimg.cn/blog_migrate/3c83280732f716fb89310102ec937e8f.jpeg)
进行DCT变换
![48b792535c957cd5649765757611f544.png](https://i-blog.csdnimg.cn/blog_migrate/ae789f4c836315363c3cfe00bf506b06.jpeg)
我们拿到左上角的8*8的区域, 根据平均值hash算法比较这个灰度图的汉明距离
完整的代码如下:
# 感知hashdef p_hash(img): # 缩放到32 * 32 img = cv2.resize(img, (32, 32), interpolation=cv2.INTER_CUBIC) cv2.imwrite("bb.jpg