OpenCV-Python (官方)中文教程(部分一)_Day20

22.直方图

22.1直方图的计算,绘制与分析

使用 OpenCV 或 Numpy 函数计算直方图

使用 Opencv 或者 Matplotlib 函数绘制直方图

将要学习的函数有:cv2.calcHist(),np.histogram()

什么是直方图呢?通过直方图你可以对整幅图像的灰度分布有一个整体的 了解。直方图的 x 轴是灰度值(0 到 255),y 轴是图片中具有同一个灰度值的 点的数目。

直方图其实就是对图像的另一种解释。一下图为例,通过直方图我们可以 对图像的对比度,亮度,灰度分布等有一个直观的认识。几乎所有的图像处理 软件都提供了直方图分析功能。下图来自Cambridge in Color website,强 烈推荐你到这个网站了解更多知识。

让我们来一起看看这幅图片和它的直方图吧。(要记住,直方图是根据灰度 图像绘制的,而不是彩色图像)。直方图的左边区域像是了暗一点的像素数量, 右侧显示了亮一点的像素的数量。从这幅图上你可以看到灰暗的区域比两的区 域要大,而处于中间部分的像素点很少。

(1).统计直方图

现在我们知道什么是直方图了, 那怎样获得一副图像的直方图呢? OpenCV和Numpy 都有内置函数做这件事。在使用这些函数之前我们有 必要想了解一下直方图相关的术语。

BINS上面的直方图显示了每个灰度值对应的像素数。如果像素值为 0 到 255,你就需要 256 个数来显示上面的直方图。但是,如果你不需要知道每一个像素值的像素点数目的,而只希望知道两个像素值之间的像素点数目怎么办呢?举例来说,我们想知道像素值在 0 到 15 之间的像素点的数目,接着 是 16 到 31,....,240 到 255。我们只需要 16 个值来绘制直方图。OpenCV Tutorials   on  histograms中例子所演示的内容。

那到底怎么做呢?你只需要把原来的 256 个值等分成 16 小组,取每组的总和。而这里的每一个小组就被成为 BIN。第一个例子中有 256 个 BIN,第 二个例子中有 16个 BIN。在 OpenCV  的文档中用 histSize  表示   BINS。

DIMS表示我们收集数据的参数数目。在本例中,我们对收集到的数据只考虑一件事:灰度值。所以这里就是 1。

RANGE:就是要统计的灰度值范围,一般来说为 [0,256],也就是说所有的灰度值

使用 OpenCV 统计直方图 函数 cv2.calcHist 可以帮助我们统计一幅图像的直方图。我们一起来熟悉一下这个函数和它的参数:

cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])

  1. images: 原图像(图像格式为 uint8 或 float32)。当传入函数时应该 用中括号 [] 括起来,例如:[img]。

  2. channels: 同样需要用中括号括起来,它会告诉函数我们要统计那幅图 像的直方图。如果输入图像是灰度图,它的值就是 [0];如果是彩色图像 的话,传入的参数可以是  [0],[1],[2]   它们分别对应着通道  B,G,R。

  3. mask: 掩模图像。要统计整幅图像的直方图就把它设为 None。但是如 果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像,并 使用它。(后边有例子)

  4. histSize:BIN  的数目。也应该用中括号括起来,例如:[256]。

  5. ranges: 像素值范围,通常为 [0,256]

让我们从一副简单图像开始吧。以灰度格式加载一幅图像并统计图像的直方图。

import cv2

import numpy as np

import matplotlib.pyplot as plt

# 1. 读取图像(灰度模式)

img = cv2.imread('home.jpg', 0)  # 参数0表示以灰度模式读取

# 检查图像是否成功加载

if img is None:

    raise FileNotFoundError("无法加载图像,请检查路径")

# 2. 计算直方图

hist = cv2.calcHist(

    [img],       # 输入图像(必须用列表包裹)

    [0],         # 通道索引(灰度图是0)

    None,        # 掩膜(None表示整个图像)

    [256],       # 直方图大小(bin的数量)

    [0, 256]     # 像素值范围

)

# 3. 可视化直方图

plt.figure(figsize=(10, 5))

plt.title("Grayscale Histogram")

plt.xlabel("Pixel Value")

plt.ylabel("Frequency")

plt.xlim([0, 256])  # X轴范围

plt.plot(hist, color='black')

plt.grid(True, linestyle='--', alpha=0.7)

