【ISP】CCM变换和标定

1.CCM的简单介绍

1.1人眼的特性

人眼视网膜的微观结构如下图所示。

从图中可以看到,人眼视网膜上有三种锥细胞(cone)用于感受蓝、绿、红三种频率的色光,一种杆细胞(rod)只在低照度条件下感应亮度信息,不能分辨颜色和细节。

已知三种锥细胞的总个数大约600~800万,分布比例大约是1:16:32,杆细胞的总数大约是1200万。人眼的三种锥细胞对不同波长的电磁波的响应是有明显区别的,研究发现,人眼的红、绿、蓝三种锥细胞光谱响应曲线的峰值比例是0.54:0.575:0.053,如下图所示。

如从图中曲线可以看到,人眼对波长为555纳米的绿色光吸收率可达20%,对波长为650纳米的橙色光的吸收率在4%左右,对波长为450纳米的蓝色光的吸收率最高只有2%左右,大约是绿色光最高吸收率的1/10。

因此,对于辐射强度相同而颜色(波长)不同的光,人眼的亮度感觉是不同的:波长为555纳米的黄绿光感觉最亮,波长为450纳米的蓝色光感觉最暗。另外还发现,当光线微弱时,人眼最敏感的波长会移动至507nm。

人眼对不同波长的光有不同的色调感觉,严格地讲,只有波长为572nm的黄光、503nm的绿光和478nm的蓝光,其色调不随光强而变化,其它波长的色光都随光强的改变略有变化。在可见光谱中,从紫到红分布着各种不同的颜色,人眼能分辨出色调差别的最小波长变化称为色调分辨阈.其数值随波长而改变.人眼对480~640nm区间色光的色调分辨力较高,其中,对500nm (青绿色)和600nm(橙黄色〉两个波长来说,只要波长变化约1nm,便可分辨出色调的变化。而从655nm的红色到可见光谱长波末端,以及从430nm的紫色到可见光谱短波末端,人眼几乎感觉不到色调的差别。当饱和度减小时,人眼的色调分辨力将下降;当亮度太大或太小时,色调分辨力也会下降。

1.2CCM颜色校正

人眼在可见光波段的频谱响应度和半导体传感器的频谱响应以及显示器的激励响应都存在较大的差别,这些差别会对摄像机的色彩还原造成较大的影响。举例来说,从下图所示的光谱响应曲线中可以了解到,一个典型的硅材料sensor在500nm处对蓝、绿光的响应几乎是相等的,但是人眼的蓝色锥细胞对500nm的蓝绿光响应却几乎为零。假设sensor按照自己的特性忠实地记录下它对500nm波长的响应值为b,根据CIE的标准,显示器会在b值的驱动下发出波长为435.8nm的蓝光,使人眼感知到明亮的蓝光。这个过程在人眼看来,就是成像系统在绿色中凭空增加了很多蓝色的成分,降低了绿色的饱和度,造成了颜色失真。

下图是因为人眼和cmos都是针对不同光谱之间的响应程度,是在前端响应端。

有些人会使用LMS那张人眼的图,我认为不合适,因为LMS是使用模拟的三种刺激光,是属于显示器端的发光情况,不属于全光谱的响应情况。(这段有待商榷,我后续有新的理解再来补充)

不仅人眼的响应与sensor不同,不同厂家制造的sensor响应也是不同的。下图显示了三个camera在相同参数下拍摄到的颜色效果。

此外,摄像机光路上一般还存在镜头、滤波片等光学元件,镜头的镀膜、滤光片的频率响应等参数也会对色彩还原造成影响,这些因素综合作用的结果,就是人眼在显示器上看到的RGB颜色与真实世界中感知到的物体颜色存在偏差, 尤其是色饱和度受到较大影响,因此必须对摄像机记录的颜色进行校正以还原人眼的感知效果。

颜色校正,英文color correction,是在RGB空间中完成的处理任务,主流的做法是用一个3x3 的矩阵将一个输入像素值(R, G, B)线性地映射为一个新的像素值(R', G', B'),通过审慎地选择矩阵参数使映射后的颜色更符合人的认知习惯。

Color Correction Matrix (CCM)
The Color Correction Matrix block corrects the image color variations coming from many different causes that can include spectral characteristics of the optics (lens, filters), lighting source variations, characteristics of the color filters of the sensor and many others. The CCM block contains 3x3 programmable coefficient matrix multipliers with offset compensation that can be used in color correction operations such as adjusting white balance, color cast, brightness, or contrast in an image.

为什么ISP模块中要有这个模块呢,上面列的一堆原因,最重要的因素是我们肉眼的对光谱的RGB响应曲线和sensor的响应曲线是不同的(但请注意sensor的QE也不能与人眼相差太远,不然CCM是救不会来的)。

CCM一般是3x3矩阵形式,也有3x4形式的,3x4形式主要是给rgb各自加一个offset

上面的人眼rgb响应和sensor rgb响应曲线都是非线性的,所以指望通过一个CCM矩阵就得到匹配度很好的映射关系是不现实的。现实中,往往会标定很多个CCM,ISP在运行的时候根据照度,光源等等因素,选择两个最近的CCM插值得到最终的CCM。

CCM公式的物理意义是从一种颜色种减除另外两种颜色的成分,以增加该颜色的饱和度,使变换的结果接近人的视觉感受,或者更符合人的主观审美。由于输入颜色可以有上千万种组合,而CCM参数却只有9个,所以CCM实际上只能优先保证几个最重要的颜色在人看来是“正确”的,而不可能面面俱到地保证所有颜色在所有条件下都是最优的。下图显示了变换值(虚线)与理想值(实线)之间的差异。

CCM公式的一个基本约束就是不能破坏白平衡,即对于任何R=G=B的输入,必须保证输出满足R'=G'=B'。正式由于这个原因,颜色校正操作只能放在白平衡调整之后执行。

CCM模块在apply awb gain后面,因此3x3个值存在约束条件:

保证灰点也就是r=g=b的点,经过CCM以后仍然r=g=b;

2.标定CCM方法

  • 用camera拍一张某个色温下的24色卡raw文件:

注意shading影响,拍这个色卡占整个sensor中间一小部分就可以

总共24个patch,用前18个patch即可

  • raw文件预处理

主要包括减blc,根据第4行的patch,获取awb gain值,乘上去;这样就拿到了这个色温下24个patch的rgb值;

  • 理想rgb值

这是色卡厂家提供的24个patch的标准rgb空间下的理论值;

拿到这个值以后,需要进行反gamma处理,因为厂家提供的是srgb的值,是带了2.2gamma的,ISP的CCM模块一般是在gamma前面,因此要对理论值进行反gamma处理;

现在准备工作完成了,接下来是算法。

3.标定算法

已知100个raw rgb值,已知对应的理论rgb值;求一个3x3线性变换矩阵;这个矩阵要使得映射后的rgb值尽可能的接近理论值;

借鉴深度学习的梯度下降方法,可以快速得到CCM;并且可以自定义100个patch的重要程度,使得某些patch的误差非常小。

抱歉手头没有24色卡的raw,没有真实数据;只能用随机数据来模拟了;

首先我们随机生成18个随机rgb值,定义一个矩阵,画出它的映射:

import matplotlib.pyplot as plt
import torch

ccm = torch.tensor([[1655, -442, -189], [-248, 1466, -194], [-48, -770, 1842]], dtype=torch.float32)
rgb_data = torch.randint(0, 255, (3, 100))
rgb_data = rgb_data.float()

rgb_target = ccm.mm(rgb_data)/1024.0

fig1 = plt.figure(1)
ax1 = fig1.add_subplot(111, projection='3d')
x2 = rgb_data[0]
y2 = rgb_data[1]
z2 = rgb_data[2]

ax1.scatter(x2, y2, z2, marker='*', c='b', label='origin RGB')

ax1.set_xlim(-80, 360)
ax1.set_ylim(-80, 360)
ax1.set_zlim(-80, 360)
ax1.set_xlabel('R')
ax1.set_ylabel('G')
ax1.set_zlabel('B')

x3 = rgb_target[0]
y3 = rgb_target[1]
z3 = rgb_target[2]

ax1.scatter(x3, y3, z3, marker='o', c='c', label='target rgb')

for i in range(len(x3)):
    ax1.plot([x2[i], x3[i]], [y2[i], y3[i]], [z2[i], z3[i]], 'k-.')
ax1.legend()

plt.show()

映射关系如下:

现在给原始rgb加一些noise,根据上面得到的CCM后的rgb值,来推算CCM,看是否和预定义的CCM接近:

error_manual = torch.randn((3, 100)) * 16
rgb_target_error = rgb_target + error_manual

定义损失和梯度函数,测量rgb值得差异,采用L2距离;

完整代码如下:

这里可以将RGB转成LAB值,通过LAB计算梯度会更加精准。 

from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import torch

ccm = torch.tensor([[1655, -442, -189], [-248, 1466, -194], [-48, -770, 1842]], dtype=torch.float32)
rgb_data = torch.randint(0, 255, (3, 100))
rgb_data = rgb_data.float()

error_manual = torch.randn((3, 100)) * 16
rgb_target = ccm.mm(rgb_data)/1024.0
rgb_target_error = rgb_target + error_manual
ccm_calc1 = torch.tensor([0.0], dtype=torch.float32, requires_grad=True)
ccm_calc2 = torch.tensor([0.0], dtype=torch.float32, requires_grad=True)
ccm_calc3 = torch.tensor([0.0], dtype=torch.float32, requires_grad=True)
ccm_calc5 = torch.tensor([0.0], dtype=torch.float32, requires_grad=True)
ccm_calc6 = torch.tensor([0.0], dtype=torch.float32, requires_grad=True)
ccm_calc7 = torch.tensor([0.0], dtype=torch.float32, requires_grad=True)

def squared_loss(rgb_tmp, rgb_ideal):
    return torch.sum((rgb_tmp-rgb_ideal)**2)

def sgd(params, lr, batch_size):
    for param in params:
        param.data -= lr * param.grad/batch_size;

def net(ccm_calc1, ccm_calc2, ccm_calc3, ccm_calc5, ccm_calc6, ccm_calc7, rgb_data):
    rgb_tmp = torch.zeros_like(rgb_data)
    rgb_tmp[0, :] = ((1024.0 - ccm_calc1 - ccm_calc2) * rgb_data[0, :] + ccm_calc1 * rgb_data[1, :] + ccm_calc2 * rgb_data[2, :]) / 1024.0
    rgb_tmp[1, :] = (ccm_calc3 * rgb_data[0, :] + (1024.0 - ccm_calc3 - ccm_calc5) * rgb_data[1, :] + ccm_calc5 * rgb_data[2, :]) / 1024.0
    rgb_tmp[2, :] = (ccm_calc6 * rgb_data[0, :] + ccm_calc7 * rgb_data[1, :] + (1024.0 - ccm_calc6 - ccm_calc7) * rgb_data[2, :]) / 1024.0
    return rgb_tmp

lr = 3
num_epochs = 100
for epoch in range(num_epochs):
    l = squared_loss(net(ccm_calc1, ccm_calc2, ccm_calc3, ccm_calc5, ccm_calc6, ccm_calc7, rgb_data), rgb_target_error)
    l.backward()
    sgd([ccm_calc1, ccm_calc2, ccm_calc3, ccm_calc5, ccm_calc6, ccm_calc7], lr, 100)
    ccm_calc1.grad.data.zero_()
    ccm_calc2.grad.data.zero_()
    ccm_calc3.grad.data.zero_()
    ccm_calc5.grad.data.zero_()
    ccm_calc6.grad.data.zero_()
    ccm_calc7.grad.data.zero_()
    print('epoch %d, loss %f'%(epoch, l))

res = torch.tensor([[1024.0 - ccm_calc1 - ccm_calc2, ccm_calc1, ccm_calc2],
                    [ccm_calc3, 1024.0-ccm_calc3-ccm_calc5, ccm_calc5],
                    [ccm_calc6, ccm_calc7, 1024.0-ccm_calc6-ccm_calc7]], dtype=torch.float32)
print(res);

rgb_apply_ccm = res.mm(rgb_data)/1024.0

fig1 = plt.figure(1)
ax1 = fig1.add_subplot(111, projection='3d')
fig2 = plt.figure(2)
ax2 = fig2.add_subplot(111, projection='3d')

x2 = rgb_data[0]
y2 = rgb_data[1]
z2 = rgb_data[2]

ax1.scatter(x2, y2, z2, marker='*', c='b', label='origin RGB')

ax1.set_xlim(-80, 360)
ax1.set_ylim(-80, 360)
ax1.set_zlim(-80, 360)
ax1.set_xlabel('R')
ax1.set_ylabel('G')
ax1.set_zlabel('B')

x3 = rgb_target[0]
y3 = rgb_target[1]
z3 = rgb_target[2]

ax1.scatter(x3, y3, z3, marker='o', c='c', label='target rgb')

for i in range(len(x3)):
    ax1.plot([x2[i], x3[i]], [y2[i], y3[i]], [z2[i], z3[i]], 'k-.')
ax1.legend()

ax2.set_xlim(-80, 360)
ax2.set_ylim(-80, 360)
ax2.set_zlim(-80, 360)
ax2.set_xlabel('R')
ax2.set_ylabel('G')
ax2.set_zlabel('B')
ax2.scatter(x3, y3, z3, marker='o', c='c', label='target rgb')

x4 = rgb_apply_ccm[0]
y4 = rgb_apply_ccm[1]
z4 = rgb_apply_ccm[2]
ax2.scatter(x4, y4, z4, marker='^', c='b', label='apply ccm rgb')
ax2.legend()

plt.show()

运行结果对比:

可视化看一下映射后的点与理论点的距离:

很接近了!!!

参考

https://zhuanlan.zhihu.com/p/108626480

https://zhuanlan.zhihu.com/p/98831426

<think>好的,用户现在问的是关于ISP Tuning在面试中经常问到的问题及答案。我需要先理解ISP Tuning是什么,可能用户正在准备面试,尤其是涉及图像信号处理相关的职位,比如相机开发、图像算法工程师等。ISP Tuning即图像信号处理器调试,涉及优化图像质量的各种参数算法。 首先,我需要回顾之前用户的历史对话,看看有没有相关的内容。之前用户问的是关于合法获取图片资源的问题,现在转向ISP Tuning的面试问题,可能用户现在在准备技术面试,需要这方面的指导。 用户的需求是了解面试中常见的问题答案,可能需要一个结构化的回答,涵盖基本概念、流程、关键技术点、常见问题及解决方案,以及项目经验等。用户可能希望不仅知道问题本身,还要有详细的解答,以帮助他们在面试中更好地表现。 接下来,我需要整理ISP Tuning的关键知识点。例如,ISP的基本流程,包括Bayer去马赛克、白平衡、降噪、锐化、色彩校正等。然后,常见的问题可能涉及这些步骤中的具体挑战,比如如何调试白平衡,如何处理噪声细节的平衡,如何评估图像质量等。 此外,项目经验部分也很重要,用户可能需要知道如何描述自己的项目,突出技术难点解决方案。同时,面试官可能会问及工具使用,比如熟悉哪些ISP工具或平台,以及调试中的具体案例。 需要注意回答的结构清晰,分点列出问题及答案,帮助用户逐步理解。同时,要确保技术细节准确,比如正确解释3A算法(AE、AWB、AF),或者噪声模型的处理方法。还要考虑用户可能存在的疑问,比如调试中的主观与客观评估如何结合,或者如何处理硬件限制带来的挑战。 最后,需要提醒用户结合自身项目经验准备,因为面试中通常会深入询问个人经历。可能还需要补充一些学习资源或建议,比如推荐书籍或在线课程,帮助用户进一步学习。</think>以下是在面试中涉及**ISP Tuning(图像信号处理器调试)**的常见问题及参考答案,结合技术要点与实战经验整理,供您针对性准备: --- ### **一、基础概念类问题** #### 1. **什么是ISP Tuning?核心目标是什么?** **答**: - **定义**:ISP Tuning是通过调整图像信号处理器(ISP)的算法参数,优化图像质量的过程,涵盖去噪、色彩校正、锐化、动态范围控制等模块。 - **目标**: - 提升主观视觉质量(如色彩自然度、细节清晰度) - 平衡客观指标(如SNR、MTF、Delta E) - 适配硬件特性(如传感器噪点分布、镜头光学限制) #### 2. **ISP处理流程的关键步骤有哪些?** **答**:典型流程如下(需结合具体芯片架构调整): ```mermaid graph LR A[Raw图输入] --> B(坏点校正) B --> C(黑电平补偿) C --> D(镜头阴影校正) D --> E(去马赛克) E --> F(自动白平衡AWB) F --> G(色彩校正矩阵CCM) G --> H(伽马校正) H --> I(降噪与锐化) I --> J[输出RGB/YUV] ``` **高频追问**: - **为什么需要去马赛克(Demosaic)?** → 传感器输出的Bayer格式仅含单通道信息,需通过插值算法(如双线性、自适应梯度)恢复全彩RGB。 - **伽马校正的作用是什么?** → 将线性光信号转换为符合人眼感知的非线性响应(近似$V_{out} = V_{in}^{1/2.2}$),避免暗部细节丢失。 --- ### **二、调试实战类问题** #### 1. **如何调试白平衡(AWB)?遇到偏色如何解决?** **答**: - **调试步骤**: 1. 使用标准色卡(如24色卡)拍摄,确保光源类型(D65/TL84等)与场景匹配。 2. 分析色温曲线,调整R/G/B增益比值(如$R/G = f(T)$)。 3. 验证灰区(18%灰卡)的色差(Δu'v' < 0.01)。 - **偏色处理**: - **硬件因素**:检查IR-Cut滤光片是否偏移,或传感器QE曲线异常。 - **算法优化**:引入色域限制(如限制绿色通道增益),或使用动态色温估计(结合场景识别)。 #### 2. **降噪(NR)与细节保留如何权衡?** **答**: - **分层处理**: - **空域降噪**:对低频噪声使用高斯滤波,保留高频边缘(通过梯度检测)。 - **时域降噪**:多帧对齐后加权平均,但需避免运动拖影(用光流法补偿)。 - **参数调节**: - 亮度噪声:调整IIR滤波器的截止频率(如$f_c=0.3 \times f_{Nyquist}$)。 - 色度噪声:增大色差平面的滤波强度(因人类视觉对色噪更敏感)。 #### 3. **如何评估图像质量?主观与客观指标如何结合?** **答**: - **客观指标**: - **SNR**(信噪比):$SNR = 20 \log_{10}(\mu / \sigma)$,要求>40dB(低光下可放宽)。 - **MTF50**:衡量锐度,需达到传感器极限的70%以上。 - **主观评估**: - 组织多人盲测,按**ITU-R BT.500**标准打分(如5分制:1=严重缺陷,5=完美)。 - **协同策略**:客观指标用于初筛,主观评分决定最终调参方向。 --- ### **三、进阶技术类问题** #### 1. **HDR场景下ISP如何实现动态范围扩展?** **答**: - **多曝光合成**: - 采集长/短曝光帧,对齐后融合(权重函数需避免鬼影)。 - **Tone Mapping**: - 使用局部算子(如双边滤波)压缩高动态范围至显示设备范围,公式示例: $$ L_{d} = \frac{L_{w}}{1 + L_{w}} \cdot L_{max} $$ ($L_w$为场景亮度,$L_{max}$为显示最大亮度) #### 2. **低光照环境下ISP调优的关键点?** **答**: - **噪声模型适配**:建立泊松-高斯混合模型,分频段降噪(小波变换)。 - **局部增益控制**:对暗区提亮时,限制增益倍数(如$Gain < 4\times$),避免放大噪声。 - **非均匀性补偿**:标定传感器的固定模式噪声(FPN),通过查找表(LUT)校正。 --- ### **四、项目经验类问题** #### 1. **描述一个你参与的ISP调试项目,解决了什么问题?** **参考答案模板**: - **背景**:某手机项目在低光下出现“色彩断层”(如天空过渡不自然)。 - **分析**:发现色度降噪过强导致色深损失,量化误差被放大。 - **解决**: 1. 降低色度NR强度,改为空时联合滤波。 2. 在伽马校正前插入10bit->12bit的位深扩展模块。 - **结果**:断层问题减少80%,PSNR提升2dB。 #### 2. **调试中遇到硬件限制(如传感器噪声高)怎么办?** **答**: - **软件补偿**: - 增加黑电平校准频率(如每10帧校准一次)。 - 设计基于场景的自适应降噪强度(如暗光下NR强度+20%)。 - **跨部门协作**:推动硬件团队优化传感器驱动(如降低读出噪声)。 --- ### **五、面试官可能追问的方向** 1. **工具链熟悉度**: - 是否使用过Imatest、DXO Analyzer等测试工具? - 如何通过MATLAB/Python脚本自动化参数迭代? 2. **3A算法理解**: - AE(自动曝光)如何与ISP联动? - AF(自动对焦)的清晰度评价函数如何设计? 3. **行业趋势**: - 深度学习在ISP中的应用(如替换传统降噪模块)? - 计算摄影(如夜景模式)对ISP架构的影响? --- ### **学习建议** 1. **理论夯实**:阅读《Digital Image Processing》(Rafael C. Gonzalez)第6章(颜色与空间滤波)。 2. **实战演练**:下载开源RAW图(如[Google HDR+数据集](https://hdrplusdata.org/)),用RawTherapee手动调试并观察效果。 3. **行业标准**:熟悉EMVA1288(传感器表征)、ISO12233(分辨率测试)等标准。 如需深入某个技术点(如Demosaic算法对比),可进一步补充说明。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值