感知哈希算法--python实现
来源:互联网 发布:mac怎么打开rar 编辑:程序博客网 时间:2024/05/16 10:36
最近在看运动目标跟踪方面的资料,偶然间看到zouxy09大神的一篇《基于感知哈希算法的视觉跟踪》,觉得挺有意思的。于是去查了相关的感知哈希的资料,发现在图片搜索领域里面应用非常广泛,这种技术我觉得有点像模板匹配,其核心在于:通过指纹的相似度来搜索最相似的图片。
基于zouxy09大神的c++程序改写了一个python版本,并且增加了差值哈希的实现。
——————————————————————————————————————————
一、算法原理及过程
1.ahash算法
在向下采样的过程中,只保留图像的低频信息。
工作过程:
①缩小尺寸,简化色彩:8*8灰度
②计算灰度均值:64个灰度值的平均
③生成哈希码:将64个灰度值与上一步生成的平均值进行比较。比均值大,则置1;比均值小,则置0。从而得到一个包含64个元素的“指纹”。
④计算汉明距离:将两个“指纹”进行比较,计算它们的汉明距离。(==0):非常相似;(<5): 相似; (>10): 不同
2.phash算法
均值哈希虽然简单,但是受均值影响大。如果对图像进行伽马校正或者进行直方图均值化都会影响均值,从而影响哈希值的计算。所以就有人提出更健壮的方法,通过离散余弦(DCT)进行低频提取。
离散余弦变换(DCT)是种图像压缩算法,它将图像从像素域变换到频率域。然后一般图像都存在很多冗余和相关性的,所以转换到频率域之后,只有很少的一部分频率分量的系数才不为0,大部分系数都为0(或者说接近于0)。下图的右图是对lena图进行离散余弦变换(DCT)得到的系数矩阵图。从左上角依次到右下角,频率越来越高,由图可以看到,左上角的值比较大,到右下角的值就很小很小了。换句话说,图像的能量几乎都集中在左上角这个地方的低频系数上面了。
工作过程:
①缩小尺寸,简化色彩:32*32灰度
②计算DCT:对图像进行离散余弦变换,得到32*32的DCT系数矩阵
③截取DCT:因为只有左上角的部分呈现图像的最低频部分,所以我们截取左上角的8*8矩阵
④计算均值:64个DCT系数的均值
⑤生成哈希码:将64个DCT系数与上一步生成的平均值进行比较。之后过程同均值哈希
3.dhash算法
这是一种通过渐变实现的哈希算法,相比phash,速度上有较大的优势。
工作过程:
①缩小尺寸、简化色彩:9*8灰度
②计算差异:每行9个像素做差得到8个差异值,总共64个差异值
③生成哈希码:差异值与0比较。大于0,置1;小于0,置0。之后过程同均值哈希
——————————————————————————————————————————
二、代码实现:
# coding:UTF-8import cv2import numpy as npimport timefrom glob import iglobclass HashTracker: def __init__(self, path): # 初始化图像 self.img = cv2.imread(path) self.gray = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY) def cal_hash_code(self, cur_gray): s_img = cv2.resize(cur_gray, dsize=(8, 8)) img_mean = cv2.mean(s_img) return s_img > img_mean[0] def cal_phash_code(self, cur_gray): # 缩小至32*32 m_img = cv2.resize(cur_gray, dsize=(32, 32)) # 浮点型用于计算 m_img = np.float32(m_img) # 离散余弦变换,得到dct系数矩阵 img_dct = cv2.dct(m_img) img_mean = cv2.mean(img_dct[0:8, 0:8]) # 返回一个8*8bool矩阵 return img_dct[0:8, 0:8] > img_mean[0] def cal_dhash_code(self, cur_gray): # dsize=(width, height) m_img = cv2.resize(cur_gray, dsize=(9, 8)) m_img = np.int8(m_img) # 得到8*8差值矩阵 m_img_diff = m_img[:, :-1] - m_img[:, 1:] return m_img_diff > 0 def cal_hamming_distance(self, model_hash_code, search_hash_code): # 返回不相同的个数 diff = np.uint8(model_hash_code - search_hash_code) return cv2.countNonZero(diff) def hash_track(self, roi, rect, flag=0): # 获得矩形框信息 width = abs(rect[0] - rect[2]) height = abs(rect[1] - rect[3]) # 获得当前图像的长宽信息 img_w, img_h = self.img.shape[:2] # 根据flag,选择方法,计算前一帧的hash值 if flag == 0: model_hash_code = self.cal_hash_code(roi) elif flag == 1: model_hash_code = self.cal_phash_code(roi) elif flag == 2: model_hash_code = self.cal_dhash_code(roi) # 初始化汉明距离 min_dis = 64 # 滑动窗口匹配,步长为2 for i in xrange(0, img_h, 2): for j in xrange(0, img_w, 2): if flag == 0: search_hash_code = self.cal_hash_code(self.gray[j:j + height, i:i + width]) elif flag == 1: search_hash_code = self.cal_phash_code(self.gray[j:j + height, i:i + width]) elif flag == 2: search_hash_code = self.cal_dhash_code(self.gray[j:j + height, i:i + width]) # 计算汉明距离 distance = self.cal_hamming_distance(model_hash_code, search_hash_code) # 获得最小汉明距离,同时得到此时的匹配框 if distance < min_dis: rect = i, j, i + width, j + height min_dis = distance # 根据匹配框,获得下一帧的匹配模板 roi = self.gray[rect[1]:rect[3], rect[0]:rect[2]] # 显示当前帧矩形框位置 cv2.rectangle(self.img, (rect[0], rect[1]), (rect[2], rect[3]), (255, 0, 0), 2) return roi# 鼠标响应函数box = [0]*4def mouse_handler(event, x, y, flag, param): if event == cv2.EVENT_LBUTTONDOWN: # 起始点记录 box[0], box[1] = x, y elif event == cv2.EVENT_MOUSEMOVE and flag == cv2.EVENT_FLAG_LBUTTON: box[2], box[3] = x, y elif event == cv2.EVENT_LBUTTONUP: # 获得右下角点 box[2], box[3] = x, ydef main(): # 读取第一张图片,用来画框 img = cv2.imread('./img/0001.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cv2.namedWindow('hashTracker', 1) cv2.setMouseCallback('hashTracker', mouse_handler) while True: cv2.imshow('hashTracker', img) if cv2.waitKey(1) == 27: break # 获取初始化模型 model = gray[box[1]:box[3], box[0]:box[2]] # 获取图片序列 paths = iglob(r'./img/*.jpg') # 计数用 frame_count = 0 # 循环读入图片 for path in paths: frame_count += 1 # 实例创建 h = HashTracker(path) # 感知哈希跟踪 start_time = time.clock() model = h.hash_track(model, box) fin_time = time.clock() print "%d: delta time:%.2f" % (frame_count, fin_time - start_time) cv2.imshow('hashTracker', h.img) if cv2.waitKey(20) == 27: breakif __name__ == '__main__': main()——————————————————————————————————————————
三、实验结果及分析
下面是基于均值哈希跟踪的实验结果
第25帧 第50帧
第100帧 第200帧
结果:均值哈希和差值哈希速度相对比较快,phash效果好,但是速度好慢;其实总体上,如果要用作跟踪算法的话,我觉得速度都比较慢OTZ。但是思路还是很好。
——————————————————————————————————————————
参考文献:
① 基于感知哈希算法的视觉目标跟踪
②三种基于感知哈希算法的相似图像检索技术
③相似图片搜索原理
- 感知哈希算法--python实现
- 感知哈希算法——Python实现
- 感知机算法python实现
- python实现感知器算法
- iOS实现感知哈希算法
- 感知哈希算法Java实现
- 感知哈希算法的opencv实现
- 感知哈希算法原理与实现
- 感知哈希算法--实现图片搜索
- iOS实现感知哈希算法
- 相似图片检测:感知哈希算法之dHash的Python实现
- [python]感知机学习算法实现
- 用python实现简单感知机算法
- 神经网络-感知器算法python代码实现
- python实现自适应线性感知器算法
- 感知哈希算法
- 感知哈希算法
- 压缩感知重构算法之OMP算法python实现
- OPENWRT 查看DHCP的IP地址
- MapReduce类型与格式
- Ubuntu14.04及以后的版本强制安装ia32-libs
- 关于有偿提供拼图响应式后台的通知
- 1011
- 感知哈希算法--python实现
- 查找
- 图像特效---滤镜晕影特效调节算法
- 标签中的data-属性有什么用
- ps stat
- HUSTOJ 1017:三个整数是否相邻
- Surrounded Regions
- C语言 打印1到最大的N位数(输入3,打印1,2,3~999)
- OpenMP并行化实例----Mandelbrot集合并行化计算