plt.show()

# 4. 可选:显示原图

cv2.imshow("Original Image", img)

cv2.waitKey(0)

cv2.destroyAllWindows()

hist   是一个  256x1  的数组,每一个值代表了与次灰度值对应的像素点数目。

使用 Numpy 统计直方图 Numpy 中的函数 np.histogram() 也可以帮 我们统计直方图。你也可以尝试一下下面的代码:

import cv2

import numpy as np

import matplotlib.pyplot as plt

# 1. 读取图像(灰度模式)

img = cv2.imread('11111.png', 0)  # 参数0表示以灰度模式读取

# 检查图像是否成功加载

if img is None:

    raise FileNotFoundError("无法加载图像,请检查路径")

# 2. 使用numpy计算直方图(不需要中括号)

hist, bins = np.histogram(img.ravel(),  # 将图像展平为一维数组

                         bins=256,      # 直方图的bin数量

                         range=[0, 256]) # 像素值范围

# 3. 可视化直方图

plt.figure(figsize=(10, 5))

plt.title("Grayscale Histogram (numpy)")

plt.xlabel("Pixel Value")

plt.ylabel("Frequency")

plt.xlim([0, 256])  # X轴范围

# 注意:bins比hist多一个元素,需要调整显示

plt.bar(bins[:-1],        # X轴坐标(bin的左边界)取bins数组除最后一个元素外的所有值(因为bins比hist多一个元素)

        hist,             # Y轴高度(频数)每个bin对应的像素频数

        width=1,          # 柱子的宽度 设置每个柱子的宽度为1(保证柱子之间无间隙)

        color='black',    # 柱子填充颜色 黑色

        edgecolor='none') # 柱子边框颜色(无边框)

plt.grid(True,           # 启用网格线

         linestyle='--', # 虚线样式

         alpha=0.7)      # 透明度(0.7表示70%不透明)

plt.show()

# 4. 可选:显示原图

cv2.imshow("Original Image", img)

cv2.waitKey(0)

cv2.destroyAllWindows()

hist 与上面计算的一样。但是这里的 bins 是 257,因为 Numpy 计算 bins 的方式为:0-0.99,1-1.99,2-2.99 等。所以最后一个范围是 255-255.99。 为了表示它,所以在 bins 的结尾加上了 256。但是我们不需要 256,到 255 就够了。

其 他:Numpy    还 有 一 个 函 数   np.bincount(), 它 的 运 行 速 度 是 np.histgram   的 十 倍。 所 以 对 于 一 维 直 方 图, 我 们 最 好 使 用 这 个 函 数。 使 用   np.bincount   时 别 忘 了 设 置   minlength=256。 例 如, hist=np.bincount(img.ravel(),minlength=256)

注 意:OpenCV的函数要比 np.histgram()快40倍.所以坚持使用OpenCV 函数.

(2).绘制直方图

有两种方法来绘制直方图:

1.Short Way(简单方法):使用 Matplotlib 中的绘图函数。

2.Long Way(复杂方法):使用 OpenCV 绘图函数

使用 Matplotlib 中有直方图绘制函数:matplotlib.pyplot.hist()

它可以直接统计并绘制直方图。你应该使用函数  calcHist()  或 np.histogram()

统计直方图。

以下是关于 matplotlib.pyplot.hist()、cv2.calcHist() 和 np.histogram() 三个函数的详细对比分析,包括它们的区别、优缺点和适用场景:

1. matplotlib.pyplot.hist()​

特点:

​​一体化操作:直接统计并绘制直方图(计算+可视化一步完成)

​​接口简单:无需手动处理 bins 和 hist 的对应关系

​​可视化集成:自动添加坐标轴、标题等图形元素

import cv2

from matplotlib import pyplot as plt

 

img = cv2.imread('drawing.png',0) 

plt.hist(img.ravel(),256,[0,256])

plt.show()

2. cv2.calcHist()​​

特点:

​​OpenCV专属:针对图像数据高度优化

​​多通道支持:可同时计算多通道直方图

​​灵活掩膜:支持指定ROI区域计算

import cv2

img = cv2.imread('image.jpg', 0)

hist = cv2.calcHist([img], [0], None, [256], [0, 256])

# 需要手动绘制

plt.plot(hist, color='red')

plt.title('OpenCV Histogram')

plt.show()

3. np.histogram()​​

特点:

​​纯计算函数:只返回统计结果,不包含绘图

