作者: FAE SHARE,微信公众号
一、CCM介绍
由于Sensor采集到的颜色分量曲线与人眼对颜色分量的感知曲线不一致,所以会导致拍摄的图像呈现在人眼前时感觉与真实世界相去甚远。因此需要对Sensor采集的图像做线性或者非线性的映射,以追求符合人眼的感知特性。这一过程通常经过1D查找表映射(RGB单通道内)和color correction matrix(CCM,3x3 matrix)来对图像进行校正。
以蓝色通道为例,蓝色通道是来自场景中的蓝色光谱的组合通过蓝色滤光片后在感光器件上的响应值。然而,滤光片和感光器件的反应与人眼的反应大不相同,所以传感器看到的蓝色和人看到的蓝色是大不相同的。这种差异可以被纠正,使其更接近于人类视觉可接受的蓝色。颜色校正矩阵核心是将像素值乘以一些系数来增强或减弱它,从而产生有效的增益。同时,可以在蓝色通道中加入绿色或红色通道影响。为了用数学方法来表达这个过程,校正后的蓝色(Bc)与校正前的蓝色(B)、红(R)和绿(G)的关系如下:
Bc = K1 x R + K2 x G + K3 x B
其中K1、K2和K3是红、绿、蓝混合到校正后的蓝色的权重。扩展这个概念,一个标准的3×3矩阵乘法可以同时并行应用于每个颜色通道。这是一个矩阵操作,其中权重定义了一个颜色校正矩阵。在典型应用中,色彩校正还包含偏移补偿,如图1-1中偏移量O,以确保色彩范围能填充满整个色域。
图1-1、CCM公式示意图
二、CCM参数标定
标定通常需要一张标准的24色卡。24色卡是一种常用的色彩参考工具,它包含了24种常见的颜色,这些颜色经过精确的配比和标准化处理。
色卡能提供24种颜色的理论值,如图2-1所示。
图2-1、24色卡的理论值(图片来源wiki)
有了理论值,我们还需要一张在特定色温下拍摄的未经CCM变换的24色卡图,即真实的图像值,如图2-2所示。
图2-2、未经CCM处理的原始24色卡图
统计上述24色卡中的对应24种颜色值,可以得到3x24的矩阵B:
图2-3、统计每个色块的RGB通道值
结合之前提到标准色卡提供24种颜色的理论值的矩阵A(3x24),以及需要求出的3x3矩阵M,可以得到公式:
A=M*B
即可通过最小二乘法或梯度下降等方法算出接近的矩阵M。如矩阵M为:
[1.8069-0.3559 0.0757;
-0.44881.6948 -0.6218;
-0.3581-0.3389 1.5460]
将3x3矩阵M参数对原始图像进行运算即可得到CCM后的图像。
图2-4、24色卡CCM后的图像对比
图2-5、真实图像CCM后的图像对比(原图是已处理过的)
三、基于AMD FPGA的CCM实现
AMD Vivado 2019.1之前的版本可以直接调用Color Correction Matrix LogiCORE来进行设计。
图3-1、AMD Color Correction Matrix LogiCORE
在AMD Vivado 2019.1以及之后的版本,集成到了Video Processing Subsystem中,作为Color Space Conversion的一部分与Vivado绑定免费使用。
图3-2、VPSS for CCM
当然,客户也可以按照自己的需求来设计实现,只需要消耗少量的LUTs或DSP48(也可全部使用LUTs)资源。
图3-3、rtl实现
图3-4、12bit深度RGB CCM资源占用
四、3D LUT介绍
了解3D LUT是什么之前,有必要先了解一下什么是1D LUT。LUT是查找表Look Up Table的缩写。在图像编辑、电影和视频中,LUT用于根据LUT中包含的数据将源像素的输入颜色值重新映射到新的输出值。
应用1D LUT时,其本身只能将一个输入值更改为一个输出值。这意味着它只能用于亮度的变化,例如伽玛校正、对比度、亮度和黑白级别。
图4-1、1D LUT映射
通常将3x 1D LUT一起使用:每个颜色通道一个。当LUT应用于源时,每个像素的输入红色、绿色和蓝色值将映射到新的输出值。LUT根据LUT中包含的值相互独立地整每个红色、蓝色和绿色通道的亮度。
图4-2、3x1D LUT映射
虽然1D LUT对于许多色彩校正任务(例如总体色彩平衡和伽马校正)很有用,但它们缺乏更复杂的非线性色彩校正所需的精度。之前提到CCM也是如此。
在高画质要求的专业视频领域如广播电视、电影和图形行业中,人们可能不满足于线性处理的调色效果。这个时候,一种非线性的颜色空间映射方式3D查找表( 3D LUT )有了用武之地。
3D LUT用于颜色分级以及将一种颜色空间映射到另一种颜色空间。最理想的情况下,输入一个点[sR,sG,sB]即可从3D LUT表中查出一个点[dR,dG,dB]。但是现实是,以RGB深度为10bit为例,3D LUT表需要存储1024x1024x1024个dRGB值,超过了10亿个值,这是一个非常庞大的数据量,对实现的硬件平台要求非常苛刻。因此,常见的作法是抽样形成3D LUT表,再在后续的运算中做插值补偿得到近似的值。常见的3D LUT表网格有17x17x17、33x33x33、65x65x65或更高,位深度可以是8位、10位、12位或更高。
因此,3D LUT可以理解为是输出RGB颜色值的3D网格,可以通过输入RGB颜色值集进行索引。3D网格的每个轴代表三个输入颜色分量之一,因此输入颜色定义在3D网格内的一个点。由于该点可能不在格点上,因此必须对格值进行插值。
图4-3、3D LUT表 示意图
五、3D LUT Cube文件
Cube文件是一种标准的3D LUT调色文件,里面包含表的格式以及LUT值等,通用于许多后期调色软、硬件,比如Adobe Photoshop、Sony Vegas、BlackMagic Davinci等。
以柯达的“Rec709 Kodak 2383 D65.cube”为例,头文件中“LUT_3D_SIZE 33”表示3D LUT的晶格为33x33x33,“LUT_3D_INPUT_RANGE 0.0 1.0”表示像素值由0到1之间的数据表示(在实际FPGA实现中需要根据实际像素位深度来定点和截取)。
图5-1、Cube文件示意
一拉到底会发现除去头文件的长度,数据长度为35937,即33x33x33。
六、3D LUT实现过程
3D LUT映射的实现过程主要分为两部分:位置确定和插值。
确定输入的像素rgb在3D LUT网格内的位置,得到8个网格点:
图6-1、rgb在3D网格中的位置
如图3-1所示,输入像素rgb在3D LUT网格内的位置,这一过程通过rgb像素的高位部分来获取。以33x33x33的3D LUT为例,rgb像素每个通道的高5bit就能确定(R0,G0,B0)、(R0,G0,B1)、(R1,G0,B1)、(R1,G0,B0)、(R0,G1,B0)、(R1,G1,B1)、(R1,G1,B0)、(R0,G1,B0) 8个网格点的位置。
插值是3D LUT映射最重要的环节,插值算法的选择对图像质量的影响很大。目前主流的插值算法是采用四面体插值或三线性插值。
插值的权重系数由rgb像素每个通道的低位确定,如下图所示:
图6-2、插值权重系数
对于三线性插值,第一步插值:在R轴方向上进行线性插值,得到四个中间值。
第二步插值:在G轴方向上对第一步的结果进行线性插值,得到两个中间值。第三步插值:在B轴方向上对第二步的结果进行线性插值,最终得到目标点的值。三线性插值过程由下图所示:
图6-3、三线性插值过程
对于四面体插值,需要判断(r,g,b)位于哪个四面体内。如果(r,g,b)位于某个四面体的内部,则利用该四面体的顶点信息进行插值计算。
图6-4、四面体插值中的6种情况
在FFmpeg中,由对上述两种插值方式的C语言实例,如下图所示:
图6-5、两种插值实例
用“Rec709 Kodak 2383 D65.cube”c处理色度测试图大致效果如下图:
图6-6、3D LUT映射效果
通过Davinci分析不同插值后的图像波形,可以看出四面体插值和三线性插值的效果最好并且相差无几,而普通的两点插值效果较差。
图6-7、3D LUT处理后波形(分别是上下点插值、四面体插值、三线性插值)
七、基于AMD FPGA的3D LUT实现
AMD提供第三方的3D LUT颜色校正和处理IP core的支持,可在ZCU104 Zynq开发板上运行,并使用AMD的HDMI 2.0内核接收RGB 24位格式的4K30输入并以30位HDR输出RGB。
我们也可以基于Xilinx提供的BRAM/UltraRAM等资源来实现。
算法的实现不在赘述,主要需要考虑的点有两方面:设计使用BRAM/UltraRAM来存储3D LUT以达到BRAM资源最小化;设计pipeline来满足实时性要求,在一个像素时钟内完成最多8个点(三线性插值)或4个点(三面体插值)的取值和插值运算。
图7-1、定点后的coe文件用于存储3D LUT初始值
图7-2、基于AMD FPGA一路33x33x33的3D LUT实现的资源占用情况
图7-3、对实时视频增加电影模板(Rec709 Fujifilm)的效果对比
如果您在使用FPGA实现图像ISP方面有疑问,欢迎联系:
simonyang@comtech.cn
charlesxu@comtech.cn