raw域噪声建模实战:从泊松-高斯模型到均值方差标定
我这几年一听到“raw域噪声建模”这几个字就会想起项目初期拿到第一批raw样张、放大到100%去找噪点特征的那个晚上。噪点这个东西看着是随机分布的小颗粒真要建模才能发现它背后的规律一点也不“随机”。很多朋友一开始都默认用高斯白噪声来模拟raw噪声觉得只要给定一个sigma往干净图上加就行了。结果呢暗部的颗粒感怎么加都不对亮部的纹理又容易被噪声淹没。后来我花了一整个周末把传感器从头到尾标了一遍才把“raw域噪声到底怎么建模”这个问题的门道摸清楚。这篇文章就把这套经验完整整理出来。适合刚接触计算摄影、想做raw域去噪算法、或者需要给ISP仿真器提供噪声输入的朋友参考。我不打算写高深莫测的数学推导尽量用做工程的思路把原理、步骤、坑都讲明白。核心就一句话raw域噪声不是单一的高斯噪声而是“信号相关”和“信号无关”两部分组合起来的混合分布建模的本质是把这两部分拆开标定。1. 为什么raw域噪声建模是个绕不开的事1.1 噪声不是高斯白噪声别再用一个sigma莽过去了先聊一个场景。假设你要训练一个去噪网络训练数据是干净图加上合成的噪声。最常见的做法是把8位sRGB图转成浮点加上高斯白噪声然后输入网络。这种做法在早期demo里能跑通因为网络看到的就是“干净图固定强度噪声”学到的只不过是一层平滑滤波器。一旦你把它部署到真实拍摄的raw上效果立刻露馅暗部要么磨成一块要么残留大量色噪亮部反而容易被过度平滑。问题出在raw域噪声的性质上。真实传感器产生的噪声方差和信号强度是挂钩的。明亮区域入射光子多光子数的随机波动大噪点颗粒就粗黑暗区域入射光子少噪声主要来自电路本身的底噪颗粒相对均匀。如果你用一个固定方差的高斯噪声去近似等于强行把这两类完全不同的噪声混成一个常数那无论怎么调参数都只能勉强照顾到某一个亮度区间。这也是为什么raw域噪声建模要单独拿出来研究。我们要做的不是“加噪声”而是要先理解传感器全链路里噪声从哪里来、以什么形式叠加、最终呈现成什么分布然后才能用一个参数极少但足够准确的模型去描述它。1.2 光子到电子的过程散粒噪声是物理上绕不开的一环任何数字图像传感器的第一步都是光电转换。光子打到像素的感光区域产生电子-空穴对电子被收集起来变成一个电压信号再经过放大、采样、模拟转数字最终成为你在raw文件中看到的那串像素值。关键点在于光子到达像素的过程不是一个均匀、平滑的流而是离散的随机事件。就像餐厅门口在一个小时内来的顾客数量你只能说平均每分钟大概是几个但没法精确预测每一秒会不会来人。光子的到达时间同样服从泊松分布。泊松分布有一个非常有名的特性均值等于方差。设一段时间内到达某个像素的光子期望数是$\lambda$那么实际接收到的光子数量会在$\lambda$附近波动这个波动的方差也正好是$\lambda$。换算到电子数上散粒噪声的标准差大约等于电子数的平方根。假设光子转换电子的量子效率是1像素收集了10000个电子那么散粒噪声标准差就是100个电子信噪比是100。如果某个暗部像素只收集了100个电子标准差就是10个电子信噪比降到10。这个过程决定了信号越强噪声的“绝对幅度”越大但信噪比反而越高。人眼在暗部看到的那些又粗又脏的颗粒本质就是因为信噪比太低噪声幅度相对信号而言十分刺眼。正因为散粒噪声是物理规律决定的建模时不能绕过它。把raw域噪声简化成纯高斯噪声等于是把这一段物理过程完全丢弃模型必然失真。1.3 读出电路和高斯噪声从哪来除了光子散粒噪声像素里的电子还要走一条很长的模拟链路电荷转移、放大、采样保持、AD转换。每一步都会往信号里叠加额外的扰动。复位噪声像素在曝光前要清空电荷但复位后的电压有一个初始随机波动这个波动通常被看作高斯分布。读出噪声放大器本身的电子热运动、1/f噪声、电源波动等统称读出噪声。所有像素共享一部分每个像素又有独立的一部分。这一大堆源头叠加起来中心极限定理会让它非常接近高斯分布。量化噪声AD转换器的分辨率有限模拟电压落到数字码上必然有舍入误差。12bit、14bit甚至16bit的raw精度不同量化噪声量级也不一样通常可以折算进高斯读出噪声里一起标定。高斯噪声不像散粒噪声那样依赖信号强度。它是加性的、独立的、信号无关的。这两类噪声在raw里同时存在混在一起之后整体分布就不再是干净的高斯也不是干净的泊松而是一个“泊松叠加上高斯”的混合体。一个经典类比是你在一个安静房间里听音乐会。散粒噪声好比观众席上掌声的起伏——人多的时候掌声大且波动明显高斯噪声好比音响设备本身的电流底噪——不管你鼓不鼓掌它都在那里。要描述最终听到的总噪声只测音响底噪是不行的还必须把掌声的均值-方差关系一起建模。2. 主流的噪声模型长什么样2.1 泊松-高斯模型一年到头都逃不过的公式接触raw噪声标定的人最后基本都会落到同一个模型上也就是泊松-高斯模型。它把光电子转换过程看作泊松过程把后续读出过程看作高斯过程两个过程首尾相接形成完整链路。写成公式大概是这个样子x a * n_p(λ) n_g c其中x传感器输出的数字信号单位DN数字码值λ像素接收到的光子数对应的电子数a转换增益把一个电子的电荷量换算成多少DN单位是DN/e⁻n_p(λ)服从均值为λ、方差为λ的泊松随机变量n_g读出噪声近似高斯分布均值为0方差为σ_g²c黑色电平black level传感器没有光照时也会输出的基准码值对这个模型取期望和方差会得到两条很干净的公式E[x] a * λ cVar(x) a² * λ σ_g²把第一个公式变形出λ(E[x]-c)/a代进第二个公式就能消掉λVar(x) a * (E[x]-c) σ_g²在raw处理流程里白色电平减去黑色电平是一个常规操作。如果提前做了这个减法c就抵消掉了模型进一步简化成Var(x) a * mean b其中b集中了读出噪声方差和其他固定底噪。这就是均值-方差模型。它的核心含义是噪声方差和信号均值呈一次线性关系。斜率a取决于转换增益截距b取决于读出底噪。这个模型最讨喜的地方在于它把复杂的泊松混合过程变成了一个可以用线性拟合直接标定的模型。只要你有足够多的raw帧能算出每个像素位置的均值和方差就能拟合出a和b。这也是后面所有实操的基础。2.2 FPN和暗电流时间噪声之外的固定图案上面说的散粒噪声和读出噪声都是“时间噪声”也就是说同一像素在不同帧里的取值会随机变化。除此之外传感器还有一类“固定图案噪声”Fixed Pattern NoiseFPN。固定图案噪声的成因包括像素之间暗电流大小不一致。暗电流是即使没有光照像素也会因为热激发慢慢积累的电子。不同像素的暗电流由于制造工艺差异略有不同长时间曝光后就会形成固定的点状图案。列放大器、列采样电路的不一致性。这类误差通常表现为竖向条纹也就是行噪声column noise或列噪声。某些传感器还会因为电源时序问题出现明显的水平横纹。像素复位电压差异。每个像素的复位MOS管阈值电压不完全相同导致每次曝光起始点有一个像素相关的偏置。固定图案噪声不随时间变化因此利用多帧平均就可以把它分离出来。把几十张暗场raw叠起来取平均随机的时间噪声会被平均掉剩下的就是一张“固定图案噪声地图”。处理时把每一帧减去这张地图就完成了FPN校正。这里必须提醒一个容易被忽略的点固定图案噪声不是纯加性噪声。暗电流和曝光时间成正比温度越高、曝光越长暗电流引起的FPN越严重。因此做长曝光raw噪声标定时必须按实际曝光时间和温度来选择对应的暗场帧不能拿一张1/30秒的暗场图去校正4秒曝光的raw那样暗部会长出明显的光斑和条纹。2.3 PRNU要不要放进来光响应非均匀性Photo Response Non-UniformityPRNU是另一个绕不开的项。它描述的是同样强度的光打到不同像素上产生的电子数不完全一样。这是因为每个像素的量子效率、微透镜对光的汇聚能力存在微小的工艺差异。PRNU本质上是乘性噪声——信号越强像素间的固定差异越大。PRNU的常规处理方式和加性FPN不同。一般做法是拍摄均匀光照下的多帧亮场raw平均后得到一个“均匀光响应图像”。把整张图除以全局均值得到的就是PRNU归一化因子图。后续处理亮场raw时把像素值除以这个因子就能把每个像素的响应拉回平均水平。在噪声建模里PRNU要不要放进模型取决于应用精度要求。如果你只是大概合成一点噪声来训练网络PRNU可以先用一个小方差的乘性噪声去近似或者干脆忽略因为深度学习网络能从数据里自动学出一部分不变的模式。但如果你是在做sensor characterization或者要评估硬件性能PRNU就必须单独标定不然后续均值和方差的估计都会有偏差。2.4 为什么要用均值-方差曲线而不是直方图拟合有人会问既然噪声分布已经知道了为什么不直接拍一张均匀灰卡raw看它的直方图然后拟合参数理论上可以但实际操作很麻烦。单张raw的直方图是“空间上所有像素的噪声融合结果”。假设画面里有一个从亮到暗的渐变直方图会被拉伸得很宽很难直接看出噪声分布形态。一定要用大片均匀区域才能让直方图集中反映某个亮度下的噪声分布。而只要亮度有一个轻微的渐变或者照明不均匀直方图就会变宽拟合出来的方差偏大。均值-方差曲线的做法则是拍摄多帧同一场景对每个像素位置计算时域均值和时域方差。这样可以直接控制“同一个亮度水平下的噪声”。一张raw里哪怕有丰富纹理只要多帧之间的场景是静止的纹理部分因为帧间不变不会贡献到时域方差里反而是那些亮度平坦区域时域方差完全由噪声决定。因此均值-方差曲线天然规避了场景纹理对照度估计的干扰。只需要把像素按亮度分箱统计每个亮度箱里的平均方差就能得到一条稳定的噪声曲线。这也是行业里做raw噪声标定最通用的方法。3. 噪声标定实操全流程3.1 前期准备器材、环境、数据清单开始标定之前先把环境稳定下来。温度是最大的变量传感器暗电流随温度几乎是指数增长。实测经验是相机开机预热20分钟以上让传感器温度稳定到正常工作状态再开始采集数据。整个标定过程最好在恒温房间进行避免中途空调开关导致温度上下跳动。需要的器材清单并不复杂一台能输出raw格式的相机或开发板能手动锁定曝光参数、ISO、白平衡一个带手动挡的恒定光圈镜头或者干脆用机身自带的传感器直采模式避开镜头光圈不一致带来的暗角全黑不透光的镜头盖或者一小块黑色绒布用来拍暗场一个可调亮度的均匀光源。最好用积分球没有积分球就用多张灰卡纸加无影灯凑合一台能跑Python的电脑数据采集的策略按下面这个矩阵来打变量取值建议说明ISO/增益最低、中间、最高至少三档最好按1、2、4倍数取模拟增益和数字增益切换点附近参数会突变曝光时间暗场要拍多档如1/30s、1/2s、2s、8s用于拟合暗电流随曝光时间的变化光源亮度用中性密度片衰减或调节光源功率取8~12个亮度级别覆盖暗部到接近饱和的整个动态范围帧数每个条件至少30帧推荐64~128帧方差估计精度与帧数平方根成正比帧数太少曲线会很毛糙我第一次标定时偷懒每个ISO只拍了16帧拟合出来的曲线上下抖动严重尤其是暗部区域方差估计的置信区间宽到没法用。后来加到64帧之后曲线才光滑到能直接用。帧数这东西宁多勿少。3.2 暗场数据采集盖镜头盖的艺术暗场数据的核心目标是标定“信号为零”时的噪声本底。所谓“信号为零”指的是完全无光入射时传感器的输出。听起来很简单实际上最容易被测试者搞砸。先说物理遮光。镜头盖拧上之后我还习惯用黑色绒布把镜头筒整个包住防止盖子的缝隙漏光。注意取景器也会漏光单反要盖目镜遮罩无反相机则要盖机身盖拍摄。我甚至见过有人在白天用机身盖拍暗场结果因为机身盖边缘有微小的漏光暗部出现了微弱的横向渐变条不仔细看根本发现不了。暗场数据建议按下面步骤采集相机锁定在手动M挡固定ISO和曝光时间。盖上镜头盖包好遮光布拍第一帧。拍完不要改变任何参数连续拍摄64帧以上。换下一组曝光时间重复上面步骤。采集暗场的目的有三个一是估计读出噪声方差二是提取固定图案噪声地图三是拟合暗电流随曝光时间的变化。暗场中所有像素的均值应该等于黑色电平如果发现暗场均值明显偏高通常就是遮光没做好或者曝光时间太长导致暗电流很大。用Python读取暗场raw时注意raw文件里有一些光学黑区optical black像素它们被专门遮挡可以用来动态估计黑色电平。如果直接拿整张图减掉一个固定常量可能会因为温度变化引入偏差。最稳妥的做法是读取raw文件内嵌的黑色电平信息或者用光学黑区逐行估算。3.3 亮场数据采集均匀光源的讲究亮场拍摄是用来拟合均值-方差曲线主体部分的数据。光源均匀性直接影响标定精度。积分球是最理想的均匀光源它内部是一个中空球体内壁涂有高反射漫反射材料光线经过多次反射后从出口射出亮度极其均匀。没有积分球时退而求其次可以用大张灰卡纸配合两盏无影灯从两侧45度均匀打光用镜头对着灰卡纸拍摄。这里的坑是灰卡纸本身可能有轻微的纹理或纸纤维反光多帧平均之后空间方差会偏高影响方差估计。实际操作中我会用一套中灰阶卡从接近黑色的深灰到接近过曝的浅灰每张拍一组不同ISO和曝光的raw。如果只能控制光源亮度就把快门、光圈固定调节光源功率来改变亮度水平。曝光时间最好固定在一个值避免暗电流在亮场数据里混入过多贡献。还有一点容易被忽略镜头暗角。任何镜头在最大光圈下都会出现边缘亮度下降导致画面四周的均值偏低。如果直接用整张图统计均值-方差同一帧里会混入多个亮度水平曲线会变得不干净。处理办法很简单用镜头的vignette校正文件提前校正或者只取画面中央约30%区域做统计避开暗角明显的边缘区域。几组亮场数据采集完成后应该快速检查每帧的直方图。如果某组数据出现了大面积饱和说明亮度设置过高降低光源亮度或缩小光圈重拍如果各组数据的均值都挤在一个很窄的区间说明亮度级别不够分散后面拟合出的线性关系可信度也会下降。3.4 预处理黑电平、拜耳分通道、去FPN拿到raw数据之后先做预处理再做统计。预处理这一步做不好后面拟合出的参数全是错的。读取raw文件可以用rawpy、tifffile这类库。读出来的原始数据通常是16bit整数已经有厂商写好的黑电平值。处理流程如下减去黑色电平。raw文件标头或DNG元数据里会有black level字段比如1024或2048。减掉这个值让“纯黑”信号的均值落到0附近。分离拜耳通道。普通彩色传感器的raw是拜耳阵列R、Gr、Gb、B四个通道分别对应不同光谱响应和增益路径。噪声参数必须分通道标定因为绿色通道在白平衡数字增益下可能已经被乘了不同系数混在一起统计会得到一个不伦不类的平均结果。去除固定图案噪声。用暗场多帧平均得到的FPN地图逐帧减去。检查饱和像素。凡是超过白电平减去黑电平后的阈值比如14bit raw里超过16000的像素一律丢掉不参与统计。这里尤其要说一下拜耳分通道的必要性。有些开发板在raw域输出的RGB增益是已经乘过的也就是说绿色通道的噪声方差已经被放大。如果你不分通道直接全图统计得到的是一个把“物理噪声”和“数字增益”混在一起的综合系数。用在合成噪声时每通道还要反推一次增益麻烦得很。分通道标定后每个通道的参数可以直接对应到拜耳图对应位置后续做噪声合成时也更好操作。整个预处理过程的代码框架也不复杂下面这段是核心的统计逻辑import numpy as np def calc_mean_var(frames): # frames: (N, H, W) uint16 raw frames, black-level already subtracted stack frames.astype(np.float32) / 65535.0 mean stack.mean(axis0) var stack.var(axis0, ddof1) return mean, var # 按通道拆分 def split_bayer(img_2d, patternRGGB): if pattern RGGB: return img_2d[0::2, 0::2], img_2d[0::2, 1::2], img_2d[1::2, 0::2], img_2d[1::2, 1::2]这样每个通道会得到一张“均值图”和一张“方差图”。把均值图和方差图里的所有像素取出来再按均值分箱就能得到用于拟合的散点。3.5 拟合参数从均值-方差到a和b拟合阶段的目标是让每个通道都拟合出“Var a × mean b”的线性参数。但这个拟合不是普通的直线拟合需要讲究权重和稳健性。先把所有像素按均值分成若干个bin。比如从0到接近饱和的范围内分256个bin每个bin内计算像素的平均均值、平均方差。分箱操作有两个好处一是把高动态范围的数据压成少量节点让拟合更稳定二是同一个bin内可能有几十万像素方差估计的误差被大幅平均掉。分好箱之后用加权最小二乘拟合直线。权重怎么取暗部区域的方差本身较小如果直接等权重拟合会被大量暗部点拽偏。按误差传播理论方差估计的采样误差大约正比于Var/sqrt(N_bin)可以近似给每个bin的权重取1/Var²让高信噪比、方差更大的区域获得更高权重。老手一般懒得手动算权重直接用scipy的curve_fit配合绝对误差或Huber损失也够用。拟合得到斜率a和截距b之后要画图检查残差。正常情况下亮部残差应该在零附近随机波动如果出现明显上翘或下弯大概率是PRNU没校正干净或者有暗电流混入了均值增量。把不同ISO的拟合结果放在一个表里趋势应当大致是ISO越高斜率a越大因为模拟增益把每个电子对应的DN数放大了截距b通常也会增大但增大的幅度不如斜率那么规律。下面是我在某项目里标定得到的一个示意结果ISO斜率aDN/e⁻截距bDN²1000.111.62000.212.34000.432.98000.874.416001.727.632003.5015.2注意这张表只是给你一个直观感觉不同型号的传感器差异很大。斜率接近整数倍上升说明以模拟增益为主如果斜率在某些档位没有成倍增长很可能中间混入了数字增益切换。4. 噪声模型的验证与应用4.1 先用合成噪声验证模型正确性模型标定完之后第一件事不是拿去训练网络而是先在干净raw上合成噪声拿真实噪场与合成结果做对比验证模型是否靠谱。合成噪声的代码长这样。这里用“泊松采样电子数高斯读出”的严格形式避免用高斯近似在高增益暗部翻车import numpy as np def synthesize_noise(clean_dn, black_level, a, sigma_read, patternRGGB): # clean_dn: float32 raw-like image, black level included or not? x clean_dn - black_level # 信号分量单位DN electrons x / a # 由DN换算回电子数 shot_e np.random.poisson(np.maximum(electrons, 0)).astype(np.float32) out_dn shot_e * a black_level out_dn out_dn np.random.normal(0, sigma_read, out_dn.shape) return out_dn合成完成后拿一张真实拍摄的raw做对比把同一场景用两种方式呈现左边是真实raw放大后的噪点右边是合成模型生成的噪点。如果几乎看不出差别说明标定参数可信如果暗部颗粒明显偏小或偏大就要回去检查暗场数据或者拟合权重。有一个很常见的细节实际raw里黑色电平是一个整数值比如1024但噪声合成时如果直接加高斯噪声到整数上取整后会出现微小的步进伪影。更好的做法是保持浮点运算最后再按需要进行取整。去噪网络训练时通常会输入浮点数据所以这一步不太要紧如果是直接用raw文件保存就要小心。4.2 去噪网络训练数据增强的正确姿势有了可靠的噪声模型最直接的应用就是给去噪网络合成训练数据。很多人训练raw域去噪网络时是在任意sRGB干净图上加固定噪声再转raw这种做法的问题在于sRGB图像已经经过了白平衡、去马赛克、颜色校正、gamma映射链路像素亮度已经不再是传感器线性信号。你要在sRGB上加噪声必须先把噪声方差映射到sRGB空间去而这个映射是非线性的很难精确建模。更合理的流程是准备线性raw格式或无失真线性HDR图像作为干净数据模拟不同的场景辐照度结合标定好的a、b参数给每个像素生成噪声把带噪raw通过真实ISP管线转成sRGB作为网络的输入把干净raw通过同样ISP管线转成sRGB作为训练目标这样做的好处是网络学到的映射始终在真实sRGB空间里不需要额外设计复杂的噪声变换。多帧数据增强时还可以在每帧之间随机扰动ISO和曝光时间模拟用户在不同拍照条件下的噪声变化这样训练出来的网络对增益档位更有泛化能力。数据增强里还有一个技巧不要直接在整个亮度区间使用同一个噪声模型。动态范围极高的场景比如窗外逆光和室内暗部同时存在亮部散粒噪声大、暗部读出噪声主导要先算出每个像素位置对应的噪声方差再逐像素采样。随机采样时可以对a、b参数加入10%~20%的扰动量让网络见过更多噪声形态能明显提升真实场景上的鲁棒性。4.3 ISP仿真、相机原型评估等其他用途除了训练数据噪声模型还常用于ISP仿真。我在调某个前摄效果时经常需要提前模拟“换了传感器之后的高感表现”。这时候只要从新传感器标定出新的a、b参数就能在不换硬件的情况下快速生成一套接近真机的raw噪声样本代入ISP流水线里提前调降噪参数能省下一大笔工程调试时间。噪声模型还能用来做“可感知噪声水平”评估。传统测试人员喜欢直接看测试卡上的噪点密度其实不如把raw数据代入模型计算不同亮度区域的等效噪声标准差再映射到视觉敏感度曲线上得到一张“噪声可见度地图”。这张图可以直观指导降噪算法该在哪些区域加力、哪些区域收手。比较贴心的一点是标定过的模型可以复用到同一个供应商同一批工艺的传感器上。如果你手头有同型号模组的标定数据直接拷贝参数往往八九不离十能省掉重复标定的时间。但跨型号、跨工艺的传感器就不能随便套用了那会把你带到坑里。5. 踩坑记录与问题排查5.1 温度漂移标定参数今天能用明天就飘温度对暗电流的影响非常明显。曾经有一次标定完暗场下午去户外阳光下拍了一组验证raw发现暗部均值整体抬升了好几十个DN噪声方差也随之变大。有些传感器在环境温度从25度升到50度时暗电流噪声可能会翻好几倍。要规避这个问题建议在标定过程中同时记录传感器温度。现在很多设备的raw元数据里带机身温度、传感器温度字段读取一下并不费事。实际应用中把模型参数按温度做个简单线性外推比硬套一套常温参数要靠谱得多。如果只是做算法研发不追求绝对精度至少要做一件事暗场数据的采集环境温度和实际拍摄场景不要差太多。冬天在室外拍素材就不要用夏天标定的暗场参数直接去推噪声模型。5.2 黑电平裁剪噪声分布直接被截断raw数据在数字域里有一个暗部“裁切”问题。传感器输出经过AD转换后如果信号低于黑电平有些处理链路会直接把数值“卡”在黑电平上导致暗部的噪声分布不再对称负方向的噪声被截掉了。这种情况会让均值-方差模型在极暗区域失效因为实际测得的方差会比真实噪声方差更小。碰到这种裁剪现象有几个处理思路在标定数据采集时先确认raw文件里有没有存负值或低于黑电平的码值。多数高质量raw允许低于黑电平的数值存在这样噪声信息才完整。如果确认被强制裁切就要把模型的使用下限抬高只对黑电平以上若干DN的信号建噪声模型。在一些ISP设备上黑电平本身会被实时动态调整需要确认标定时用的黑电平与运行时的黑电平一致。这个坑在暗部细节较多的夜景场景里尤其容易被忽视。去噪算法在暗部一旦把裁切噪声当成高斯噪声去处理很容易在纯黑区域产生色斑被误判成“色彩噪声残留”。5.3 白平衡增益已经把通道乘过了很多raw开发板的用户直接拿RGB raw做统计却忘了raw里的RGB增益可能不是1:1:1。相机厂商经常在raw输出前就乘上了白平衡数字增益结果蓝色通道的增益可能是红色的两倍多导致蓝通道的噪声方差被放大。如果建模时没注意到这一点你拟合出的“蓝色通道b值”其实是“原始读出噪声×数字增益²”而这不是传感器本身的物理参数。解决方法是查看raw元数据里的as shot neutral或color matrix确认各通道当前增益如果白平衡增益已经乘进去了建模时可以单独记录每个通道的有效数字增益并在合成噪声后再模拟白平衡。否则每次换一个白平衡设置模型参数也要跟着变非常不利于算法落地。我之前就犯过这个错误标定出来的绿色通道噪声比红色通道高一大截怎么都解释不通。后来检查元数据才发现开发板默认白平衡把绿色增益乘了1.4倍。重新按物理通道标定之后参数立刻干净了。5.4 数据量不够方差估计本身有偏差方差估计有一个反直觉的特性如果你的帧数太少Estimating variance is noisy而且不只是噪声大它是有偏的。当采样数非常少时得到的方差会系统性偏小并且随着均值升高偏小得更厉害。这会让你拟合出来的斜率a偏低看起来像传感器增益不高。经验法则是暗部区域因为方差小想要把方差估计的误差压到10%以内至少需要上百帧亮部区域方差大30帧也能凑合。所以标定时要平衡总数据量每个ISO档位下暗场和不同亮度的亮场尽量都拍够64帧以上。存储空间不够时宁可减少亮度级别也不要减少帧数。如果时间实在紧张也可以先用少量帧做一次“粗糙标定”拿到大致参数范围之后再补充数据精修。但粗糙结果不要直接用于训练网络不然合成的噪声方差偏差会在网络里固化下来后期很难通过调整网络结构弥补。5.5 非理想场景HDR、多帧合成和低照度极限现在很多设备有HDR模式、多帧RAW输出和超高ISO合成功能。这些模式下噪声模型不能直接用普通标定参数套多帧HDR合成raw同一帧内不同像素可能采用不同曝光时间噪声方差在空间上不连续标定时需要按曝光比分组统计。多帧降噪raw厂商已经在芯片内做了对齐和叠加输出raw的噪声水平已被压低用普通标定参数去模拟会高估噪声。超高ISO下的数字增益叠加如果模拟增益已经到头数字增益继续放大信号和噪声斜率a会随着ISO进一步增大但不再是整齐的倍数关系。碰到这些场景我建议直接对“最终输出raw”重新标定而不是试图从底层物理参数推导。因为芯片内部的信号处理链越来越复杂你很难还原厂商每一步做了什么。针对应用层做标定才是最省力的方案。还有一类低照度极限情况环境亮度极低时像素值接近甚至低于黑电平泊松采样的电子数有时候只有个位数这时候严格泊松-高斯模型的采样过程就特别重要。如果用高斯近似去生成噪声暗部会生成明显的负像素值即使加上黑电平也无法修复必须用np.random.poisson采样电子数再换算回DN才能得到看起来自然的极暗部颗粒。6. 一条实用的收尾建议如果让我给刚接触raw域噪声建模的朋友一句建议我会说先别急着搭网络、调loss花一个晚上把均值-方差曲线标出来。你会对人眼看到的噪点有完全不一样的认知。现在我每到一个新项目拿到第一批raw样张后都要做一次噪声标定看起来是额外工作实际上后面所有降噪、仿真、评测的道路都会顺畅很多。最后分享一个小技巧标定完成之后把所有参数和采集环境条件整理成一个配置文件放在工程仓库里留档。参数不仅要记录a、b值还要记录传感器型号、固件版本、温度、曝光时间、黑电平、通道增益这些细节。下次想复现某个效果或者排查奇怪问题时这些记录能帮你节省一大半时间。噪声建模这件事参数本身不神秘真正珍贵的反而是标定过程中的边界条件和踩坑记录。