前言
本章主要学习图像直方图的相关知识与实操应用,涵盖直方图基础概念、图像直方图绘制、掩码局部灰度统计以及直方图均衡化图像增强技术,结合代码实战完成图像灰度分析与图像增强任务。
一、核心 API 介绍
1.1 图像直方图基础概念
结合示意图可直观理解:图像直方图是针对图像灰度信息的二维分布统计图,专门用于量化图像明暗结构,完全对应图片对应关系:
横轴(X轴):灰度级别,取值固定为 0~255。其中 0 代表纯黑色、255 代表纯白色,中间数值对应不同亮度的灰色,完整覆盖图像所有明暗等级。
纵轴(Y轴):像素数量,代表当前横坐标对应灰度级别的像素点总个数,用于体现该亮度在整张图像中的占比多少。
从示意图可以明显看出:直方图不记录图像空间信息,不关注物体位置、轮廓、纹理、形状,只统计「不同亮度像素有多少个」的全局数值分布。无论图像中物体如何平移、变换位置,只要灰度像素数量比例不变,直方图曲线就不会改变。


1.2 使用直方图的意义与作用
人眼观察图像只能获得主观视觉感受,无法精准判断图像的明暗分布、对比度强弱,而直方图可以将图像视觉特征数据化、量化,为图像处理提供客观依据。主要作用如下:
-
辅助图像分析:通过直方图分布形态,可快速判断图像偏暗、偏亮、对比度过高或过低等问题;
-
实现图像增强:基于直方图均衡化算法,重新分布灰度像素,优化图像对比度;
-
支持局部统计:结合掩码 Mask,可单独统计图像感兴趣区域(ROI)的灰度分布,实现局部图像分析。
1.3 直方图核心特点
直方图具备位置无关性,只要两张图像的灰度像素数量、分布比例一致,无论图像内容、物体位置如何变化,最终生成的直方图完全一致。
1. cv2.calcHist () 计算图像直方图
|--------------------------------------------|
| 作用:统计图像像素灰度级分布,得到直方图数据,可使用 matplotlib 绘制曲线 |
python
cv2.calcHist(images, channels, mask, histSize, ranges)
参数说明:
- images:原图像,格式为 uint8,传入需要用\[\]包裹,例如img
- channels:要统计的通道索引,灰度图填0;彩色图 BGR 分别对应0、1、2
- mask:掩码图像。统计整张图像直方图填None;如果只想统计图像部分区域,传入 mask 掩码。mask 等于 0 的区域不参与统计,非 0 区域参与统计。
- histSize:BIN 的数量,也就是灰度分组数目,需要\[\]包裹;统计 0‑255 全部灰度,填256。
- ranges:像素取值范围,灰度图像固定0,256。
2. np.ravel()
|----------------------------------------------|
| numpy 函数,把多维的图像数组拉伸为一维数组,配合plt.hist()直接画直方图。 |
3. cv2.bitwise_and () 按位与运算
python
cv2.bitwise_and(src1, src2, dst=None, mask=None)
- src1、src2:参与运算输入图像
- mask:掩码,掩码为 0 的位置输出全部置 0;非 0 位置正常输出运算结果。
4. cv2.equalizeHist () 直方图均衡化
|----------------------------------------------------|
| 图像增强技术,重新分布图像灰度像素,提升图像对比度、亮度,改善图像视觉效果。 只接收灰度图作为输入。 |
二、绘制灰度图直方图
为直观掌握图像直方图的绘制方法,本节以手机灰度图像为测试样本,分别通过两种方式绘制图像直方图,实现图像灰度分布的可视化统计。