​​通用性强:适用于任何数值数据(不限于图像)

​​精确控制:可自定义 bins 和 range

import numpy as np

import matplotlib.pyplot as plt

img = cv2.imread('image.jpg', 0)

hist, bins = np.histogram(img.ravel(), bins=256, range=[0, 256])

# 手动绘制(需处理bins边界)

plt.bar(bins[:-1], hist, width=1)

plt.title('NumPy Histogram')

plt.show()

如何选择?​

​​1、需要快速可视化​​ → plt.hist()

plt.hist(img.ravel(), bins=256, range=[0,256], alpha=0.7)

​​2、OpenCV图像处理流程​​ → cv2.calcHist()

hist = cv2.calcHist([img], [0], mask, [256], [0,256])

​​3、精确控制或非图像数据​​ → np.histogram()

hist, bins = np.histogram(data, bins=50, range=[min_val, max_val])

4、多通道图像分析​​ → cv2.calcHist() + 循环

colors = ('b','g','r')

for i, col in enumerate(colors):

    hist = cv2.calcHist([img], [i], None, [256], [0,256])

plt.plot(hist, color=col)

性能实测对比​

import time

import matplotlib.pyplot as plt

import cv2

import numpy as np

img = cv2.imread('drawing.png', 0)

# 测试plt.hist

t1 = time.time()

plt.hist(img.ravel(), bins=256)

print(f"plt.hist: {time.time()-t1:.4f}s")

# 测试cv2.calcHist

t2 = time.time()

hist = cv2.calcHist([img], [0], None, [256], [0,256])

print(f"cv2.calcHist: {time.time()-t2:.4f}s")

# 测试np.histogram

t3 = time.time()

hist, bins = np.histogram(img.ravel(), bins=256)

print(f"np.histogram: {time.time()-t3:.4f}s")

典型输出(4000x3000像素图像):

plt.hist: 3.7026s

cv2.calcHist: 0.0060s

np.histogram: 0.0209s

或者你可以只使用 matplotlib 的绘图功能,这在同时绘制多通道(BGR) 的直方图,很有用。但是要告诉绘图函数你的直方图数据在哪里。运行 一下下面的代码:

import cv2

from matplotlib import pyplot as plt

img = cv2.imread('drawing.png') #读取BGR格式的彩色图像(默认加载为3通道numpy数组)

if img is None:

    raise FileNotFoundError("无法加载图像,请检查路径")

#元组存储三个颜色符号,对应Matplotlib的绘图颜色:

#'b': 蓝色(Blue,OpenCV的通道0)

#'g': 绿色(Green,通道1)

#'r': 红色(Red,通道2)

color = ('b', 'g', 'r')

#同时获取索引i(0,1,2)和颜色符号col('b','g','r')

for i, col in enumerate(color):

    #[img]: 输入图像(必须放在列表中)[i]: 通道索引(0=Blue, 1=Green, 2=Red)

    #None: 不使用掩膜(计算全图)[256]: 直方图bin数量(256级)[0,256]: 像素值范围(0~255)

    histr = cv2.calcHist([img], [i], None, [256], [0,256])

    #histr: 当前通道的直方图数据(256维向量)color=col: 使用对应通道的颜色(蓝/绿/红)

    plt.plot(histr, color=col, label=f'{col.upper()} Channel')  # 添加标签

plt.title('RGB Channel Histogram')

plt.xlabel('Pixel Value')

plt.ylabel('Frequency')

plt.xlim([0, 256]) #限制X轴显示范围为0~256(覆盖所有像素值)

plt.legend()  # 显示图例

plt.grid(True, linestyle='--', alpha=0.5)  # 添加网格线

plt.show()

输出效果​​

将显示一个包含三条曲线的直方图:

​​蓝色曲线​​: 蓝色通道的像素值分布

​​绿色曲线​​: 绿色通道的分布

​​红色曲线​​: 红色通道的分布

(X轴为像素值0~255,Y轴为对应像素值的出现频率)

关键点总结​​

​​enumerate(): 同时获取索引和值,避免手动计数

​​calcHist()的列表输入: 必须用[img]和[i]传递参数

​​通道顺序: OpenCV默认BGR,Matplotlib默认RGB,注意颜色对应关系

使用 OpenCV 自带函数绘制直方图比较麻烦,这里不作介 绍,有兴趣可以自己研究。可以参考 OpenCV-Python2 的官方示例。

