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

简介:

本文介绍了图像检索的三种实现方式,均用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)

采用的公式是:

其中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时计算好,避免后续操作中的冗余重复计算。

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

(0)

相关推荐

  • Python基于正则表达式实现检查文件内容的方法【文件检索】

    本文实例讲述了Python基于正则表达式实现检查文件内容的方法分享给大家供大家参考,具体如下: 这个是之前就在学python,欣赏python的小巧但是功能强大,是连电池都自带的语言.平时工作中用Java ,觉得python在日常生活中比java用处要大,首先语法没那么复杂,特别是io的操作,java里要写一大坨没关的代码.还有就是不用编译,而且linux系统默认都会自带. 这次遇到的问题是工作当中想要迁移一个系统中的一个模块,这个时候需要评估模块里的代码有没有对其他代码强依赖,就是有没有imp

  • Python中使用haystack实现django全文检索搜索引擎功能

    前言 django是python语言的一个web框架,功能强大.配合一些插件可为web网站很方便地添加搜索功能. 搜索引擎使用whoosh,是一个纯python实现的全文搜索引擎,小巧简单. 中文搜索需要进行中文分词,使用jieba. 直接在django项目中使用whoosh需要关注一些基础细节问题,而通过haystack这一搜索框架,可以方便地在django中直接添加搜索功能,无需关注索引建立.搜索解析等细节问题. haystack支持多种搜索引擎,不仅仅是whoosh,使用solr.elas

  • 听歌识曲--用python实现一个音乐检索器的功能

    听歌识曲,顾名思义,用设备"听"歌曲,然后它要告诉你这是首什么歌.而且十之八九它还得把这首歌给你播放出来.这样的功能在QQ音乐等应用上早就出现了.我们今天来自己动手做一个自己的听歌识曲 我们设计的总体流程图很简单: ----- 录音部分 ----- 我们要想"听",就必须先有录音的过程.在我们的实验中,我们的曲库也要用我们的录音代码来进行录音,然后提取特征存进数据库.我们用下面这样的思路来录音 # coding=utf8 import wave import pya

  • python 全文检索引擎详解

    python 全文检索引擎详解 最近一直在探索着如何用Python实现像百度那样的关键词检索功能.说起关键词检索,我们会不由自主地联想到正则表达式.正则表达式是所有检索的基础,python中有个re类,是专门用于正则匹配.然而,光光是正则表达式是不能很好实现检索功能的. python有一个whoosh包,是专门用于全文搜索引擎. whoosh在国内使用的比较少,而它的性能还没有sphinx/coreseek成熟,不过不同于前者,这是一个纯python库,对python的爱好者更为方便使用.具体的

  • python检索特定内容的文本文件实例

    windows环境下python2.7 脚本指定一个参数作为要检索的字符串 例如: >find.py ./ hello # coding=utf-8 import os import sys # 找到当前目录下的所有文本文件 def findFile(path): f = [] d = [] l = os.listdir(path) for x in l: if os.path.isfile(os.path.join(os.getcwd() + "\\", x)): f.appe

  • python django使用haystack:全文检索的框架(实例讲解)

    haystack:全文检索的框架 whoosh:纯Python编写的全文搜索引擎 jieba:一款免费的中文分词包 首先安装这三个包 pip install django-haystack pip install whoosh pip install jieba 1.修改settings.py文件,安装应用haystack, 2.在settings.py文件中配置搜索引擎 HAYSTACK_CONNECTIONS = { 'default': { # 使用whoosh引擎 'ENGINE': '

  • 使用python实现正则匹配检索远端FTP目录下的文件

    遇到一个问题,需要正则匹配远端FTP目录下的文件,如果使用ftp客户端可以通过命令行很容易的做到这一点,但是暂时没有一个工具支持这样的需求,于是通过python对FTP的支持和对正则表达式的支持,写了这么一个简单的工具,用于使用正则表达式来匹配远端目录的文件. 代码如下 # coding=utf-8 ######################################################################### # File Name: reg_url.py #

  • python使用xlrd实现检索excel中某列含有指定字符串记录的方法

    本文实例讲述了python使用xlrd实现检索excel中某列含有指定字符串记录的方法.分享给大家供大家参考.具体分析如下: 这里利用xlrd,将excel中某列数据中,含有指定字符串的记录取出,并生成用这个字符串命名的txt文件 import os import xlrd,sys # input the excel file Filename=raw_input('input the file name&path:') if not os.path.isfile(Filename): rais

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

    简介: 本文介绍了图像检索的三种实现方式,均用python完成,其中前两种基于直方图比较,哈希法基于像素分布. 检索方式是:提前导入图片库作为检索范围,给出待检索的图片,将其与图片库中的图片进行比较,得出所有相似度后进行排序,从而检索结果为相似度由高到低的图片.由于工程中还包含Qt界面类.触发函数等其他部分,在该文档中只给出关键函数的代码. 开发系统:MacOS 实现方式:Qt + Python 方法一:自定义的直方图比较算法 a) 基本思路 遍历图片像素点,提取R\G\B值并进行对应的计数,得

  • Python列表删除的三种方法代码分享

    1.使用del语句删除元素 >>> i1 = ["a",'b','c','d'] >>> del i1[0] >>> print(i1) ['b', 'c', 'd'] >>> del语句将值从列表中删除后,就再也无法访问它了. 2.使用pop()删除元素 pop()可删除列表末尾的元素,并让你能够接着使用它.食欲弹出(pop)源自这样的类比:列表就是一个栈,而删除列表末尾的元素相当于弹出栈顶元素. >>

  • Python中逗号的三种作用实例分析

    本文实例讲述了Python中逗号的三种作用.分享给大家供大家参考.具体分析如下: 最近研究python  遇到个逗号的问题 一直没弄明白 今天总算搞清楚了 1.逗号在参数传递中的使用: 这种情况不多说  没有什么不解的地方 就是形参或者实参传递的时候参数之间的逗号 例如def  abc(a,b)或者abc(1,2) 2.逗号在类型转化中的使用 主要是元组的转换 例如: >>> a=11 >>> b=(a) >>> b 11 >>> b

  • 详解python播放音频的三种方法

    第一种 使用pygame模块 pygame.mixer.init() pygame.mixer.music.load(self.wav_file) pygame.mixer.music.set_volume(0.5) pygame.mixer.music.play() 缺点:pygame模块播放音频时,有时候会产生失真,且无法通过修改播放器的频率来矫正音色. 第二种 使用pyqt5模块 from PyQt5 import QtMultimedia from PyQt5.QtCore import

  • Python实现定时执行任务的三种方式简单示例

    本文实例讲述了Python实现定时执行任务的三种方式.分享给大家供大家参考,具体如下: 1.定时任务代码 #!/user/bin/env python # @Time :2018/6/7 16:31 # @Author :PGIDYSQ #@File :PerformTaskTimer.py #定时执行任务命令 import time,os,sched schedule = sched.scheduler(time.time,time.sleep) def perform_command(cmd

  • 详解Python发送email的三种方式

    Python发送email的三种方式,分别为使用登录邮件服务器.使用smtp服务.调用sendmail命令来发送三种方法 Python发送email比较简单,可以通过登录邮件服务来发送,linux下也可以使用调用sendmail命令来发送,还可以使用本地或者是远程的smtp服务来发送邮件,不管是单个,群发,还是抄送都比较容易实现.本米扑博客先介绍几个最简单的发送邮件方式记录下,像html邮件,附件等也是支持的,需要时查文档即可. 一.登录邮件服务器 通过smtp登录第三方smtp邮箱发送邮件,支

  • 对python For 循环的三种遍历方式解析

    实例如下所示: array = ["a","b","c"] for item in array: print(item) for index in range(len(array)): print(str(index)+".."+array[index]) for index,val in enumerate(array): print(str(index)+"--"+val); 打印结果 a b c 0.

  • python反转列表的三种方式解析

    这篇文章主要介绍了python反转列表的三种方式解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.内建函数reversed() li =[1, 2, 3, 4, 5, 6] a = list(reversed(li)) print (a) 注意:reversed()函数返回的是一个迭代器,而不是一个List,所以需要list函数转换一下 2.内建函数sorted() sorted()语法 sorted(iterable[, cmp[, k

  • python求绝对值的三种方法小结

    如下所示: 1.条件判断 2.内置函数abs() 3.内置模块 math.fabs abs() 与fabs()的区别 abs()是一个内置函数,而fabs()在math模块中定义的. fabs()函数只适用于float和integer类型,而abs()也适用于复数. abs()返回是float和int类型,math.fabs()返回是float类型 以上这篇python求绝对值的三种方法小结就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • python 字典访问的三种方法小结

    定义字典 dic = {'a':"hello",'b':"how",'c':"you"} 方法一: for key in dic: print key,dic[key] print key + str(dic[key]) 结果: a hello ahello c you cyou b how bhow 细节: print key,dic[key],后面有个逗号,自动生成一个空格 print key + str(dic[key]),连接两个字符串,

随机推荐