python实现图像检索的三种(直方图/OpenCV/哈希法)


Posted in Python onAugust 08, 2019

简介:

本文介绍了图像检索的三种实现方式,均用python完成,其中前两种基于直方图比较,哈希法基于像素分布。
检索方式是:提前导入图片库作为检索范围,给出待检索的图片,将其与图片库中的图片进行比较,得出所有相似度后进行排序,从而检索结果为相似度由高到低的图片。由于工程中还包含Qt界面类、触发函数等其他部分,在该文档中只给出关键函数的代码。

开发系统:MacOS
实现方式:Qt + Python

方法一:自定义的直方图比较算法

a) 基本思路

遍历图片像素点,提取R\G\B值并进行对应的计数,得到原始直方图,但由于0-255的范围太大,因此每一个像素值的统计量均偏小,因此分别将R\G\B的256个像素值映射到0-31共32个像素值上,将像素值范围由256*3缩小到32*3。记录像素值采用的数据结构为一维数组,第1到32个值为R的像素直方图,第33到第64个值为G的像素统计,第65到96个值为B的像素统计。得到直方图后,计算待检索图的直方图和图片库中图像的直方图之间的相似性。

b) 具体实现

用到的函数:

  • split_Img()
  • calc_Hist(img)
  • calc_Similar(h1,h2)
  • calc_Similar_Split(h1,h2)

遍历图片的像素点以计算直方图:calc_Hist(img)

尝试了两种方式,第一种是对图像遍历时逐个调用getpixel()来获取R,G,B的值,但发现这种方式的速度太慢。第二种采用的是内存读取,利用load()函数一次性读取图像的像素值,然后对像素值进行遍历,该方法的速度比逐个提取更快。

#统计直方图,用load()载入图片的像素pix,再分别读取每个像素点的R\G\B值进行统计(分别为0-255)
#将256个颜色值的统计情况投影到32个,返回R\G\B投影后的统计值数组,共32*3=96个元素
def calc_Hist(img):
  '''
  #120张图片,4.43s
  w,h = img.size
  pix = img.load() #载入图片,pix存的是像素
  calcR = [0 for i in range(0,32)]
  calcG = [0 for i in range(0,32)]
  calcB = [0 for i in range(0,32)]
  for i in range(0,w):
    for j in range(0,h):
      (r,g,b) = pix[i,j]
      #print (r,g,b)
      calcR[r/8] += 1
      calcG[g/8] += 1
      calcB[b/8] += 1
  calcG.extend(calcB)
  calcR.extend(calcG)

  return calcR
  '''
  #120张图,3.49s

  w,h = img.size
  pix = img.load() #载入图片,pix存的是像素
  calcR = [0 for i in range(0,256)]
  calcG = [0 for i in range(0,256)]
  calcB = [0 for i in range(0,256)]
  for i in range(0,w):
    for j in range(0,h):
      (r,g,b) = pix[i,j]
      #print (r,g,b)
      calcR[r] += 1
      calcG[g] += 1
      calcB[b] += 1
  calcG.extend(calcB)
  calcR.extend(calcG) #256*3

  #calc存放最终结果,32*3
  calc = [0 for i in range(0,96)]
  step = 0 #calc的下标,0~95
  start = 0 #每次统计的开始位置
  while step < 96:
    for i in range(start,start+8): #8个值为1组,统计值相加,eg:色彩值为0~7的统计值全部转换为色彩值为0的统计值
      calc[step] += calcR[i]
    start = start+8
    step += 1
  #print calc 
  return calc

直方图比较 calc_Similar(h1,h2)

采用的公式是: 

python实现图像检索的三种(直方图/OpenCV/哈希法)

其中N为颜色级数,Sim越靠近1则两幅图像的相似度越高。

c) 问题和改进

简单实现直方图比较后,检索的结果并不好,和预期相比误差较大。分析原因,直方图比较主要依靠整幅图像的色彩统计来进行比较,而对像素的位置并没有很好的记录,因此会造成误判。

同时增加calc_Similar_Split(h1,h2)函数,加入分块比较的部分,计算方法是:对每个小块调用calc_Similar(h1,h2),累加计算结果,最后除以16取平均值。

测试发现效果显著提升,基于颜色相似的同时保留了形状信息。

函数如下:

