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的内建模块collections的教程
Apr 28 Python
python中安装模块包版本冲突问题的解决
May 02 Python
Python 中pandas.read_excel详细介绍
Jun 23 Python
Python之ReportLab绘制条形码和二维码的实例
Jan 15 Python
Python实现的拟合二元一次函数功能示例【基于scipy模块】
May 15 Python
pyqt5 实现 下拉菜单 + 打开文件的示例代码
Jun 20 Python
Python Pandas数据中对时间的操作
Jul 30 Python
Pytorch 实现自定义参数层的例子
Aug 17 Python
python打印异常信息的两种实现方式
Dec 24 Python
浅谈keras中的后端backend及其相关函数(K.prod,K.cast)
Jun 29 Python
Python爬虫与反爬虫大战
Jul 30 Python
Python可变与不可变数据和深拷贝与浅拷贝
Apr 06 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
phpwind中的数据库操作类
2007/01/02 PHP
PHP Google的translate API代码
2008/12/10 PHP
教你识别简单的免查杀PHP后门
2015/09/13 PHP
PHP面向对象程序设计实例分析
2016/01/26 PHP
PHPTree――php快速生成无限级分类
2018/03/30 PHP
jQuery Validation插件remote验证方式的Bug解决
2010/07/01 Javascript
JQuery制作的放大效果的popup对话框(未添加任何jquery plugin)分享
2013/04/28 Javascript
node.js中的fs.rmdirSync方法使用说明
2014/12/16 Javascript
浅析Javascript中“==”与“===”的区别
2014/12/23 Javascript
第二章之Bootstrap 页面排版样式
2016/04/25 Javascript
JavaScript中实现键值对应的字典与哈希表结构的示例
2016/06/12 Javascript
JavaScript中boolean类型之三种情景实例代码
2016/11/21 Javascript
jQuery-mobile事件监听与用法详解
2016/11/23 Javascript
基于nodejs res.end和res.send的区别
2018/05/14 NodeJs
JavaScript多种页面刷新方法小结
2019/04/04 Javascript
vue缓存的keepalive页面刷新数据的方法
2019/04/23 Javascript
Python写的服务监控程序实例
2015/01/31 Python
在win和Linux系统中python命令行运行的不同
2016/07/03 Python
Python实现去除列表中重复元素的方法小结【4种方法】
2018/04/27 Python
python机器学习之神经网络实现
2018/10/13 Python
Python实现的爬取小说爬虫功能示例
2019/03/30 Python
Python matplotlib画图与中文设置操作实例分析
2019/04/23 Python
python-numpy-指数分布实例详解
2019/12/07 Python
Python如何使用argparse模块处理命令行参数
2019/12/11 Python
使用python3批量下载rbsp数据的示例代码
2019/12/20 Python
利用4行Python代码监测每一行程序的运行时间和空间消耗
2020/04/22 Python
汉森冲浪板:Hansen Surfboards
2018/05/19 全球购物
教师岗位职责范本
2013/12/29 职场文书
总经理秘书岗位职责
2014/03/17 职场文书
大学毕业生求职自荐书
2014/06/05 职场文书
法定代表人授权委托书
2014/09/19 职场文书
领导干部群众路线对照检查材料
2014/11/05 职场文书
旷工辞退通知书
2015/04/17 职场文书
SpringMVC 整合SSM框架详解
2021/08/30 Java/Android
MySQL慢查询优化解决问题
2022/03/17 MySQL
springboot 自定义配置 解决Boolean属性不生效
2022/03/18 Java/Android