2. 直方图均衡化原理:图像直方图、累积分布函数、映射函数推导
好,咱们正式开始啃 CLAHE 之前,得先把它的老祖宗——直方图均衡化(HE)给彻底搞明白。说白了,HE 就是 CLAHE 的基石。你如果连 HE 的映射函数怎么来的都说不清,那 CLAHE 的“自适应”和“对比度限制”就更是空中楼阁了。
我个人习惯,讲算法一定要先看它要解决什么问题。一张图像,如果曝光不足或者过曝,像素灰度值就会挤在某个小范围内。比如一张夜景照片,大部分像素都集中在暗区。这时候图像的细节就“糊”在一起了,对比度极差。
直方图均衡化想干嘛?它想把挤在一起的像素分布,拉伸成在整个灰度范围内均匀分布。就像把一堆挤在角落的人,均匀地铺满整个房间。这样一来,暗部的细节就亮起来了,亮部的细节也不会过曝。
2.1 图像直方图:统计的起点
先说说图像直方图。这东西不复杂,就是一个统计图。
- 横轴:灰度级。对于 8 位图,就是 0 到 255。
- 纵轴:每个灰度级出现的像素个数。
用数学表达就是:
h(r_k) = n_k
其中 r_k 是第 k 个灰度级,n_k 是该灰度级的像素总数。
嗯,这里要注意。我们通常还会用归一化的直方图,也就是概率密度函数(PDF):
p(r_k) = n_k / N
N 是图像总像素数。这样纵轴就变成了概率,范围在 0 到 1 之间。
2.2 累积分布函数:映射的桥梁
有了概率密度函数,我们怎么把像素值从暗区映射到亮区呢?
答案就是累积分布函数(CDF)。CDF 就是 PDF 的累加和。它表示小于等于某个灰度级的像素占总像素的比例。
CDF(r_k) = Σ_{j=0}^{k} p(r_j)
你想想看,CDF 的值域天然就在 [0, 1] 之间。这正好对应了我们想要的输出灰度范围(归一化后)。
为什么 CDF 能用来做映射?因为 CDF 是一个单调递增函数。它保证了映射后的灰度顺序不变——原来暗的像素,映射后还是暗的;原来亮的,映射后还是亮的。不会出现灰度反转这种离谱的事。
2.3 映射函数推导:从理论到公式
好,现在我们来推导那个最终的映射公式。别怕,其实就是几步简单的数学。
假设我们有一张连续灰度图像,灰度值 r 在 [0, L-1] 范围内。它的概率密度函数是 p(r)。
我们想要找到一个变换函数 s = T(r),使得输出图像 s 的灰度分布是均匀的。
根据概率论,如果 T(r) 是单调递增的,那么输出 s 的概率密度函数 p_s(s) 和输入 p_r(r) 的关系是:
p_s(s) = p_r(r) * |dr/ds|
我们希望 p_s(s) 是均匀的,即 p_s(s) = 1/(L-1)。
那么,变换函数 T(r) 应该是什么?
答案就是输入图像的累积分布函数乘以 (L-1):
s = T(r) = (L-1) * ∫_{0}^{r} p_r(w) dw
对于离散图像,积分变成求和,公式就是:
s_k = T(r_k) = (L-1) * Σ_{j=0}^{k} p(r_j) = (L-1) * CDF(r_k)
这就是我们最终要用的映射函数。
2.4 效果与局限:为什么还需要 CLAHE?
直方图均衡化效果很直观。对比度提升了,细节出来了。但它有两个硬伤:
| 问题 | 表现 | 原因 |
|---|---|---|
| 过度增强 | 图像出现不自然的“块状感”,噪声被放大 | 全局映射,把原本集中的灰度级强行拉开,导致某些区域对比度过高 |
| 细节丢失 | 图像某些区域变得过亮或过暗 | 全局直方图统计无法照顾局部特征,背景和目标的灰度被“平均”处理 |
说白了,全局 HE 是“一刀切”。它不管图像里不同区域的亮度差异有多大,都用同一个映射函数。这就像给全班同学穿同一码的鞋——肯定有人舒服,有人挤脚。
CLAHE 就是来解决这个问题的。它把图像分成小块,每块独立做 HE,再通过插值消除块效应。同时,它还加了一个“对比度限制”,防止噪声被过度放大。
下面这张图,帮你把整个 HE 的流程和局限串起来:
嗯,看到这里,你应该明白了。HE 是一个优雅的数学工具,但它太“耿直”了。它假设整张图像的亮度分布是均匀的,这显然不符合现实。