#该函数用于统一图片大小为256*256,并且分割为16个块,返回值是16个局部图像句柄的数组
def split_Img(img, size = (64,64)):
  img = img.resize((256,256)).convert('RGB')
  w,h = img.size
  sw,sh = size
  return [img.crop((i,j,i+sw,j+sh)).copy() for i in xrange(0,w,sw) for j in xrange(0,h,sh)]

#计算两个直方图之间的相似度,h1和h2为直方图,zip表示同步遍历
def calc_Similar(h1,h2):
  return sum(1 - (0 if g==s else float(abs(g-s))/max(g,s)) for g,s in zip(h1,h2)) / len(h1)

方法二:openCV库的直方图比较算法实现

openCV开源库已经集成了直方图提取、直方图均衡化以及直方图比较的功能,调用方便。为了进一步了解直方图比较的各类实现方法,利用openCV重新进行了实验。

a) 基本思路

对图片库中每个图片提取直方图并均衡化,然后调用cv库函数进行直方图比较,结果进行排序,并显示。

b) 具体实现

首先调用cv2.imread()读取图像,然后调用cv2.calcHist()计算直方图,cv2.normalize()均衡化后进入比较阶段,调用cv2.compareHist(),比较待检索图和图片库图像之间的直方图差异,然后调用DisplayTotalPics()进行显示。

关键代码如下:

results = {} #记录结果
reverse = True #correlation/intersection方法reverse为true,另外两种为false

imgCV = cv2.imread(self.testImg.encode('utf-8'))
#self.testImg为待匹配图片
testHist = cv2.calcHist([imgCV],[0,1,2],None,[8,8,8],[0,256,0,256,0,256])
#提取直方图
testHist = cv2.normalize(testHist,testHist,0,255,cv2.NORM_MINMAX).flatten()
#均衡化

#计算self.testImg和其他图片的直方图差异,INTERSECTION方法效果比较好
for (k, hist) in self.index_cv.items(): 
#self.index_cv保存的是图片库中图片的直方图信息
  d = cv2.compareHist(testHist,hist, cv2.cv.CV_COMP_INTERSECT)
  results[k] = d
  #对结果排序,以v即上面的d作为关键字
  results = sorted([(v, k) for (k, v) in results.items()], reverse = reverse) 
  end = time.time()
  print 'OpenCV Time:'
  print end-start     
self.DisplayTotalPics(results)

c) 问题与解决

openCV中的compareHist函数中提供了4中比较方法:
1.相关系数标准(method=CV_COMP_CORREL) 值越大,相关度越高,最大值1,最小值0
2.卡方系数标准(method=CV_COMP_CHISQR) 值越小,相关度越高,无上限,最小值0
3.相交系数标准(method=CV_COMP_INTERSECT)值大,相关度越高,最大9.455319,最小0
4.巴氏系数的标准(method=CV_COMP_BHATTACHARYYA) 值小,相关度越高,最大值1,最小值0

测试后选择的是method = cv2.cv.CV_COMP_INTERSECT

另外,该方法的速度很快,完全基于图像的色彩分布,但在一些情况下精度并不高。

方法三:平均哈希值比较算法实现

用到的函数:getKey(),getCode(),cmpCode()

a) 基本思路

平均哈希值的比较算法是基于像素分布的,比较对象是灰度图的图像指纹。图像指纹的计算通过比较每个图的像素值和平均像素值来计算,然后计算图像指纹之间的汉明距离,排序后得到相似图像。

b) 具体实现

具体方法是:计算进行灰度处理后图片的所有像素点的平均值,然后遍历灰度图片每一个像素,如果大于平均值记录为1,否则为0,这一步通过定义函数getCode(img)完成。接着计算编码之间的汉明距离,即一组二进制数据变为另一组数据所需的步骤数,汉明距离越小,说明图像指纹的相似度越高。计算汉明距离可以通过简单的遍历和计数来完成,函数为compCode(code1,code2),其中code1和code2为getCode得到的图像指纹。

关键函数代码如下:

#获取排序时的关键值(即汉明距离)    
def getKey(x): 
  return int(x[1])

#由灰度图得到2值“指纹”,从而计算汉明距离
def getCode(img):
  w,h = img.size
  pixel = []
  for i in range(0,w):
    for j in range(0,h):
      pixel_value = img.getpixel((i,j))
      pixel.append(pixel_value) #加入pixel数组
  avg = sum(pixel)/len(pixel) #计算像素平均值

  cp = [] #二值数组
  for px in pixel:
    if px > avg:
      cp.append(1)
    else:
      cp.append(0)
  return cp

