当前位置: 首页 > news >正文

揭开图像的秘密:OpenCV直方图入门详解

揭开图像的秘密:OpenCV直方图入门详解

大家好!在你学习计算机视觉的旅途中,你一定会遇到一个既基础又极其强大的工具–直方图。初看这个词可能有点抽象,但别担心,它其实非常直观。简单来说,图像直方图就是一个“像素人口普查”图。它统计了一张图片中每个亮度级别的像素有多少个。通过这张图,我们可以一眼看出照片是偏暗、偏亮,还是对比度适中。(图片来源于网络,如有侵权联系我删除)

一、什么是直方图?

想象一下,我们有一张8-bit的灰度图。这意味着每个像素的亮度值都在0(纯黑)到255(纯白)之间。

直方图的X轴代表像素的亮度值(0-255),而Y轴代表具有该亮度值的像素数量(频率)。

图像类型对应的直方图特点
偏暗的图像直方图的大部分数据会集中在X轴的左侧(低亮度值区域)
偏亮的图像直方图的大部分数据会集中在X轴的右侧(高亮度值区域)
低对比度图像直方图的数据会记载一个很窄的区域里,说明像素的亮度变化不大
高对比度图像直方图的数据会分布在X轴的大部分区域,说明图像同时包含了很暗和很亮的像素

所以,直方图就是图像的“指纹”,它揭示了图像的亮度分布和对比度信息,是进行图像分析、分割和增强的重要依据。

二、OpenCV实战:计算并绘制直方图

理论看完了,让我们立刻动手实践!在OpenCV中,我们主要使用cv2.calcHist()函数来计算直方图。

函数原型:cv2.calcHist()

hist = cv2.calcHist(images, channels, mask, histSize, ranges)

image:源图像,必须用方括号括起来,例如[image]

channels: 指定要计算哪个通道的直方图。同样要用方括号。

  • 对于灰度图,它是 [0]。
  • 对于 BGR 彩色图,[0] 是蓝色通道,[1] 是绿色通道,[2] 是红色通道。

mask: 掩码图像。如果你想计算整张图的直方图,设为 None。如果你只想分析图中某个特定区域,可以传入一个掩码图像。

histSize: 也叫 BINS 的数量。这决定了直方图 X 轴的“柱子”数量。对于 8-bit 图像,通常设为 [256],表示我们关心 0 到 255 每一个亮度级别的像素数。

ranges: 像素值的范围。对于 8-bit 图像,范围是 0 到 255,所以我们传入 [0, 256](包含 0,不包含 256)。

1.计算灰度图的直方图

计算很简单,但OpenCV本身不能直接画图,所以我们通常借助matplotlib库来可视化

