4. 直方图均衡化原理

直方图均衡化,说白了就是让一张图的灰度分布从「扎堆」变成「铺开」。我刚开始接触图像增强时,总觉得调亮度对比度就够了,直到有一次处理一张雾天拍的监控画面——整张图灰蒙蒙的,直方图全挤在中间一段。试了各种线性拉伸都不理想,最后用均衡化,效果立竿见影。嗯,从那以后我就把这招当成预处理的标准动作了。

4.1 为什么需要均衡化?

先看一个直观问题。一张曝光不足或过度的图像,它的直方图往往集中在某个狭窄区间。比如暗图,像素大多集中在低灰度区;亮图则集中在高灰度区。这种「集中分布」导致图像对比度低,细节看不清。

均衡化的目标很明确:把原始直方图映射成近似均匀分布。让每个灰度级上的像素数量大致相等,这样图像的动态范围就被充分利用了。

核心思想: 用累积分布函数(CDF)作为映射函数,将原始灰度值重新分配,使输出图像的直方图尽可能平坦。

4.2 累积分布函数(CDF)

要理解均衡化,必须先搞懂CDF。直方图是概率密度函数(PDF)的离散近似,而CDF就是PDF的积分。

对于灰度级 rk,其概率密度为:

p(r_k) = n_k / N

其中 nk 是灰度级 rk 的像素数,N 是总像素数。

CDF 定义为:

CDF(r_k) = Σ p(r_i)   (i = 0 到 k)

说白了,CDF 就是「小于等于某个灰度值的像素占比」。它的值从 0 单调递增到 1。

我个人习惯: 在写代码前,先手动算一遍小图像的CDF。比如一张 4×4 的图,灰度范围 0-3,算一遍你就彻底理解映射关系了。纸上得来终觉浅嘛。

4.3 均衡化的数学推导

假设原始灰度 r 在 [0, 1] 区间,其PDF为 p(r)。我们希望找到一个变换 s = T(r),使得输出灰度 s 的PDF是均匀的。

关键定理来了:变换函数 T(r) 取原始图像的CDF,就能实现均衡化。

推导过程很简单:

s = T(r) = ∫ p(w) dw   (从 0 到 r)

这个变换的导数 dT/dr = p(r)。根据概率论中变换后的PDF公式:

p_s(s) = p_r(r) · |dr/ds| = p_r(r) · 1/p_r(r) = 1

看,输出PDF恒等于1,完美均匀分布。数学上就是这么漂亮。

我曾经踩过的坑: 离散情况下,CDF是阶梯函数,映射后直方图不会完全平坦,只会「近似均匀」。别指望均衡化后直方图变成一条直线,那是不可能的。我刚开始做时总纠结这个,后来才明白——离散化带来的量化误差是固有的。

4.4 全局均衡化算法

实际工程中,我们处理的是离散灰度级(比如0-255)。算法步骤如下:

  1. 统计直方图: 计算每个灰度级 rk 的像素数 nk。
  2. 计算PDF: p(rk) = nk / N。
  3. 计算CDF: cdf(rk) = Σ p(ri),i=0..k。
  4. 映射到输出灰度: sk = round( cdf(rk) × (L-1) ),其中 L 是灰度级数(通常256)。
  5. 替换像素值: 将原图中灰度 rk 的像素替换为 sk。

代码实现非常直接:

def histogram_equalization(img):
    # img: 灰度图, 0-255
    hist = np.zeros(256, dtype=np.float32)
    h, w = img.shape
    N = h * w
    
    # 1. 统计直方图
    for i in range(h):
        for j in range(w):
            hist[img[i,j]] += 1
    
    # 2. 计算PDF
    pdf = hist / N
    
    # 3. 计算CDF
    cdf = np.zeros(256)
    cdf[0] = pdf[0]
    for k in range(1, 256):
        cdf[k] = cdf[k-1] + pdf[k]
    
    # 4. 映射
    lut = np.round(cdf * 255).astype(np.uint8)
    
    # 5. 替换
    out = lut[img]
    return out

工程优化: 实际项目中我会用 np.cumsum 一步算CDF,再用 np.interp 做映射,比手写循环快一个数量级。你想想看,处理一张4K图像,循环256次和循环几百万次,差别太大了。

4.5 算法效果与局限

特性 说明
对比度增强 显著拉伸图像动态范围,细节更清晰
自动化 无需人工参数,完全由数据驱动
可逆性 映射是单调的,理论上可逆(但量化会损失信息)
噪声放大 均匀区域中的噪声会被放大,出现「颗粒感」
过度增强 某些图像会出现不自然的「块状」或「伪影」

避坑指南: 我曾经在医学X光片上用全局均衡化,结果骨骼边缘出现了明显的伪影。后来才意识到——医学图像往往有很长的平坦背景区域,均衡化会把背景噪声放大到肉眼可见。这种情况下,自适应均衡化(AHE)或限制对比度自适应直方图均衡化(CLAHE)才是正解。后面章节会详细讲。

4.6 知识结构图

下面这张图梳理了本章的核心逻辑链:

直方图均衡化知识结构 直方图均衡化核心逻辑 图像对比度不足 核心原理:CDF作为映射函数 数学推导:s = T(r) = ∫p(w)dw → p_s(s) = 1 算法步骤 统计直方图 → 计算PDF → 计算CDF → 映射到输出灰度 → 替换像素 效果:对比度增强 | 局限:噪声放大、过度增强 注意 后续改进

4.7 小结

直方图均衡化是图像增强的基石。它的数学基础是CDF变换,算法简单高效,效果立竿见影。但记住——它不是万能的。遇到噪声多、背景平坦的图像时,要谨慎使用。