#计算两个编码之间的汉明距离
def compCode(code1,code2):
  num = 0
  for index in range(0,len(code1)):
    if code1[index] != code2[index]:
      num+=1
  #print num
  #print '\n'
  return num

c) 问题与优化

我们发现在数据量大时,该方法的检索速度较慢,因此我们将图像指纹也作为图像的属性存在self.hashCode中,在importFolder时计算好,避免后续操作中的冗余重复计算。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python使用os模块的os.walk遍历文件夹示例
Jan 27 Python
Numpy 改变数组维度的几种方法小结
Aug 02 Python
python实现微信定时每天和女友发送消息
Apr 29 Python
用pycharm开发django项目示例代码
Jun 13 Python
详解Selenium+PhantomJS+python简单实现爬虫的功能
Jul 14 Python
Python对列表的操作知识点详解
Aug 20 Python
Django配置MySQL数据库的完整步骤
Sep 07 Python
Python字符串中添加、插入特定字符的方法
Sep 10 Python
python 实现从高分辨图像上抠取图像块
Jan 02 Python
python如何保存文本文件
Jun 07 Python
基于tf.shape(tensor)和tensor.shape()的区别说明
Jun 30 Python
使用Python实现NBA球员数据查询小程序功能
Nov 09 Python
python批量修改ssh密码的实现
Aug 08 #Python
更新pip3与pyttsx3文字语音转换的实现方法
Aug 08 #Python
Python使用百度翻译开发平台实现英文翻译为中文功能示例
Aug 08 #Python
python按行读取文件并找出其中指定字符串
Aug 08 #Python
python实现PID算法及测试的例子
Aug 08 #Python
python开头的coding设置方法
Aug 08 #Python
pycharm 安装JPype的教程
Aug 08 #Python
You might like
php5中类的学习
2008/03/28 PHP
ThinkPHP3.1基础知识快速入门
2014/06/19 PHP
php实现删除指定目录下相关文件的方法
2014/10/20 PHP
CodeIgniter框架实现的整合Smarty引擎DEMO示例
2019/03/28 PHP
PHP goto语句用法实例
2019/08/06 PHP
用jQuery扩展自写的 UI导航
2010/01/13 Javascript
Javascript 设计模式(二) 闭包
2010/05/26 Javascript
理解Javascript_13_执行模型详解
2010/10/20 Javascript
使用js修改客户端注册表的方法
2013/08/09 Javascript
jquery实现点击弹出层效果的简单实例
2014/03/03 Javascript
javascript的BOM汇总
2015/07/16 Javascript
Bootstrap Paginator分页插件使用方法详解
2016/05/30 Javascript
Bootstrap轮播插件简单使用方法介绍
2016/06/21 Javascript
JavaScript函数柯里化原理与用法分析
2017/03/31 Javascript
Vue2仿淘宝实现省市区三级联动
2020/04/15 Javascript
JS+H5 Canvas实现时钟效果
2018/07/20 Javascript
微信小程序开发之路由切换页面重定向问题
2018/09/18 Javascript
解决vue页面渲染但dom没渲染的操作
2020/07/27 Javascript
[59:53]DOTA2-DPC中国联赛 正赛 VG vs Elephant BO3 第二场 3月6日
2021/03/11 DOTA
Python生成8位随机字符串的方法分析
2017/12/05 Python
python 监听salt job状态,并任务数据推送到redis中的方法
2019/01/14 Python
解决新版Pycharm中Matplotlib图像不在弹出独立的显示窗口问题
2019/01/15 Python
关于Tensorflow分布式并行策略
2020/02/03 Python
Python 写了个新型冠状病毒疫情传播模拟程序
2020/02/14 Python
Pycharm2020最新激活码|永久激活(附最新激活码和插件的详细教程)
2020/09/29 Python
Python利用myqr库创建自己的二维码
2020/11/24 Python
Ryderwear澳洲官网:澳大利亚高端健身训练装备品牌
2018/09/18 全球购物
西部世纪.net笔试题面试题
2014/04/03 面试题
护士毕业生自荐信
2014/02/07 职场文书
作风大整顿心得体会
2014/09/10 职场文书
机票销售员态度不好检讨书
2014/09/27 职场文书
2015年小学美术工作总结
2015/05/25 职场文书
学子宴致辞大全
2015/07/27 职场文书
教你使用Pandas直接核算Excel中快递费用
2021/05/12 Python
利用Python脚本写端口扫描器socket,python-nmap
2022/07/23 Python