4、LSC硬件实现:网格增益表(Gain Grid)与插值算法(双线性、双三次)
上一章我们聊了怎么算增益曲面,那是理论。到了硬件实现这一步,事情就变得很具体了。说白了,你不可能在芯片里存一个完整的连续曲面,那太费存储了。实际做法是——存一张稀疏的网格表,然后用插值把缺失的点算出来。
我刚开始接触ISP硬件时,总觉得插值嘛,不就是算个加权平均?后来被时序和面积逼得改了好几版设计,才明白这里面门道不少。今天咱们就把网格增益表和两种主流插值算法掰开揉碎了讲清楚。
4.1 网格增益表(Gain Grid)
增益表,本质上是一个二维数组。数组里的每个元素代表图像上某个网格点的增益值。网格点之间的像素,靠插值得出。
举个例子。假设传感器输出是1920x1080,你不可能给每个像素都配一个增益系数。那得存200多万个数,太奢侈了。实际做法是——每隔16个像素取一个网格点。这样一张表的大小就变成了 (1920/16 + 1) x (1080/16 + 1) ≈ 121 x 68,才8000多个数。
网格表的设计有几个关键参数:
| 参数 | 说明 | 我的经验值 |
|---|---|---|
| 网格间距(Grid Step) | 相邻网格点之间的像素数 | 8~32像素,常用16 |
| 网格尺寸(Grid Size) | 水平/垂直方向的网格点数 | 根据图像分辨率计算 |
| 增益精度(Gain Precision) | 每个增益值的位宽 | 12~16位定点数 |
| 存储格式 | 行优先或列优先 | 行优先,方便流水线读取 |
4.2 双线性插值(Bilinear Interpolation)
双线性插值是硬件实现中最常用的方法。为什么?因为它简单、快、资源少。
原理不复杂。对于任意一个像素,找到它周围的四个网格点。先水平方向插一次,再垂直方向插一次。两次线性插值,搞定。
我画了一张图,帮你理解这个过程:
公式看起来有点长,但硬件实现其实就几个乘加器。我习惯用定点数来做,避免浮点运算带来的面积开销。
双线性插值的优缺点很明显:
- 优点: 计算简单,延迟低,适合流水线
- 缺点: 只能保证C0连续,在网格边界处导数不连续
4.3 双三次插值(Bicubic Interpolation)
双三次插值比双线性高一个档次。它用4x4的网格点,而不是2x2。每个方向用三次多项式拟合,能保证C1连续——也就是一阶导数连续。
说白了,双三次插值算出来的增益曲面更平滑,不会出现折痕。代价是计算量大了不少。
核心公式长这样:
G(x,y) = Σᵢ₌₀³ Σⱼ₌₀³ aᵢⱼ · xⁱ · yʲ
其中 aᵢⱼ 是16个系数,由4x4网格点的值通过矩阵运算得到。硬件实现时,一般会预先算好系数,或者用查表法加速。
我整理了一个对比表,方便你选型:
| 对比项 | 双线性插值 | 双三次插值 |
|---|---|---|
| 网格点数 | 2x2 | 4x4 |
| 连续阶 | C0 | C1 |
| 计算量 | 4次乘法 + 3次加法 | 16次乘法 + 15次加法 + 系数计算 |
| 硬件面积 | 小 | 大(约3~5倍) |
| 适用场景 | 普通镜头、低功耗 | 高精度、专业相机 |
4.4 硬件流水线设计要点
不管用哪种插值,硬件实现时都要考虑流水线结构。我总结几个关键点:
- 行缓冲(Line Buffer): 双线性需要2行网格数据,双三次需要4行。行缓冲的大小取决于图像宽度和网格间距。
- 系数预计算: 双三次的系数可以提前算好存到ROM里,运行时直接查表,省掉矩阵运算。
- 定点数精度: 我一般用Q12格式(12位小数位),既能保证精度,又不会溢出。
- 流水线级数: 双线性可以做到2~3级流水,双三次需要5~7级。级数越多,延迟越大,但频率可以跑得更高。
最后放一张整体流程图,帮你把今天的内容串起来:
嗯,今天的内容就到这儿。网格增益表是LSC硬件实现的骨架,插值算法是血肉。选哪个方案,取决于你的项目对面积、功耗和画质的要求。没有的好坏,只有合不合适的取舍。