opencv进阶01-直方图的应用及示例cv2.calcHist()
直方图是什么?
直方图是一种图形表示方法,用于显示数据中各个数值或数值范围的分布情况。它将数据划分为一系列的区间(也称为“箱子”或“bin”),然后统计每个区间中数据出现的频次(或频率)。直方图可以帮助我们更好地理解数据的分布特征,包括集中趋势、离散程度等。
直方图的主要特点包括:
1. 横轴(X 轴): 横轴表示数据的数值范围或区间。每个区间通常由两个数值来表示,例如,0-10、10-20 等。
2. 纵轴(Y 轴): 纵轴表示每个区间中数据的频次(或频率),也就是该区间内数据出现的次数。
3. 条形图: 直方图的图形由一系列的矩形条组成,每个矩形条的宽度表示区间的宽度,高度表示该区间内数据的频次。
4. 连续数据: 直方图适用于连续型数据
,例如测量数据、时间数据等。对于离散型数据,柱状图可能更为适合
。
直方图在许多领域有重要的应用,包括统计学、图像处理、数据分析等。在图像处理中,直方图可以用来分析图像的像素值分布,从而进行图像增强、对比度调整、图像分割等操作。在统计学中,直方图可以帮助我们了解数据的分布情况,如正态分布、偏态分布等。通过观察直方图,我们可以对数据的特征有更深入的了解,从而做出更准确的决策和分析
直方图在图像中的含义
从统计的角度讲,直方图是图像内灰度值的统计特性与图像灰度值之间的函数,直方图统计图像内各个灰度级出现的次数。从直方图的图形上观察,横坐标是图像中各像素点的灰度级,纵坐标是具有该灰度级(像素值)的像素个数。
例如,有一幅图像如图 13-1 所示。该图中只有 9 个像素点,存在 1、2、3、4、5,共 5 个灰度级。
统计各个灰度级出现的次数,如表 13-1 所示
在绘制直方图时,将灰度级作为 x 轴处理,该灰度级出现的次数作为 y 轴处理,则可知:
- x 轴的数据为 x=[1 2 3 4 5]。
- y 轴的数据为 y=[3 1 2 1 2]。
根据上述关系,可以绘制出如图 13-2 所示的折线图(左图)和直方图(右图)。一般情况下,我们把左侧的直线图和右侧直方图都称为直方图。
在实际处理中,图像直方图的 x 轴区间一般是[0, 255],对应的是 8 位位图的 256 个灰度级;y 轴对应的是具有相应灰度级的像素点的个数。
例如在图 13-3 中,上图是一张图像,下图则是其对应的直方图。图中圆点表示这些像素点会被统计到对应的灰度级上。
虽然 8 位的图像都具有 256 个灰度级(每一个像素可以有 256 个灰度值),但是属于不同灰度级的像素数量是很不一样的。
例如图 13-4,从图中可以看出,图像的不同部分直方图是不一样的。
有时为了便于表示,也会采用归一化直方图。在归一化直方图中,x 轴仍然表示灰度级;y轴不再表示灰度级出现的次数,而是灰度级出现的频率。
例如,针对图 13-1,统计各个灰度级出现的频率:
灰度级出现的频率 = 灰度级出现的次数/总像素数
在图 13-1 中共有 9 个像素,所以统计结果如表 13-2 所示。
在归一化直方图中,各个灰度级出现的频率之和为 1。例如,本例中:
在绘制直方图时,将灰度级作为 x 轴数据处理,将其出现的频率作为 y 轴数据处理,则可知:
- x 轴的数据为 x=[1 2 3 4 5]
- y 轴的数据为 y=[3/9 1/9 2/9 1/9 2/9]
根据上述关系,可以绘制出如图 13-5 所示的归一化直方图。对比图 13-4 与图 13-5,可以看到,归一化直方图与直方图在外观上是一致的,只是 y 轴的标签不同而已。
本例中,在直方图内,y 轴显示的标签是 1、2、3;在归一化直方图中,y 轴显示的标签是 1/9、2/9、3/9。
在 OpenCV 的官网上,特别提出了要注意三个概念:DIMS、BINS、RANGE。
- DIMS:表示在绘制直方图时,收集的参数的数量。一般情况下,直方图中收集的数据只有一种,就是灰度级。因此,该值为 1。
- RANGE:表示要统计的灰度级范围,一般为[0, 255]。0 对应的是黑色,255 对应的是白色。
- BINS:参数子集的数目。在处理数据的过程中,有时需要将众多的数据划分为若干个组,再进行分析。
例如,针对图 13-1 中的灰度级,你可能希望将两个像素值作为一组讨论。这样,整个灰度级被划分为三组,具体为{ {1,2} , {3,4} , {5} }。图 13-6 所示的是划分前后的直方图情况。
也可以按照上述方式对灰度图像进行划分。例如,在灰度图像中,将[0, 255]区间内的 256个灰度级,按照每 16 个像素一组划分为子集:
[0, 255] = [0, 15] ∪ [16, 31] ∪…∪[240, 255]
按照上述方式,整个灰度级范围可以划分为 16 个子集,具体为:
整个灰度级范围 = bin1 ∪ bin2 ∪…∪ bin16
子集划分完以后,某灰度图像生成的直方图如图 13-7 所示(图中的 b1 代表 bin1,b2 代表bin2,以此类推)。
下面讨论 BINS 的值:
- 针对图 13-1,在原始图像中,共有 5 个灰度级,其 BINS 值为 5。在以 2 个灰度级为一个小组划分子集后,得到 3 个子集,其 BINS 值为 3。
- 针对灰度图像,灰度级区间为[0, 255],共有 256 个灰度级,其 BINS 值为 256;在以 16个灰度级为一个小组划分子集后,其 BINS 值为 16。
说白了就是柱子的数量
绘制直方图
Python 的模块 matplotlib.pyplot 中的 hist()
函数能够方便地绘制直方图,我们通常采用该函数直接绘制直方图(机器学习也用的这个)。除此以外,OpenCV 中的cv2.calcHist()函数
能够计算统计直方图,还可以
在此基础上绘制图像的直方图。下面分别讨论这两种方式。
使用Numpy绘制直方图
模块 matplotlib.pyplot 提供了一个类似于 MATLAB 绘图方式的框架,可以使用其中的matplotlib.pyplot.hist()函数
(以下简称为 hist()函数)来绘制直方图。
此函数的作用是根据数据源和灰度级分组绘制直方图。其基本语法格式为:
matplotlib.pyplot.hist(X,BINS)
其中两个参数的含义如下:
-
X:数据源,必须是一维的。图像通常是二维的,需要使用 ravel()函数将图像处理为一维数据源以后,再作为参数使用。
-
BINS:BINS 的具体值,表示灰度级的分组情况。
函数 ravel()的作用是将二维数组降维成一维数组。例如,有图像 a,其值为:
使用函数 ravel()对 a 进行处理:
b = a.ravel()
可以得到 b 为:
示例:使用 hist()函数绘制一幅图像的直方图。
代码如下:
import cv2
import matplotlib.pyplot as plt
o=cv2.imread("boat.jpg")
plt.hist(o.ravel(),256)
plt.show()
运行结果:
示例:使用函数 hist()将一幅图像的灰度级划分为 16 组后,绘制该图像的直方图。
将上面的255改成了16
import cv2
import matplotlib.pyplot as plt
o=cv2.imread("boat.jpg")
plt.hist(o.ravel(),16)
plt.show()
使用OpenCV绘制直方图
OpenCV 提供了函数 cv2.calcHist()用来计算图像的统计直方图,该函数能统计各个灰度级的像素点个数。利用matplotlib.pyplot 模块中的 plot()函数,可以将函数 cv2.calcHist()的统计结果绘制成直方图
1.用cv2.calcHist()函数统计图像直方图信息
函数 cv2.calcHist()用于统计图像直方图信息,其语法格式为:
hist = cv2.calcHist( images, channels, mask, histSize, ranges, accumulate )
函数中返回值及参数的含义为:
-
hist:返回的统计直方图,是一个一维数组,数组内的元素是各个灰度级的像素个数。
-
images:原始图像,该图像需要使用“[ ]”括起来。
-
channels:指定通道编号。通道编号需要用“[ ]”括起来,如果输入图像是单通道灰度图像,该参数的值就是[0]。对于彩色图像,它的值可以是[0]、[1]、[2],分别对应通道B、G、R。
-
mask:掩模图像。当统计整幅图像的直方图时,将这个值设为 None。当统计图像某一部分的直方图时,需要用到掩模图像。
-
histSize:BINS 的值,该值需要用“[ ]”括起来。例如,BINS 的值是 256,需要使用“[256]”作为此参数值。
-
ranges:即像素值范围。例如,8 位灰度图像的像素值范围是[0, 255]。
-
accumulate:累计(累积、叠加)标识,默认值为 False。如果被设置为 True,则直方图在开始计算时不会被清零,计算的是多个直方图的累积结果,用于对一组图像计算直方
图。该参数允许从多个对象中计算单个直方图,或者实时更新直方图。该参数是可选的,一般情况下不需要设置。
示例:使用 cv2.calcHist()函数计算一幅图像的统计直方图结果,并观察得到的统计直方图信息。
代码如下:
import cv2
img=cv2.imread("boat.jpg")
hist = cv2.calcHist([img],[0],None,[16],[0,255])
print(type(hist))
print(hist.shape)
print(hist.size)
print(hist)
运行结果如下:
需要注意,在本例的 cv2.calcHist()函数中:
- 第 1 个参数“[img]”表示要绘制直方图的原始图像,是使用“[ ]”括起来的。
- 第 2 个参数表示要统计哪个通道的直方图信息。本例中读取的 img 是灰度图像,所以使
用“[0]”来表示。 - 第 3 个参数是掩模图像,在本例中的值为“None”,表示计算整幅图像的直方图。
- 第 4 个参数“[16]”表示 BINS 的值是 16,也就是分了16组
- 第 5 个参数“[0, 255]”表示灰度级的范围是[0, 255]。
<class 'numpy.ndarray'>
(16, 1)
16
[[ 12575.][ 39591.][ 56651.][ 38932.][ 29997.][ 33472.][ 46033.][ 74555.][199718.][288966.][136663.][ 44440.][ 20355.][ 20691.][ 5578.][ 344.]]
示例:绘制统计直方图
import cv2
from matplotlib import pyplot as pltimg=cv2.imread("boat.jpg")
hist = cv2.calcHist([img],[0],None,[16],[0,255])plt.plot(hist,color='b')
plt.show()
运行结果:
以上都是将图像进行直方图展示函数,下面来讲下直方图在图像处理中的应用函数。
直方图均衡化
如果一幅图像拥有全部可能的灰度级,并且像素值的灰度均匀分布,那么这幅图像就具有高对比度和多变的灰度色调,灰度级丰富且覆盖范围较大。在外观上,这样的图像具有更丰富的色彩,不会过暗或过亮。
图 13-22 展示了对一幅图像进行直方图均衡化前后的对比,左图是原始图像,比较暗;右图是均衡化后的图像,色彩比较均衡。
在 OpenCV 的官网上,对图像均衡化(即直方图均衡化)前后的直方图进行了对比,如图13-23 所示。其中,左图是原始图像的直方图,可以看到灰度级集中在中间,图像中没有较暗和较亮的像素点;右图是对原图均衡化后的直方图,像素分布更均衡。
直方图均衡化的主要目的是将原始图像的灰度级均匀地映射到整个灰度级范围内,得到一个灰度级分布均匀的图像。这种均衡化,既实现了灰度值统计上的概率均衡,也实现了人类视觉系统(Human Visual System,HVS)上的视觉均衡。
直方图均衡化函数
OpenCV 使用函数 cv2.equalizeHist()实现直方图均衡化
。该函数的语法格式为:
dst = cv2.equalizeHist( src )
式中:
- dst 是直方图均衡化处理的结果。
- src 是 8 位单通道原始图像。
示例:使用函数 cv2.equalizeHist()实现直方图均衡化。
原图:
代码如下:
#-----------导入使用的模块---------------
import cv2
import matplotlib.pyplot as plt
#-----------读取原始图像---------------
img = cv2.imread('equ.bmp',cv2.IMREAD_GRAYSCALE)
#-----------直方图均衡化处理---------------
equ = cv2.equalizeHist(img)
#-----------显示均衡化前后的图像---------------
cv2.imshow("original",img)
cv2.imshow("result",equ)
#-----------显示均衡化前后的直方图---------------
plt.figure("原始图像直方图") #构建窗口
plt.hist(img.ravel(),256)
plt.figure("均衡化结果直方图") #构建新窗口
plt.hist(equ.ravel(),256)
plt.show()
#----------等待释放窗口---------------------
cv2.waitKey()
cv2.destroyAllWindows()
结果中可以看到对比很明显:在直方图均衡化之前,图像整体比较
亮;均衡化以后,图像的亮度变得比较均衡。而两幅图像的直方图的对比,则不太明显。这实际上体现了,均衡化是指综合考虑了统计概率和 HVS 的结果。
下面做简单的说明:
-
原始图像的直方图,大部分的像素值集中在右侧(线条密集)。这说明图像中位于[200,255]区间的像素点很多,图像比较亮。
-
在均衡化后的直方图中,左侧的像素点比较密集而右侧的相对比较稀疏。但是,实际上人眼并不能明显感受到像素值的细微差别,所以我们可以将相近的像素值看成同一个像素值,这样就会得到类似于图 13-29 的直方图。此时,直方图内灰度级的分布就比较均衡了,是均衡一致的直方图。
相关文章:

opencv进阶01-直方图的应用及示例cv2.calcHist()
直方图是什么? 直方图是一种图形表示方法,用于显示数据中各个数值或数值范围的分布情况。它将数据划分为一系列的区间(也称为“箱子”或“bin”),然后统计每个区间中数据出现的频次(或频率)。直…...

网络通信原理TCP的四次断开连接(第四十九课)
FIN:发端完成发送任务标识。用来释放一个连接。FIN=1表明此报文段的发送端的数据已经发送完毕,并要求释放连接。 SEQ:序号字段。 TCP链接中传输的数据流中每个字节都编上一个序号。序号字段的值指的是本报文段所发送的数据的第一个字节的序号。 序列号为X ACK :确认号 。 …...

(二)结构型模式:2、桥接模式(Bridge Pattern)(C++实现示例)
目录 1、桥接模式(Bridge Pattern)含义 2、桥接模式应用场景 3、桥接模式的UML图学习 4、C实现桥接模式的示例 1、桥接模式(Bridge Pattern)含义 桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离&#…...

FPGA_学习_16_IP核_ROM
在寻找APD最合适的偏压的过程中,一般会用到厂商提供一条曲线,横坐标是温度的变化,纵坐标表示击穿偏压的变化,但每个产品真正的击穿偏压是有差异的。 为了能够快速的找到当前温度下真实的击穿偏压,我们可以这样做&#…...

