4、直方图均衡化算法流程:输入图像、计算直方图、计算累积分布、生成映射表、输出图像
好,咱们今天来聊聊直方图均衡化的具体流程。说实话,这个算法在嵌入式视觉里太常用了。我最早在FPGA上实现它的时候,踩了不少坑,后来才慢慢摸清楚每个步骤的细节。
直方图均衡化,说白了就是让图像的灰度分布更均匀。你想想看,一张图如果整体偏暗或者偏亮,细节就看不清楚。均衡化就是要把这些像素重新分配一下,让亮部和暗部都有足够的细节。
整个流程分五步走:输入图像 → 计算直方图 → 计算累积分布 → 生成映射表 → 输出图像。每一步都有讲究,咱们一个一个说。
4.1 输入图像
这一步看起来简单,其实有门道。我习惯先把图像转成灰度图,因为直方图均衡化本质上是针对单通道的操作。如果是彩色图,你可以对亮度通道单独做,或者对三个通道分别做——但后者容易产生色偏,我个人不太推荐。
输入图像的格式也很重要。8位灰度图,像素值范围0~255,这是最常见的。如果是12位或16位的RAW图,处理逻辑一样,但映射表的大小要相应调整。
4.2 计算直方图
直方图就是统计每个灰度级有多少个像素。比如灰度值0的有100个像素,灰度值1的有50个像素……以此类推。
在嵌入式系统里,这一步通常用硬件加速。我记得在某个项目中,用C语言写了个循环去统计,结果发现CPU占用率飙到80%以上。后来改成用DMA+双缓冲的方式,效率一下就上来了。
// 计算直方图的典型代码(C语言风格)
uint32_t hist[256] = {0};
for (int i = 0; i < width * height; i++) {
hist[image[i]]++;
}
嗯,这里要注意:直方图数组的大小取决于图像的位深。8位图就是256个bin,10位图就是1024个bin。别搞错了,否则后面计算累积分布时会出问题。
4.3 计算累积分布
累积分布函数(CDF)是直方图均衡化的核心。它表示每个灰度级及之前所有灰度级的像素总数。
公式很简单:CDF(k) = sum(hist[0] + hist[1] + ... + hist[k])
我刚开始做的时候,直接拿浮点数去算,结果在定点DSP上跑得特别慢。后来改成用整数运算,把归一化放到最后一步,速度提升了将近3倍。
// 计算累积分布(整数版本)
uint32_t cdf[256] = {0};
uint32_t sum = 0;
for (int i = 0; i < 256; i++) {
sum += hist[i];
cdf[i] = sum;
}
4.4 生成映射表
有了累积分布,接下来就是生成映射表。映射表的作用是把原始灰度值映射到新的灰度值。
标准公式是:new_value = (CDF(old_value) - CDF_min) / (total_pixels - CDF_min) * 255
但在嵌入式平台上,我通常用查表法。提前算好一个256字节的查找表,运行时直接查表,比实时计算快得多。
// 生成映射表
uint8_t lut[256];
uint32_t total = width * height;
uint32_t cdf_min = 0;
// 找到第一个非零的CDF值
for (int i = 0; i < 256; i++) {
if (cdf[i] != 0) {
cdf_min = cdf[i];
break;
}
}
// 生成LUT
for (int i = 0; i < 256; i++) {
lut[i] = (uint8_t)((cdf[i] - cdf_min) * 255 / (total - cdf_min));
}
你想想看,这个LUT一旦生成,后面处理每一帧图像就只是查表操作,计算量几乎可以忽略不计。对于实时视频流来说,这个优化非常关键。
4.5 输出图像
最后一步,就是把原始图像的每个像素,通过映射表转换成新的像素值。
// 输出均衡化后的图像
for (int i = 0; i < width * height; i++) {
output[i] = lut[image[i]];
}
到这里,一张经过直方图均衡化的图像就出来了。你会发现原本灰蒙蒙的图像,现在对比度明显提升,细节也更清晰了。
核心要点总结:
- 直方图均衡化本质是非线性映射,不是简单的线性拉伸
- 嵌入式实现时,查表法是最高效的方式
- 注意处理直方图峰值,避免映射后出现伪影
- 彩色图像建议只对亮度通道做均衡化
我个人觉得,直方图均衡化是嵌入式视觉里性价比最高的算法之一。实现简单,效果明显,而且对硬件资源要求不高。你在做图像预处理的时候,不妨先试试它,往往能省掉后面很多复杂的处理步骤。
嗯,流程就这些。下一章咱们聊聊直方图均衡化的变种——自适应直方图均衡化(AHE)和限制对比度自适应直方图均衡化(CLAHE)。这两个在实际项目中更常用,尤其是处理光照不均匀的图像时。