关于本站
1、基于Django+Bootstrap开发
2、主要发表本人的技术原创博客
3、本站于 2015-12-01 开始建站
上篇博文主要讲的是用dHash均值哈希感知算法进行以图搜图。《以图搜图(一):Python实现dHash算法》
现有3张图片,用前面的dHash均值哈希感知算法计算哈希值。
1.jpg
2.jpg:1.jpg旋转90度
3.jpg:1.jpg旋转5度
dHash均值哈希感知算法计算结果:
1.jpg:270f078fd1fdffff
2.jpg:f8f0e1f0eaefcfff
3.jpg:e70f058f81f1f1ff
1.jpg和2.jpg(旋转90度)的汉明距离是13;1.jpg和3.jpg(旋转5度)的汉明距离是5。(汉明距离是两个字符串对应位置对比,总共不同的个数)
很明显,旋转了90度汉明距离变得很大。在dHash算法中,它们是不同的。而我们肉眼可以看出其实是一样的。前面说过dHash算法比较较真、比较敏感。若要处理一定程度的变形,得要调整一下这个算法。
pHash算法就是基于dHash算法调整而来的,用第一次计算得到的值进行余弦变换。所以命名为余弦哈希感知算法。它可以识别变形程度在25%以内的图片。
大致原理和处理过程是这样:
把图片缩小到32x32的尺寸,并转为灰度模式。
对图片进行二维余弦变换,得到下图。高亮的数据集中在左上角。
主要特征数据就集中在图片左上角的区域,我们去左上角的8x8区域。对这个区域求均值哈希值(参考上一篇的方法)
像素值 = [
185.6844940185547, 265.2283630371094, 295.5816650390625, 280.8827209472656, 194.1041259765625, 202.2652130126953, 219.96258544921875, 292.495361328125, 178.82818603515625, 233.83262634277344, 273.0287170410156, 149.4671630859375, 168.61572265625, 196.33615112304688, 203.49485778808594, 212.27850341796875, 132.66966247558594, 129.8767852783203, 158.14573669433594, 130.48318481445312, 183.61569213867188, 163.86473083496094, 130.6190643310547, 97.9937515258789, 62.876373291015625, 139.2428436279297, 104.12135314941406, 84.58297729492188, 65.413818359375, 50.1722297668457, 32.628944396972656, 15.74152660369873, 291.3837890625, 352.196044921875, 362.098388671875, 359.0899353027344, 435.290771484375, 385.5643310546875, 471.4906005859375, 341.85638427734375, 364.1877136230469, 376.7964172363281, 379.27386474609375, 259.00885009765625, 311.5459289550781, 309.8655700683594, 277.6601867675781, 237.609375, 203.56141662597656, 181.1670684814453, 178.15585327148438, 250.11349487304688, 233.9508514404297, 220.26385498046875, 179.6764678955078, 163.84234619140625, 129.07568359375, 149.32899475097656, 126.58440399169922, 104.8794174194336, 85.072265625, 61.521141052246094, 42.12876510620117, 21.413537979125977
]
平均值 = 204.3717007189989
得到这个平均值之后,再和每个像素对比。像素值大于平均值的标记成1,小于或等于平均值的标记成0。组成64个数字的字符串(看起来也是一串二进制的)。
降噪结果 = [
0, 1, 1, 1, 0, 0, 1, 1,
0, 1, 1, 0, 0, 0, 0, 1,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1,
0, 0, 0, 1, 1, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0]
64位字符串 = '0111001101100001000000000000000011111111111111110001110000000000'
每4个数字,由2进制转成16进制,得到哈希值 = '73610000ffff1c00'
Python代码如下:
#coding:utf-8 """ author: Haddy Yang(杨仕航) date: 2016-04-05 filename: opencv_phash.py decription: pHash算法(感知哈希算法)实现 把图片转成一个Hash值 测试环境:python2.7 win7 numpy1.11 OpenCV2.4.12 """ #numpy是OpenCV必须的科学计算库 #OpenCV在Windows系统安装比较麻烦,下载OpenCV2.4的安装程序,执行会解压得到一个目录。 #打开目录build/python/2.7,复制里面的cv2.pyd文件到C:\Python27\Lib\site-packages中即可 import cv2 import cv2.cv as cv import numpy as np from compiler.ast import flatten import sys def pHash(imgfile): """get image pHash value""" #加载并调整图片为32x32灰度图片 img=cv2.imread(imgfile, cv2.CV_LOAD_IMAGE_GRAYSCALE) img=cv2.resize(img,(32,32),interpolation=cv2.INTER_CUBIC) #创建二维列表 h, w = img.shape[:2] vis0 = np.zeros((h,w), np.float32) vis0[:h,:w] = img #填充数据 #二维Dct变换 vis1 = cv2.dct(cv2.dct(vis0)) #cv.SaveImage('a.jpg',cv.fromarray(vis0)) #保存图片 vis1.resize(8,8) #把二维list变成一维list img_list=flatten(vis1.tolist()) #计算均值 avg = sum(img_list)*1./len(img_list) avg_list = ['0' if i<avg else '1' for i in img_list] #得到哈希值 return ''.join(['%x' % int(''.join(avg_list[x:x+4]),2) for x in range(0,64,4)]) if __name__ == '__main__': if len(sys.argv)!=2: print 'Error: args error, sample: opencv_phash 1.jpg' else: print pHash(sys.argv[1])
用这个算法计算2.jpg和3.jpg的哈希值和与1.jpg对比的汉明距离分别是:
2.jpg:7ffc0000ffffe000,汉明距离是5
3.jpg:7fff0000fffff800,汉明距离是5
很明显,pHash算法得到的汉明距离更加符合我们的要求。
schunlee
现在imagehash库也可以用,imagehash.average_hash方法。
2019-08-06 11:53 回复