机器学习---对数几率回归
1. 逻辑回归 逻辑回归(Logistic Regression)的模型是一个非线性模型, sigmoid函数,又称逻辑回归函数。但是它本质上又是一个线性回归模型,因为除去sigmoid映射函 数关系,其他的步骤,算法都是…...

网络通信原理IP头部格式(第四十二课)
字段作用解析:1)版本: 指的IP地址的版本 (IPv4 或 IPV6)2)首部长度: 次数据包的首部长度一共是多少,没有加可选项3)优先级与服务类型:表示****数据包是否需要优选传递4)总长度: 表示的是整个数据包的大小,也就****是首部+数据5)标识符、标志、段偏移量:的作用将拆开的…...

Flink多流处理之join(关联)
Flink的API中只提供了join的算子,并没有left join或者right join,这里我们就介绍一下join算子的使用,其实join算子底层调用的就是coGroup,具体原理这里就不过多介绍了,如果感兴趣可以看我前面发布的文章Flink多流操作之coGroup. 数据源➜ ~ nc -lk 1111 101,A 102,B 103,C 10…...

LeetCode Top100 Liked 题单(序号34~51)
34. Find First and Last Position of Element in Sorted Array 题意:找到非递减序列中目标的开头和结尾 我的思路 用二分法把每一个数字都找到,最后返回首尾两个数 代码 Runtime12 ms Beats 33.23% Memory14 MB Beats 5.16% class Solution {…...

视觉slam十四讲---第一弹三维空间刚体运动
1.旋转矩阵 1.1内积 1.2外积 1.3坐标系间的欧式变换 相机运动是一个刚体运动,它保证了同一个向量在各个坐标系下的长度和夹角都不会 发生变化。这种变换称为欧氏变换。 旋转矩阵:它是一个行列式为 1 的正交矩阵。 旋转矩阵为正交阵,它的逆…...

手把手教你配置Jenkins自动化邮件通知
完成基于Jenkins的持续集成部署后,自动化测试执行后,测试结果需要通知到相关人员,除了钉钉通知外我们还可以通过Email通知到对应负责人,这里记录一下测试结果通过Jenkins邮件通知的配置与部署 01、安装插件 方法1: 进…...

Arcgis连续数据的分类(求不同值域的面积)
问题描述:如果得到的一个连续的影响数值数据,但是我们想求取某一段值域的面积占比,需要进行以下操作: 1.按照数值重分类,将某段数值变成一个类别 2.栅格转矢量,再求取面积...

C++ 函数
函数是一组一起执行一个任务的语句。每个 C 程序都至少有一个函数,即主函数 main() ,所有简单的程序都可以定义其他额外的函数。 您可以把代码划分到不同的函数中。如何划分代码到不同的函数中是由您来决定的,但在逻辑上,划分通常…...

关于如何创建一个windows窗口的exe文件
如何创建一个windows窗口exe文件,具体参照这个博主: http://t.csdn.cn/pfQK5 以下是实现代码,注意用vs打开: #pragma comment( linker, "/subsystem:\"windows\" /entry:\"WinMainCRTStartup\"" …...

re学习(33)攻防世界-secret-galaxy-300(动态调试)
下载压缩包: 下载链接:https://adworld.xctf.org.cn/challenges/list 参考文章:攻防世界逆向高手题之secret-galaxy-300_沐一 林的博客-CSDN博客 发现这只是三个同一类型文件的三个不同版本而已,一个windows32位exe࿰…...

springboot工程集成前端编译包,用于uni-app webView工程,解决其需独立部署带来的麻烦,场景如页面->画布->图片->pdf
前端工程 访问方式 http://127.0.0.1:8080/context/frontEnd/index放行 public class SecurityConfig extends WebSecurityConfigurerAdapter { "/frontEnd/**",SysFrontEndController import lombok.extern.slf4j.Slf4j; import nl.basjes.shaded.org.springfram…...

NeuralNLP-NeuralClassifier的使用记录(二),训练预测自己的【中文文本多分类】
NeuralNLP-NeuralClassifier的使用记录,训练预测自己的【中文文本多分类】 数据准备: 与英文的训练预测一致,都使用相同的数据格式,将数据通过代码处理为JSON格式,以下是我使用的一种,不同的原数据情况…...

express学习笔记8 - 文件上传 下载以及预览
一、上传 1、 安装multer (任意选其中一种) yarn add multer --S npm install multer --S 2、新建配置文件(utils/multerConfig) const multer require(multer); const mkdirp require(mkdirp); // const sd require(silly-datetime); const path require(path);con…...

Python系统学习1-9-类(一)
一、类之初印象 1、类就是空表格,将变量(列名)和函数(行为)结合起来 2、创建对象,表达具体行 3、创建类就是创建数据的模板 --操作数据时有提示 --还能再组合数据的行为 --结构更加清晰 4、类的内存分配…...

什么是公网、私网、内网、外网?
中午好,我的网工朋友。 最近经常有很多小白朋友在问,公网、私网、内网、外网,这些的概念是啥样的,又该怎么去界定。 关于IP地址,确实没有太明确的区分,其实也不必太过咬文嚼字。 内网、外网就是一个参考…...

一篇文章教会你搭建私人kindle图书馆,并内网穿透实现公网访问
搭建私人kindle图书馆,并内网穿透实现公网访问 在电子书风靡的时期,大部分人都购买了一本电子书,虽然这本电子书更多的时候是被搁置在储物架上吃灰,或者成为盖泡面的神器,但当亚马逊发布消息将放弃电子书在中国的服务…...

好用的安卓手机投屏到mac分享
工具推荐:scrcpy github地址:https://github.com/Genymobile/scrcpy/tree/master mac使用方式 安装环境,打开terminal,执行以下命令,没有brew的先安装brew brew install scrcpy brew install android-platform-too…...

df -h
df -h 命令用于查看磁盘占用的空间 Filesystem:表示该文件系统位于哪个分区,因此该列显示的是设备名称; Used:表示用掉的磁盘空间大小; Available:表示剩余的磁盘空间大小; Use%:磁盘…...

彻底卸载Android Studio
永恒的爱是永远恪守最初的诺言。 在安装Android Studio会有很多问题导致无法正常运行,多次下载AS多次错误后了解到,删除以下四个文件才能彻底卸载Android Studio。 第一个文件:.gradle 路径:C:\Users\yao(这里yao是本…...

QT 5.12配置OpenCV3.4.10
主要过程:使用cmake编译源码,生成Mingw64位 下的OpenCV库 三篇博客解决问题: 1.Windows下安装Qt并使用cmake配置opencv3.4.10(含错误记录及解决办法)_d:\qt\qt5.14.2\5.14.2\mingw73_64\include\qtcore\qg_会飞的DA象的博客-CSDN博客 2.【…...

Qt应用开发(基础篇)——选项卡窗口 QTabWidget
一、前言 QTabWidget类继承于QWidget,是一个拥有选项卡的窗口部件。 QTabWidget类有一个选项卡栏QTabBar和一个页面区域,用来显示和选项卡相关联的界面。用户通过点击选项卡或者自定义快捷方式(ALTKey)切换页面。 二、QTabWidget类 1、count 该属…...

Socks5代理在多线程爬虫中的应用
在进行爬虫开发过程中,我们常常需要处理大量的数据,并执行多任务并发操作。然而,频繁的请求可能会引起目标网站的反爬机制,导致IP封禁或限制访问。为了规避这些限制,我们可以借助Socks5代理的强大功能,通过…...

机器学习笔记:主动学习(Active Learning)初探
1 基本介绍 监督学习问题中,存在标记成本昂贵且难以大量获取的问题。 针对一些特定任务,只有行业专家才能为样本做上准确标记。在此问题背景下,主动学习(Active Learning, AL)尝试通过选择性地标记较少数据而训练出表…...

linux github 仓库管理常用操作
linux 的常用操作 linux 本地 ssh验证连接github账号本地仓库连接远程私有仓库push/pull操作 Connecting to Github with ssh git local configuration If you are using git for the first time, configure the user name and email in the device. git config --global u…...

IT运维:使用数据分析平台监控深信服防火墙
概述 深信服防火墙自身监控可以满足绝大部分需求,比如哪个应用占了最大带宽,哪个用户访问了哪些网站?这里我们为什么使用鸿鹄呢?因为我们要的是数据的处理和分析,比如某个用户在某个事件都做了哪些行为,这个…...

深入解析 Axios Blob 的使用方法及技巧
在 Web 开发中,处理文件传输是一个常见的需求。Blob(二进制对象)是一种表示二进制数据的方式,常用于处理文件和多媒体数据。本文将介绍如何使用 Axios 和 Blob 来处理文件传输。 Axios Blob 概念 在开始之前,让我们先…...