OpenCV-Python教程:直方图比对、直方图反投影(compareHist,calcBackProject)

news/2024/7/21 5:43:28 标签: 计算机视觉, opencv, python, 图像处理

目录

1、直方图比对compareHist

2、直方图反投影calcBackProject

扩展阅读:



opencv-python-comparehist-calcbackproject" title="原文链接:http://www.juzicode.com/opencv-python-comparehist-calcbackproject">

返回Opencv-Python教程

1、直方图比对compareHist

通过compareHist()可以从直方图的角度对比2幅图像的相关性,比较的对象可以是1D或2D直方图。

接口形式:

cv2.compareHist(H1, H2, method) ->retval
  • 参数含义:
  • H1:输入图像直方图;
  • H2:输入图像直方图,和H1相同的尺寸;
  • method:比较方法;

method包含6种方法,整数数值从0~5:

enum  	cv::HistCompMethods {
  cv::HISTCMP_CORREL = 0,
  cv::HISTCMP_CHISQR = 1,
  cv::HISTCMP_INTERSECT = 2,
  cv::HISTCMP_BHATTACHARYYA = 3,
  cv::HISTCMP_HELLINGER = HISTCMP_BHATTACHARYYA,
  cv::HISTCMP_CHISQR_ALT = 4,
  cv::HISTCMP_KL_DIV = 5
}

下面这个例子对读出的图像分别经过平滑、像素值减去一个数、加上一个数的操作,分别计算着4幅图像的直方图,并和源图像做直方图比对,就得到源图像和源图像、平滑图像、加数图像、减数图像的4个比对结果:

