顶层模块划分:五块核心骨架

HDR合成硬件架构,说白了就是把算法拆成五个能独立干活儿的模块。我做了这么多年RTL设计,最大的体会就是:模块划得好,后面联调少烦恼。今天咱们就聊聊这五个模块——图像输入、权重计算、合成核心、色调映射、输出模块。

你想想看,一个HDR合成流水线,从多帧图像进来,到最终显示出去,中间要经过多少道工序?如果全揉在一个模块里,那调试起来简直是噩梦。我早期一个项目就吃过这个亏,后来老老实实按功能切分,效率反而上去了。

1. 图像输入模块

这个模块负责接收多帧不同曝光的图像数据。通常来说,输入的是3帧:欠曝、正常、过曝。但实际项目中,我见过用2帧的,也见过用5帧的。

核心功能:

  • 帧同步:确保三帧数据对齐到达
  • 数据缓冲:用FIFO或双口RAM暂存
  • 预处理:去噪、对齐(可选)

我记得有一次做手机ISP芯片,输入模块的带宽成了瓶颈。三帧1080p@60fps的数据,RAW格式12bit,算下来带宽需求接近3GB/s。后来我们用了ping-pong buffer结构才搞定。

个人经验:输入模块的FIFO深度一定要留余量。我曾经因为FIFO深度只算了理论值,结果遇到帧率抖动直接溢出,画面出现撕裂。后来我习惯多留20%的深度。

2. 权重计算模块

权重计算,说白了就是判断每个像素该信哪一帧。过曝区域信欠曝帧,欠曝区域信过曝帧,中间区域做融合。

常见的权重函数有几种:

权重类型 特点 硬件开销
三角权重 简单,线性过渡 低
高斯权重 平滑,效果好 中
S曲线权重 对比度强,边缘锐利 高

我个人习惯用三角权重做基础版本,因为它的硬件实现只需要一个减法器和比较器,面积小。等性能调优阶段再换成更复杂的曲线。

避坑指南:权重计算模块的输出一定要做归一化。我曾经遇到过权重和不为1的情况,导致合成后画面亮度跳变。后来我在模块内部加了一个归一化除法器,虽然多花了几个周期,但稳定性好多了。

3. 合成核心模块

这是整个HDR流水线的算力中心。公式很简单:

// 伪代码示例
for each pixel (x, y):
    out_pixel = w1 * img1 + w2 * img2 + w3 * img3
    // 其中 w1 + w2 + w3 = 1

但硬件实现就没这么简单了。你需要考虑:

  • 乘法器资源:每个像素需要3个乘法器,如果做并行处理,资源消耗很大
  • 流水线深度:乘法+加法至少需要3-4级流水
  • 位宽控制:中间结果位宽要留够,防止溢出

我记得有个项目,合成核心模块的乘法器用了DSP48E2,一个时钟周期处理4个像素,吞吐量做到了4像素/周期。但代价是控制逻辑变得复杂,光状态机就写了200多行。

关键指标:

  • 吞吐率:至少1像素/周期(1080p@60fps需要约124M像素/秒)
  • 延迟:控制在10个时钟周期以内
  • 精度:中间结果保留2-4bit余量

4. 色调映射模块

合成后的图像是HDR数据,位宽通常12-16bit。但显示设备只能显示8bit。色调映射就是把高动态范围压缩到低动态范围,同时保留细节。

常用的映射算法:

  1. 全局映射:简单,但容易丢失局部细节
  2. 局部映射:效果好,但硬件开销大
  3. 自适应映射:根据图像统计信息动态调整

我建议初学者先从全局映射入手。它只需要一个查找表(LUT)就能实现。等理解了基本原理,再上局部映射。

个人经验:色调映射模块最容易出现的问题是banding(色带)。因为8bit精度不够,平滑渐变区域会出现条纹。我常用的解决办法是在输出前加一个2D抖动(dithering)模块,虽然只加了1bit的随机噪声,但视觉上改善非常明显。

5. 输出模块

输出模块负责把处理好的数据送到下一级。可能是显示接口、编码器、或者存储。

输出模块要考虑的事情:

  • 接口协议:MIPI、LVDS、HDMI?不同协议时序不同
  • 数据格式:RGB、YUV、RAW?需要做格式转换吗
  • 帧率控制:输出帧率是否和输入一致?需要做帧率转换吗

嗯,这里要注意:输出模块的时钟域通常和前面不一样。我习惯在输出模块入口处做一个异步FIFO,做跨时钟域处理。这个FIFO的深度至少能存一帧数据,防止背压导致丢帧。

整体架构图

下面这张图展示了五个模块的流水线关系:

HDR合成硬件架构 - 顶层模块划分 HDR合成硬件架构 - 顶层模块划分 图像输入模块 权重计算模块 合成核心模块 色调映射模块 输出模块 说明: 数据流方向:输入 → 权重计算 → 合成核心 → 色调映射 → 输出 权重计算模块与合成核心模块之间有紧密的数据耦合 像素数据 权重+像素 HDR数据 SDR数据

模块间接口定义

模块划好了,接口定义同样重要。我习惯用valid-ready握手协议做模块间通信。每个模块的接口包含:

信号名 方向 位宽 说明
data_in 输入 12-16bit 像素数据
valid_in 输入 1bit 数据有效标志
ready_out 输出 1bit 模块可接收数据
data_out 输出 12-16bit 处理后的像素数据
valid_out 输出 1bit 输出数据有效
ready_in 输入 1bit 下游模块可接收

重要提醒:模块间的握手信号一定要做时序收敛。我曾经在一个项目中,因为valid信号路径太长,导致setup time违例。后来我在每个模块入口加了一级寄存器打拍,虽然多了一个时钟周期的延迟,但时序问题解决了。

总结一下

五个模块,各司其职。输入模块管数据进门,权重模块算信任度,合成核心做融合,色调映射做压缩,输出模块送出门。每个模块都不复杂,但组合起来就能实现完整的HDR合成流水线。

我个人建议,刚开始做RTL实现时,先搭一个最小系统:输入→合成→输出,跳过权重和色调映射,用固定权重和线性映射。等这个通路跑通了,再逐步加入权重计算和色调映射。这样调试起来思路清晰,问题定位也快。