直方图均衡化(Histogram Equalization)是一种通过调整图像灰度分布来增强图像对比度的经典方法,尤其在处理低对比度或光照不均匀的图像时效果显著。本文深入解析其数学原理,并提供手动实现 与OpenCV优化方案的完整代码,结合实际应用场景展示其核心价值。
1. 直方图均衡化原理
(1) 核心目标
- 问题:图像灰度集中在狭窄范围 → 细节模糊。
- 解决方案 :将原始直方图变换为均匀分布,扩展动态范围。
(2) 数学推导
- 概率密度函数(PDF) :
统计各灰度级频数:


- 累积分布函数(CDF):

将映射到新的灰度级
,使新直方图接近均匀分布。
2. 手动实现直方图均衡化
(2.1) 灰度图像处理
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 解决中文显示问题
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
def manual_hist_equalize(image):
if len(image.shape) == 3:
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
hist = cv2.calcHist([image], [0], None, [256], [0, 256])
hist_norm = hist.ravel() / hist.sum() # 归一化得到PDF
cdf = hist_norm.cumsum() # 计算CDF
cdf_normalized = (cdf * 255).astype(np.uint8) # 线性映射到0-255
return cdf_normalized[image] # 应用映射
# 使用示例
img = cv2.imread('5.bmp', cv2.IMREAD_GRAYSCALE)
if img is None:
print("错误:无法加载图像,请检查文件路径。")
else:
equalized_manual = manual_hist_equalize(img)
# 显示原始图像和直方图均衡化后的图像
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.title('原始图像') # 中文标题
plt.imshow(img, cmap='gray')
plt.subplot(1, 2, 2)
plt.title('手动直方图均衡化图像') # 中文标题
plt.imshow(equalized_manual, cmap='gray')
plt.show()

(2.2) 关键步骤解析
步骤 | 功能 | 代码实现 |
---|---|---|
统计直方图 | 计算各灰度级像素数量 | cv2.calcHist |
归一化PDF | 转换为概率分布 | hist_norm = hist / total |
计算CDF | 累加概率密度,生成映射函数 | cdf = np.cumsum(hist_norm) |
应用映射 | 将原图灰度替换为CDF对应值 | equalized = cdf[original] |
3. OpenCV高效实现
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 解决中文显示问题
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置字体为黑体
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 灰度图直方图均衡化
def gray_hist_equalize(image):
if len(image.shape) == 3:
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
equalized = cv2.equalizeHist(image)
return equalized
# 彩色图直方图均衡化
def color_hist_equalize(image):
# 将图像转换为 YCrCb 色彩空间
ycrcb = cv2.cvtColor(image, cv2.COLOR_BGR2YCrCb)
# 对 Y 通道进行直方图均衡化
ycrcb[:, :, 0] = cv2.equalizeHist(ycrcb[:, :, 0])
# 转换回 BGR 色彩空间
equalized = cv2.cvtColor(ycrcb, cv2.COLOR_YCrCb2BGR)
return equalized
# 加载图像
img = cv2.imread('5.bmp')
if img is None:
print("错误:无法加载图像,请检查文件路径。")
else:
# 灰度图处理
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray_equalized = gray_hist_equalize(img)
# 彩色图处理
color_equalized = color_hist_equalize(img)
# 将 BGR 图像转换为 RGB 图像(matplotlib 使用 RGB 格式)
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
color_equalized_rgb = cv2.cvtColor(color_equalized, cv2.COLOR_BGR2RGB)
# 使用 matplotlib 显示图像
plt.figure(figsize=(15, 10))
# 显示原始图像
plt.subplot(2, 2, 1)
plt.imshow(img_rgb)
plt.title('原始彩色图像')
plt.axis('off')
# 显示原始灰度图像
plt.subplot(2, 2, 2)
plt.imshow(gray_img, cmap='gray')
plt.title('原始灰度图像')
plt.axis('off')
# 显示灰度直方图均衡化图像
plt.subplot(2, 2, 4)
plt.imshow(gray_equalized, cmap='gray')
plt.title('灰度直方图均衡化图像')
plt.axis('off')
# 显示彩色直方图均衡化图像
plt.subplot(2, 2, 3)
plt.imshow(color_equalized_rgb)
plt.title('彩色直方图均衡化图像')
plt.axis('off')
# 显示图像
plt.tight_layout()
plt.show()