import numpy as np
import matplotlib.pyplot as plt
import cv2
print('VX公众号: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)
plt.rc('font',family='Youyuan',size='9')
plt.rc('axes',unicode_minus='False')

img_src = cv2.imread('..\\samples\\data\\lena.jpg',0) 
img_comp1 = cv2.blur(img_src,(13,13))
img_comp2 = cv2.subtract(img_src,35)
img_comp3 = cv2.add(img_src,35)
#计算直方图
histSize = 256
histRange = (0, 256) 
hist_src = cv2.calcHist([img_src], [0], None, [histSize], histRange) 
hist_comp1 = cv2.calcHist([img_comp1], [0], None, [histSize], histRange)  
hist_comp2 = cv2.calcHist([img_comp2], [0], None, [histSize], histRange)  
hist_comp3 = cv2.calcHist([img_comp3], [0], None, [histSize], histRange)  
#直方图比较
for method in range(6):
    src_src = cv2.compareHist(hist_src, hist_src, method)
    src_comp1 = cv2.compareHist(hist_src, hist_comp1, method)
    src_comp2 = cv2.compareHist(hist_src, hist_comp2, method)
    src_comp3 = cv2.compareHist(hist_src, hist_comp3, method)
    print('method=%d src blur sub add'%method,src_src,src_comp1,src_comp2,src_comp3)

#显示图像
fig,ax = plt.subplots(2,2)
ax[0,0].set_title('hist_src')
ax[0,0].plot(hist_src) 
ax[0,1].set_title('blur')
ax[0,1].plot(hist_comp1)
ax[1,0].set_title('sub')
ax[1,0].plot(hist_comp2)
ax[1,1].set_title('add')
ax[1,1].plot(hist_comp3)
#ax[0,0].axis('off');ax[0,1].axis('off');ax[1,0].axis('off');ax[1,1].axis('off')#关闭坐标轴显示
plt.show()  

运行结果:

从显示的直方图可以看到,平滑处理后图像的直方图和源图像差不多一致,加数或减数会导致直方图左右或右移,可以推测平滑处理的直方图比对结果和源图像会比较接近,而加数或减数图像的直方图比对结果会相差更大,下面打印的比较结果数值可以验证该结论:

VX公众号: 桔子code / juzicode.com
cv2.__version__: 4.5.3
method=0 src blur sub add 1.0 0.9285279683865829 0.35037265936214546 0.3512659314459189
method=1 src blur sub add 0.0 23850.06026419833 7146491.858903675 5844706.253864458
method=2 src blur sub add 262144.0 236732.0 167915.0 167915.0
method=3 src blur sub add 0.0 0.15727062402652872 0.4038869008245676 0.4038869008245676
method=4 src blur sub add 0.0 37400.61455341503 217214.77007193133 217214.77007193133
method=5 src blur sub add 0.0 79978.49978387816 462272.6122239813 1060797.6089261884

method=0和method=2表示的HISTCMP_CORREL和HISTCMP_INTERSECT比对,得到的比对值越大表示2幅图像越接近;method的其他值表示的比对方法得到的值越小表示2幅图像越接近。

下图是前面例子中得到的4张图像,平滑处理的图像(blur)模糊不清,人眼看起来和源图像(src)要显得“更不像”一些,而加减数得到的图像(sub,add)和源图像除了亮度几乎没有差异。但是通过compareHist()计算得到的对比结果却认为平滑处理的图像和源图像要“更像”一些,加减数得到的图像却“更不像”一些,这点和常识是有些相悖的。

得出这个“悖论”的原因是compareHist()比对的是直方图,也就是像素值分布的比对,而人眼观察到的清晰度、梯度变化等内容在直方图里是体现不出来的。下面我们再通过一个更极端的例子来看看直方图比对的局限性,我们将前面代码中的img_comp3图像改成源图像的左右半边对调后得到的新图像:

img_src = cv2.imread('..\\samples\\data\\lena.jpg',0) 
img_comp1 = cv2.blur(img_src,(13,13))
img_comp2 = cv2.subtract(img_src,35)
img_comp3 = img_src.copy() 
img_comp3[:,:256]=img_src[:,256:] #左右半边对调
img_comp3[:,256:]=img_src[:,:256] #左右半边对调

这个时候图像img_comp3(下图中的swap)和源图像(下图中的src)从直观上看起来差别就非常大了,但是他们的直方图却是一样的:

通过compareHist()计算的比对值显示,交换左右半边得到的新图像(swap)和源图像(src)是一样的图像:

method=0 src blur sub swap 1.0 0.9285279683865829 0.35037265936214546 1.0
method=1 src blur sub swap 0.0 23850.06026419833 7146491.858903675 0.0
method=2 src blur sub swap 262144.0 236732.0 167915.0 262144.0
method=3 src blur sub swap 0.0 0.15727062402652872 0.4038869008245676 0.0
method=4 src blur sub swap 0.0 37400.61455341503 217214.77007193133 0.0
method=5 src blur sub swap 0.0 79978.49978387816 462272.6122239813 0.0u

compareHist()除了可以比对一维直方图,还可以比对2D直方图,这时compareHist()入参的H1和H2要求都是2D直方图:

#计算直方图
histSize = (256,256)
histRange = (0, 256,0, 256) 
hist_src = cv2.calcHist([img_src], [0,1], None, histSize, histRange) 
hist_comp1 = cv2.calcHist([img_comp1], [0,1], None, histSize, histRange)  
hist_comp2 = cv2.calcHist([img_comp2], [0,1], None, histSize, histRange)  
hist_comp3 = cv2.calcHist([img_comp3], [0,1], None, histSize, histRange)  
#直方图比较
for method in range(6):
    src_src = cv2.compareHist(hist_src, hist_src, method)
    src_comp1 = cv2.compareHist(hist_src, hist_comp1, method)
    src_comp2 = cv2.compareHist(hist_src, hist_comp2, method)
    src_comp3 = cv2.compareHist(hist_src, hist_comp3, method)
    print('method=%d src blur sub add'%method,src_src,src_comp1,src_comp2,src_comp3)

2、直方图反投影calcBackProject

反投影用来计算源图像的像素和特征图像直方图中像素分布的匹配程度。它返回一个与输入图像尺寸相同的图像,其中每个像素对应于该像素属于特征图像的概率,概率越高越接近要查找的对象,可以用于图像分割或查找感兴趣的区域。

接口形式:

cv2.calcBackProject(images,channels,hist,ranges,scale[,dst])->dst
  • 参数含义:
  • images:输入图像,是一个图像集合,可以是包含多通道彩色图像的list或tuple,也可以是多个灰度图组成的list或者tuple;list或tuple形式的输入
  • channels:根据images确定,指明要用images里的哪个通道号,根据images的形式确定;list或tuple形式的输入;
  • hist:输入直方图;
  • ranges:图像元素取值的范围;包含2个元素的list或tuple;
  • scale:缩放比例;
  • dst:目标图像,单通道,和images[0]同样的尺寸和depth ;

其中入参images、channels、ranges参数用法同calcHist()。

入参hist是特征图像的的直方图,使用它在源图像中查找该特征。

下面这里例子从源图像img_src中找出绿色的草地:

import matplotlib.pyplot as plt
import cv2
print('VX公众号: 桔子code / juzicode.com')
print('cv2.__version__:',cv2.__version__)
plt.rc('font',family='Youyuan',size='9')
plt.rc('axes',unicode_minus='False')
 
img_src = cv2.imread('..\\samples\\picture\\cow.jpeg' ) 
img_roi = cv2.imread('..\\samples\\picture\\cow-roi.jpeg' ) 
#计算特征图像直方图
hsv_src = cv2.cvtColor(img_src,cv2.COLOR_BGR2HSV)
hsv_roi = cv2.cvtColor(img_roi,cv2.COLOR_BGR2HSV)
hist_roi = cv2.calcHist([hsv_roi],[0, 1], None, [180, 256], [0, 180, 0, 256] )
cv2.normalize(hist_roi,hist_roi,0,255,cv2.NORM_MINMAX)
#计算反投影
img_back = cv2.calcBackProject([hsv_src],[0,1],hist_roi,[0,180,0,256],2)
#二值化和叠加
disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
img_dest=cv2.filter2D(img_back,-1,disc)
ret,thresh = cv2.threshold(img_dest,30,255,0)
thresh = cv2.merge((thresh,thresh,thresh))
img_merge = cv2.bitwise_and(img_src,thresh)
#绘图
fig,ax = plt.subplots(1,4)
ax[0].set_title('img_src')
ax[0].imshow(cv2.cvtColor(img_src,cv2.COLOR_BGR2RGB)) 
ax[1].set_title('img_roi')
ax[1].imshow(cv2.cvtColor(img_roi,cv2.COLOR_BGR2RGB)) 
ax[2].set_title('img_back')
ax[2].imshow(img_back,'gray') 
ax[3].set_title('img_merge')
ax[3].imshow(cv2.cvtColor(img_merge,cv2.COLOR_BGR2RGB)) 
plt.show()  

在这个例子里首先手动从源图像img_src中截取部分草地作为特征图像img_roi,然后读入源图像和特征图像转换为HSV色彩空间,计算特征图像的H-S通道的2D直方图,然后利用该直方图作为输入传入calcBackProject()计算匹配程度,得到第3张图img_back,该图像为单通道灰度图像,其中的草地部分表现出更高的灰度级,经过阈值处理后和源图像相与就是绿色的草地部分img_merge。

扩展阅读:

  1. OpenCV-Python教程
  2. OpenCV-Python教程:直方图(calcHist)与绘制

http://www.niftyadmin.cn/n/787854.html

相关文章

hdoj 1051 Wooden Sticks

要点:主要就是排序 可以按照长度 或者 宽度 都可以,这样正确性是因为(以长度排序)当按照长度升序时,若此时宽度也按升序必然正确,但是若此时宽度小于之前的木头,那么这个必然不能和之前的木头用同种器材处理…

.net 多个dll 封装成一个dll_丢失apimswincrtruntimel110.dll解决方案

api-ms-win-crt-runtime-l1-1-0.dll是一个重要的系统文件。自己在装Adobe 程序启动的时候,提示api-ms-win-crt-runtime-l1-1-0.dll文件缺失,这个时候不必担心,只要下载一个即可,亲测可用!1、下载api-ms-win-crt-runtim…

又发现一条喵星人将要统治地球的新线索(OpenCV猫脸检测)

都说喵星人快要统治地球了,各种证据正在被发现…… OpenCV的开发人员似乎也发现了些什么,在其发布版本里悄悄留下了些线索: 在OpenCV-Python安装包目录的data文件夹下,有2个“frontcal cat face”文件,对比其他几个人脸…

PHP—— 作业外包 学生管理系统

QQ 1274510382 Wechat JNZ_aming 商业互捧 QQ群538250800 技术搞事 QQ群599020441 技术合作 QQ群152889761 加入我们 QQ群649347320 纪年科技aming 网络安全 ,深度学习,嵌入式,机器强化,生物智能,生命科学。 地址: https://pan-yz.chaoxing.com/views/external/thum…

DFS寻找路径~

给定起点 找到从起点到各点的路径。 注意:此法只适用于简单路径(无环) 1 2 1 3 2 4 3 4 这一组就含有环 不可以,因为 记录4号顶点父节点的时候 path[]只能记录最后访问到4的那个父节点 package Graph;import java.util.Iterato…

谈谈如何优雅的关闭正在运行中的Spark Streaming的流程序

前面的文章,已经简单提到过怎么样关闭流程序。因为Spark Streaming流程序比较特殊,所以不能直接执行kill -9 这种暴力方式停掉,如果使用这种方式停程序,那么就有可能丢失数据或者重复消费数据。 为什么呢?因为流程序一…

python线条颜色不同_Python中matplotlib的颜色及线条等设置

1.颜色 plt.scatter(x,y,c‘r’,marker‘x’,label‘cluster_1’) b: blue g: green r: red c: cyan m: magenta y: yellow k: black w: white 2.线条 plt.scatter(x,y,c‘r’,marker‘x’,label‘cluster_1’) plt.plot(range(10), linestyle’–’, marker‘o’, color‘b’)…

Python的多版本、多虚拟环境共存(jupyter篇)

原文链接:http://www.juzicode.com/python-note-multi-version-python-jupyter 1、安装多个Python版本或创建虚拟环境: 2、在对应的Python版本或虚拟环境的安装路径下使用pip install jupyter安装jupyter。 3、任何版本下启动jupyter lab,找…