(3).使用掩模

要统计图像某个局部区域的直方图只需构建一副掩模图像。将要统计的部分设置成白色,其余部分为黑色,就构成一副掩模图像。然后把这个掩模图像传给函数就可以了。

import matplotlib.pyplot as plt

import cv2

import numpy as np

img = cv2.imread('drawing.png',0)

 

# create a mask

#创建与图像尺寸相同的全黑掩膜(所有像素值为0)img.shape[:2]获取图像的高度和宽度(忽略通道数)

mask = np.zeros(img.shape[:2], np.uint8) 

#将掩膜中y=100:300,x=100:400的矩形区域设为白色(255),该区域表示后续要分析的ROI

mask[100:300, 100:400] = 255

#对图像进行按位与操作,保留掩膜白色区域对应的原图像素

#参数说明:前两个img:输入图像(灰度图),mask=mask:指定掩膜区域

#效果:非ROI区域变为黑色(0),ROI区域保留原灰度值

masked_img = cv2.bitwise_and(img,img,mask = mask)

# Calculate histogram with mask and without mask

# Check third argument for mask

#计算全局和局部直方图

hist_full = cv2.calcHist([img],[0],None,[256],[0,256])

hist_mask = cv2.calcHist([img],[0],mask,[256],[0,256])

plt.subplot(221), plt.imshow(img, 'gray') 

plt.subplot(222), plt.imshow(mask,'gray') 

plt.subplot(223), plt.imshow(masked_img, 'gray')

#默认先画的hist_full为蓝色,后画的hist_mask为橙色

plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask) 

plt.xlim([0,256])

 

plt.show()

结果如下,其中蓝线是整幅图像的直方图,橙色线是进行掩模之后的直方图。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/903578.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数电发票整理:免费实用工具如何高效解析 XML 发票数据

如今数字电子发票越来越普及,但是数电发票的整理还是颇有讲究~ 今天给大家介绍一个 XML 发票阅读器。使用它完全不收取任何费用,且无广告干扰,对财务人员而言十分实用。 01 软件介绍 这款软件就是XML格式(数电票)阅读…

深度学习正则化:原理、方法与应用深度解析

摘要 本文深入探讨深度学习中的正则化技术,介绍其避免过拟合的重要性,详细讲解常见的正则化方法,如 L 1 L_1 L1​和 L 2 L_2 L2​正则化、Dropout等,并通过线性回归案例和神经网络训练流程对其进行直观阐释。帮助读者理解正则化原…

【爬虫】deepseek谈爬虫工具

2025 年,随着 Web 技术的演进和反爬机制的升级,工具生态也会进一步优化。以下是 2025 年爬虫 & 自动化测试的前沿工具预测,结合行业趋势和现有技术发展方向: 🚀 2025 年推荐组合(预测版) 1…

SQLMesh 测试自动化:提升数据工程效率

在现代数据工程中,确保数据模型的准确性和可靠性至关重要。SQLMesh 提供了一套强大的测试工具,用于验证数据模型的输出是否符合预期。本文将深入探讨 SQLMesh 的测试功能,包括如何创建测试、支持的数据格式以及如何运行和调试测试。 SQLMesh …

Java学习手册:Spring 中常用的注解

一、组件注解 Component :用于标记一个类为 Spring 管理的 Bean,是 Spring 的基本组件注解。Spring 会通过类路径扫描自动检测并注册标记了 Component 的类为 Bean。Service :是 Component 的派生注解,用于标记服务层类&#xff…

前端跨域问题详解:原因、解决方案与最佳实践

引言 在现代Web开发中,跨域问题是前端工程师几乎每天都会遇到的挑战。随着前后端分离架构的普及和微服务的发展,跨域请求变得愈发常见。本文将深入探讨跨域问题的本质、各种解决方案以及在实际开发中的最佳实践。 一、什么是跨域问题? 1.1…

[计算机网络]物理层

文章目录 物理层的概述与功能传输介质双绞线:分类:应用领域: 同轴电缆:分类: 光纤:分类: 无线传输介质:无线电波微波:红外线:激光: 物理层设备中继器:放大器:集线器(Hub)&#xff1a…

大连理工大学选修课——机器学习笔记(9):线性判别式与逻辑回归