import cv2
import numpy as np
from matplotlib import pyplot as plt# 1. 加载一张图片并转为灰度图
img = cv2.imread('your_image.jpg') # 替换成你的图片路径
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 2. 使用 cv2.calcHist() 计算直方图
# 参数: [源图像], [通道], 无掩码, [BINS数量], [像素值范围]
hist = cv2.calcHist([gray_img], [0], None, [256], [0, 256])# 3. 使用 Matplotlib 显示直方图
plt.figure()
plt.title("Grayscale Histogram")
plt.xlabel("Bins (Pixel Value)")
plt.ylabel("# of Pixels (Frequency)")
plt.plot(hist)
plt.xlim([0, 256]) # 设置X轴范围
plt.show()# 同时显示原始灰度图
cv2.imshow("Grayscale Image", gray_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

运行代码,你会得到一张灰度图和它对应的直方图。试着用一张偏亮的图片和一张偏暗的图片,看看它们的直方图有什么不同!

image-20250714141053547image-20250714141158105

2.计算彩色图的直方图

彩色图的原理完全一样,我们只需要为 B, G, R 三个通道分别计算一次,然后画在同一张图上即可。

import cv2
import numpy as np
from matplotlib import pyplot as plt# 1. 加载彩色图片
img = cv2.imread('your_image.jpg') # 替换成你的图片路径# 2. 遍历三个通道 (Blue, Green, Red)
colors = ('b', 'g', 'r')
plt.figure()
plt.title("Color Histogram")
plt.xlabel("Bins")
plt.ylabel("# of Pixels")for i, col in enumerate(colors):# 计算当前通道的直方图hist = cv2.calcHist([img], [i], None, [256], [0, 256])# 绘制直方图plt.plot(hist, color = col)plt.xlim([0, 256])plt.show()cv2.imshow("Color Image", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

这段代码会生成一张包含蓝、绿、红三条线的直方图,让你能清晰地看到每个颜色通道的分布情况。

在这里插入图片描述

在这里插入图片描述

三、 直方图的应用:直方图均衡化

这是直方图最经典、最直观的应用之一。

问题:当一张图片的像素值集中在某个狭窄的范围内时(例如,整体偏暗),图像的细节就会丢失。

解决思路:直方图均衡化 。它的核心思想就是“拉伸”这个狭窄的直方图,让它均匀地分布在整个 0-255 的范围内。这样一来,图像的对比度就被大大增强了。

在 OpenCV 中,实现这个功能只需要一行代码:cv2.equalizeHist()

注意cv2.equalizeHist() 只能处理单通道的灰度图像。

import cv2
import numpy as np
from matplotlib import pyplot as plt# 加载一张对比度较低的灰度图
img = cv2.imread('low_contrast_image.jpg', 0) # 替换成你的低对比度图片, 0表示以灰度模式加载# 1. 进行直方图均衡化
equ_img = cv2.equalizeHist(img)# 2. 并排显示原始图和均衡化后的图
res = np.hstack((img, equ_img)) # 水平拼接图像
cv2.imshow("Original vs Equalized", res)# 3. 显示原始直方图和均衡化后的直方图
plt.figure(figsize=(10, 5))# 原始图直方图
plt.subplot(1, 2, 1) # 1行2列的第1个
plt.title("Original Histogram")
plt.hist(img.ravel(), 256, [0, 256])# 均衡化后直方图
plt.subplot(1, 2, 2) # 1行2列的第2个
plt.title("Equalized Histogram")
plt.hist(equ_img.ravel(), 256, [0, 256])plt.show()cv2.waitKey(0)
cv2.destroyAllWindows()

运行结果会非常惊人:

你可以清楚地看到,原始图像(左)的直方图挤在左侧,而经过均衡化处理后,图像(右)的细节变得清晰可见,其直方图也变得更加“宽广”和“平坦”。

在这里插入图片描述
在这里插入图片描述

进阶提示:全局的直方图均衡化可能会过度增强图像中的噪声。为了解决这个问题,OpenCV 还提供了一种更高级的方法,叫做 对比度受限的自适应直方图均衡化 (CLAHE) 。你可以通过 cv2.createCLAHE() 来使用它,效果通常会更好。

总结

直方图是计算机视觉中许多高级技术的基础,例如基于颜色的对象跟踪、图像分割和图像检索。理解它,就是为你未来的学习打下了坚实的基础。

现在,去寻找一些不同的图片,亲手实践一下吧!看看你能从它们的“像素人口普查”中发现什么秘密!

http://www.dtcms.com/a/279367.html

相关文章:

  • 代数基本定理最简短的证明
  • 对于独热编码余弦相似度结果为0和词向量解决了词之间相似性问题的理解
  • ubuntu之坑(十五)——设备树
  • gRPC和http长轮询
  • 新手向:Python自动化办公批量重命名与整理文件系统
  • Dubbo 学习笔记
  • 谷歌收获成果:OpenAI收购Windsurf计划告吹
  • 工业软件加密锁复制:一场技术与安全的博弈
  • Mybatis05-参数和返回
  • 以太网供电(PoE)电源
  • 编程语言设计目的与侧重点全解析(主流语言深度总结)
  • vue中使用西瓜播放器xgplayer (封装)+xgplayer-hls 播放.m3u8格式视频
  • Spark 单机模式安装与测试全攻略​
  • STM32小实验1--点亮LED
  • # 电脑待机后出现死机不能唤醒怎么解决?
  • 【终极指南】ChatGPT/BERT/DeepSeek分词全解析:从理论到中文实战
  • 2025年人工智能与网络安全国际会议(IACAINS 2025)
  • vim扩展
  • Python Web框架对比:Flask vs FastAPI
  • Kubernetes控制器详解
  • 重复频率较高的广告为何一直在被使用?
  • JAVA经典单例模式
  • 纯CSS轮播
  • 动手学深度学习13.9. 语义分割和数据集 -笔记练习(PyTorch)
  • 文件摆渡系统:如何攻克跨网文件交换难点,实现安全合规传输?
  • ISO-IEC-IEEE 42010架构规范
  • 用Finalshell连接服务器后出现文件目录不显示,且刷新报错空指针问题记录
  • 【WRFDA实操第一期】服务器中安装 WRFPLUS 和 WRFDA
  • 探索文本切分的多种方法与应用场景
  • 学习 Flutter (三):玩安卓项目实战 - 上