顶层模块划分:五块核心骨架
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。色调映射就是把高动态范围压缩到低动态范围,同时保留细节。
常用的映射算法:
- 全局映射:简单,但容易丢失局部细节
- 局部映射:效果好,但硬件开销大
- 自适应映射:根据图像统计信息动态调整
我建议初学者先从全局映射入手。它只需要一个查找表(LUT)就能实现。等理解了基本原理,再上局部映射。
个人经验:色调映射模块最容易出现的问题是banding(色带)。因为8bit精度不够,平滑渐变区域会出现条纹。我常用的解决办法是在输出前加一个2D抖动(dithering)模块,虽然只加了1bit的随机噪声,但视觉上改善非常明显。
5. 输出模块
输出模块负责把处理好的数据送到下一级。可能是显示接口、编码器、或者存储。
输出模块要考虑的事情:
- 接口协议:MIPI、LVDS、HDMI?不同协议时序不同
- 数据格式:RGB、YUV、RAW?需要做格式转换吗
- 帧率控制:输出帧率是否和输入一致?需要做帧率转换吗
嗯,这里要注意:输出模块的时钟域通常和前面不一样。我习惯在输出模块入口处做一个异步FIFO,做跨时钟域处理。这个FIFO的深度至少能存一帧数据,防止背压导致丢帧。
整体架构图
下面这张图展示了五个模块的流水线关系:
模块间接口定义
模块划好了,接口定义同样重要。我习惯用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实现时,先搭一个最小系统:输入→合成→输出,跳过权重和色调映射,用固定权重和线性映射。等这个通路跑通了,再逐步加入权重计算和色调映射。这样调试起来思路清晰,问题定位也快。