线性判别式与逻辑回归 概述 判别式方法 产生式模型需要计算输入、输出的联合概率 需要知道样本的概率分布,定义似然密度的隐式参数也称为基于似然的分类 判别式模型直接构造判别式 g i ( x ∣ θ i ) g_i(x|\theta_i) gi​(x∣θi​),显式定义判别式…

OpenCV 图像处理核心技术 (第二部分)

欢迎来到 OpenCV 图像处理的第二部分!在第一部分,我们学习了如何加载、显示、保存图像以及访问像素等基础知识。现在,我们将深入探索如何利用 OpenCV 提供的强大工具来修改和分析图像。 图像处理是计算机视觉领域的基石。通过对图像进行各种…

【鸿蒙HarmonyOS】一文详解华为的服务卡片

7.服务卡片 1.什么是卡片 Form Kit(卡片开发服务)提供一种界面展示形式,可以将应用的重要信息或操作前置到服务卡片(以下简称“卡片”),以达到服务直达、减少跳转层级的体验效果。卡片常用于嵌入到其他应…

探索目标检测:边界框与锚框的奥秘

笔者在2022年开始学习目标检测的时候,对各种框的概念那是相当混淆,比如: 中文名词:边界框、锚框、真实框、预测框等英文名词:BoundingBox、AnchorBox、Ground Truth等 同一个英文名词比如BoundingBox翻译成中文也有多个…

[原创](现代Delphi 12指南):[macOS 64bit App开发]: [1]如何使用原生NSAlert消息框 (runModal模式)

[作者] 常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共24年] 职业生涯: 22年 开发语言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 开发工具: Visual Studio、Delphi、XCode、…

LangChain的向量RAG与MCP在意图识别的主要区别

LangChain的向量RAG与MCP在意图识别实现上的区别主要体现在技术路径、流程设计以及应用场景三个方面: 1. 技术路径差异 LangChain向量RAG 语义相似度驱动:通过用户输入的原始查询与向量化知识库的语义匹配实现意图识别。例如,用户提问"…

[特殊字符] Spring Cloud 微服务配置统一管理:基于 Nacos 的最佳实践详解

在微服务架构中,配置文件众多、管理复杂是常见问题。本文将手把手演示如何将配置集中托管到 Nacos,并在 Spring Cloud Alibaba 项目中实现统一配置管理 自动刷新机制。 一、为什么要使用 Nacos 统一配置? 传统方式下,每个服务都…

2025平航杯—团队赛

2025平航杯团队赛 计算机取证 分析起早王的计算机检材,起早王的计算机插入过USB序列号是什么(格式:1)分析起早王的计算机检材,起早王的便签里有几条待干(格式:1)分析起早王的计算机检材,起早王的计算机默认浏览器是什…

JSON-RPC 2.0 规范中文版——无状态轻量级远程过程调用协议

前言 JSON-RPC是一种简单、轻量且无状态的远程过程调用(RPC)协议,它允许不同系统通过标准化的数据格式进行通信。自2010年由JSON-RPC工作组发布以来,已成为众多应用中实现远程交互的基础协议之一。本规范主要表达了JSON-RPC 2.0版…

微控制器编程 | ISP、IAP 与 ICP 的原理与比较

注:英文引文,机翻未校。 图片清晰度限于引文原状。 Introduction to Programming of Microcontroller: ISP, IAP and ICP 微控制器编程介绍:ISP、IAP 和 ICP Date: 30-11-2022 1. What is Microcontroller Programming 什么是微控制器编…

Allegro23.1新功能之新型via structure创建方法操作指导

Allegro23.1新功能之新型via structure创建方法操作指导 Allegro升级到了23.1后,支持创建新型via structure 通过直接定义参数来生成 具体操作如下 打开软件,选择 Allegro PCB Designer

IBM WebSphere Application Server 7.0/8.5.5证书过期问题处理

证书过期错误日志: [3/14/16 7:22:20:332 PDT] 0000007d WSX509TrustMa E CWPKI0312E: The certificate with subject DN CNMXSYSTEMS, OUctgNodeCell01, OUctgNode01, OIBM, CUS has an end date Mon Jan 11 11:17:18 PST 2016 which is no longer valid. [3/14/…

select,poll,epoll区别联系

selsect,poll,epoll区别联系 目录 一、区别 二、联系 select、poll 和 epoll 都是在 Linux 系统中用于实现 I/O 多路复用的机制,它们的主要目的是让程序能够同时监控多个文件描述符,以判断是否有事件发生,从而提高 I/O 操作的效率。 一、区…