HDR图像合成硬件架构与RTL开发实战 - 第2节
多曝光图像序列:HDR的原材料
做HDR合成,第一步就是拿到多曝光图像序列。说白了,就是对着同一个场景,用不同的曝光时间拍好几张照片。你想想看,一张照片的动态范围有限,亮的地方过曝,暗的地方欠曝。但如果我们拍一组——一张欠曝、一张正常、一张过曝——就能把场景里从最亮到最暗的信息都抓全了。
我在项目中遇到过一个问题:图像序列的对齐精度。手持拍摄时,哪怕手抖一点点,像素就错位了。合成出来的HDR图像边缘会有鬼影,特别难看。所以硬件里一定要做运动补偿或者图像配准,这个后面章节会细讲。
| 曝光级别 | 曝光时间 | 保留信息 | 典型场景 |
|---|---|---|---|
| 欠曝 | 短 | 高亮区域细节 | 天空、灯光、反光面 |
| 正常 | 中 | 中间调细节 | 人物、建筑主体 |
| 过曝 | 长 | 暗部区域细节 | 阴影、背光面 |
嗯,这里要注意:多曝光序列的张数不是越多越好。3到5张是主流,再多的话,硬件处理带宽和存储开销会翻倍,收益却不大。
权重映射函数:给每个像素打分
拿到多张图像后,怎么决定每张图里哪些像素值得信任?这就是权重映射函数干的事。它的核心思想很简单:像素值太暗或太亮,噪声都大,不可靠;中间范围的像素最靠谱。
常见的权重函数有几种:
- 三角权重:线性上升再下降,实现简单,但过渡不够平滑
- 高斯权重:用高斯曲线,中间平坦,两边平滑下降,效果好
- 平台权重:中间一段给满权重,两端快速衰减,硬件实现友好
我个人习惯用平台权重。为什么?因为硬件里做查表或者分段线性,比算高斯快得多。我在一个4K@60fps的项目里,就是用平台权重,流水线延迟只多了2个时钟周期。
权重函数的数学形式大概是这样:
// 伪代码:平台权重映射
function weight(pixel_value, threshold_low, threshold_high):
if pixel_value < threshold_low:
return pixel_value / threshold_low
else if pixel_value > threshold_high:
return (255 - pixel_value) / (255 - threshold_high)
else:
return 1.0
我曾经踩过一个坑:权重函数没做归一化。合成出来的图像整体偏暗,查了半天才发现是权重和不为1。后来我在RTL里加了一个归一化除法器,问题就解决了。
合成公式:把多张图揉成一张
有了权重,合成公式就顺理成章了。每个像素位置的最终值,是所有曝光图像在该位置的加权平均。
公式长这样:
HDR(x,y) = Σ( W_i(x,y) * I_i(x,y) ) / Σ( W_i(x,y) )
其中:
I_i(x,y)是第i张曝光图像在(x,y)处的像素值W_i(x,y)是对应的权重- 分母是所有权重的和,保证归一化
你可能会问:为什么不用简单的最大值或者平均值?我试过,效果很差。最大值合成会丢失暗部细节,平均值合成会让亮部发灰。加权平均才是正道。
硬件实现小技巧:权重和分母可以用查找表预计算,避免实时除法。我在FPGA上就是这么干的,资源占用少了30%。
色调映射简介:把HDR塞进显示器
合成出来的HDR图像,像素值范围很大,可能是0到10000甚至更高。但普通显示器只能显示0到255。怎么办?这就需要色调映射。
色调映射的本质,就是把高动态范围压缩到低动态范围,同时尽量保留视觉细节。它不是简单的线性缩放——那样暗部会全黑,亮部会全白。
常见的色调映射算法分两类:
- 全局映射:整张图用同一个映射曲线。实现简单,但局部对比度会丢失
- 局部映射:根据像素周围区域调整映射参数。效果好,但硬件复杂度高
我记得在做一个监控摄像头项目时,用了全局映射。结果画面里同时有强光和阴影,细节全没了。后来换成局部映射,虽然逻辑多了不少,但效果立竿见影。
注意:色调映射不是HDR合成的必要步骤。如果你要输出真正的HDR格式(比如OpenEXR),就不需要映射。但绝大多数消费电子设备,最终都要映射到8bit或10bit输出。
本章知识体系
下面这张图,把HDR合成算法的核心流程串起来了:
从图上你能看到,整个流程是串行的:多曝光图像进来,先对齐,再算权重,然后加权合成,最后根据需求决定要不要做色调映射。每个环节都有硬件实现的考量和优化空间。
嗯,这一章的内容就到这里。核心概念就三个:多曝光序列、权重映射、合成公式。色调映射先有个印象,后面会有专门章节深入讲它的硬件实现。