2.1 方式 1:plt.hist + ravel ()
python
import cv2
import matplotlib.pyplot as plt
#读取灰度图片
phone = cv2.imread('phone.png',cv2.IMREAD_GRAYSCALE)
#ravel:多维数组转为一维
a = phone.ravel()
#绘制直方图
plt.hist(a,bins=256)
plt.show()
2.2 方式 2:cv2.calcHist 获取直方图数据再绘图
python
import cv2
import matplotlib.pyplot as plt
phone = cv2.imread('phone.png',cv2.IMREAD_GRAYSCALE)
#计算直方图数据
phone_hist = cv2.calcHist(images=[phone],channels=[0],mask=None,histSize=[256],ranges=[0,256])
plt.plot(phone_hist)
plt.show()
2.3 彩色图像多通道直方图绘制
分别统计 B、G、R 三个通道的直方图并绘制曲线
python
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('phone.png')
color = ('b','g','r')
for i,col in enumerate(color):
histr = cv2.calcHist(images=[img],channels=[i],mask=None,histSize=[256],ranges=[0,256])
plt.plot(histr,color=col)
plt.show()



三、mask 掩码,局部图像直方图统计
python
import cv2
import matplotlib.pyplot as plt
import numpy as np
phone = cv2.imread('phone.png',cv2.IMREAD_GRAYSCALE)
cv2.imshow('phone',phone)
cv2.waitKey(0)
#创建掩码:全黑图像,指定矩形区域置为白色255
mask = np.zeros(phone.shape[:2],np.uint8)
mask[50:350,100:470] = 255
cv2.imshow('mask',mask)
cv2.waitKey(0)
#bitwise_and 掩码提取ROI区域
phone_mask = cv2.bitwise_and(phone,phone,mask=mask)
cv2.imshow('phone_mask',phone_mask)
cv2.waitKey(0)
#只统计mask白色区域的直方图
phone_hist_mask = cv2.calcHist(images=[phone],channels=[0],mask=mask,histSize=[256],ranges=[0,256])
plt.plot(phone_hist_mask)
plt.show()
mask 掩码:只对图像指定区域做计算,掩码黑色 (0) 区域忽略,白色 (255) 区域参与运算。
掩码:
通过在全黑背景图像中手动将指定矩形区域设置为白色,可以创建一个简易的掩码。此外,也可以基于我们想要分析的目标物体的外接矩形来创建掩码。

得到掩码之后,我们通过 bitwise_and() 对灰度图与掩码图进行位与运算,当两个图像对应位置像素值均为真(非零)时,结果才为真。
效果图:

四、直方图均衡化 cv2.equalizeHist


观察这张女孩图像的直方图可以看出,像素分布并不均衡,灰度值在50之后几乎没有像素分布。现在我们对图像进行直方图均衡化操作,使像素分布变得更加均衡。
python
import cv2
import matplotlib.pyplot as plt
import numpy as np
#读取灰度图
black = cv2.imread('black.jpg',cv2.IMREAD_GRAYSCALE)
#均衡化处理
black_equalize = cv2.equalizeHist(black)
#绘制均衡化前直方图
plt.hist(black.ravel(),bins=256)
plt.show()
#绘制均衡化后直方图
plt.hist(black_equalize.ravel(),bins=256)
plt.show()
#横向拼接原图与均衡化结果,对比效果
res = np.hstack((black,black_equalize))
cv2.imshow('black_equalize',res)
cv2.waitKey(0)
经过 cv2.equalizeHist 对像素进行重新分布后,观察直方图可以发现像素分布变得更加均衡。通过对比均衡化前后的女孩图像,可以看出均衡化后的图像特征更加鲜明清晰,对比度显著提高。


五、本章小结
- cv2.calcHist()用于统计图像灰度分布;mask掩码可以限定只统计图像局部区域。
- np.ravel()将多维图像数组拉伸一维,直接给plt.hist绘图使用。
- 掩码配合cv2.bitwise_and()可以提取图像的感兴趣 ROI 区域。
- 直方图均衡化 cv2.equalizeHist():输入必须是灰度图,重新分配灰度分布,提升图像对比度,完成图像增强。
- 适用场景:图像整体偏暗、偏亮,使用均衡化改善图像显示效果。