018、Sensor 坏点与热噪点的工厂检测与在线校正方案

发布时间:2026/6/5 11:40:39

018、Sensor 坏点与热噪点的工厂检测与在线校正方案 018、Sensor 坏点与热噪点的工厂检测与在线校正方案一、从一条产线投诉说起去年夏天某款旗舰机在量产爬坡阶段产线突然爆出“暗光预览有白点”的批量不良。QC抽检发现大约千分之三的模组在30秒长曝光下会出现数十个固定位置的亮斑位置不随场景变化。当时产线停线三天我们团队被拉去救火。一开始怀疑是镜头脏污但擦拭后白点依然存在。后来用纯黑帧盖上镜头盖抓raw图发现这些亮斑的像素值比周围高出200-300个DN12bit raw而且位置在多次抓图后完全一致。确认是sensor本身的坏点——准确说是“热噪点”因为它们在短曝光下几乎不可见长曝光或高温下才暴露。这个案例让我意识到坏点校正不是简单的“找出来抹掉”工厂端和在线端的策略完全不同必须分开设计。二、坏点与热噪点的本质区别先理清概念别把两者混为一谈。坏点Dead/Stuck Pixelsensor制造缺陷像素点永远输出固定值全黑或全亮不随光照变化。比如某个像素永远输出409512bit满量程或者永远输出0。这类坏点出厂即存在数量通常很少几十个以内位置固定。热噪点Hot Pixel暗电流过大导致的异常像素。温度每升高10℃暗电流翻倍。在长曝光1秒或高温60℃下这些像素的暗电流积累远超正常像素表现为亮点。热噪点数量随温度、曝光时间动态变化可能从几个到几百个不等。更坑的是有些像素在常温下正常一发热就“冒”出来。工厂检测主要针对坏点热噪点则依赖在线校正。为什么因为热噪点数量多、动态变化工厂全检成本太高而且出厂时环境温度低很多热噪点根本测不出来。二、工厂端坏点检测的“三板斧”产线检测讲究快、准、稳。我们当时用的方案分三步每一步都有血泪教训。第一步暗场抓图盖上镜头盖用遮光布别用手指纹会干扰抓取至少3帧全黑raw图。曝光时间建议设为1/30秒别太长——长曝光会引入热噪点干扰坏点判断。帧数取平均消除随机噪声。这里踩过坑曾经用单帧检测结果把随机热噪声误判为坏点导致良率虚降。后来改成多帧平均误判率从5%降到0.1%。第二步阈值筛选对平均后的暗场图计算每个像素的均值μ和标准差σ。坏点的判定标准是像素值 μ k*σ。k值怎么定经验值对于12bit rawk取6-8。太小了误判多太大了漏检。但别死套公式。不同sensor的暗电流水平差异很大比如索尼IMX系列暗电流通常10e-/s而一些国产sensor可能到50e-/s。所以阈值必须针对每颗sensor标定不能一刀切。第三步位置映射与存储检测到的坏点坐标存入OTPOne-Time Programmable区域。注意坐标必须是sensor原生坐标不能是经过Binning或Cropping后的坐标。否则在线校正时坐标对不上白忙活。存储格式建议用压缩的“游程编码”因为坏点通常成簇出现。我们当时用4字节表示一个坏点2字节行号2字节列号一颗sensor最多存200个坏点OTP空间够用。三、在线校正热噪点的“动态围剿”在线校正不能依赖OTP里的静态坏点表因为热噪点是动态的。我们的方案分两级粗校正和精校正。粗校正基于帧差法的热噪点检测每帧raw图进来先做帧差。具体做法维护一个“参考帧”通常是上一帧的raw数据。当前帧与参考帧逐像素相减差值超过阈值比如50 DN的像素标记为候选热噪点。别这样写直接对当前帧做全局阈值。因为场景中的高亮物体比如灯光也会产生大差值会误判。帧差法的前提是热噪点位置固定而场景内容会移动。所以需要配合运动检测——如果整帧差值都很大说明场景在变化此时跳过热噪点检测。精校正自适应中值滤波检测到热噪点后不能简单用邻域均值替换否则边缘会糊。我们用的是“方向性中值滤波”先判断热噪点所在区域是平坦区还是边缘区。平坦区取3x3邻域的中值简单粗暴。边缘区沿边缘方向取一维中值。比如检测到水平边缘就取左右各2个像素的中值。怎么判断边缘方向用Sobel算子算梯度但别全图算只算热噪点周围的5x5区域计算量可控。温度补偿热噪点数量的“天气预报”热噪点数量与温度强相关。我们在sensor模组里贴了热敏电阻NTC实时读取温度。根据温度动态调整检测阈值温度 40℃阈值设为50 DN只校正最明显的热噪点。40℃ ~ 60℃阈值降到30 DN校正中等强度的热噪点。温度 60℃阈值降到15 DN全面校正。这个策略来自一次惨痛教训某次户外高温测试手机温度飙到65℃热噪点数量从几十个暴涨到上千个阈值没调结果画面全是白点。后来加了温度补偿问题解决。四、代码实现别踩这些坑下面给一段简化版的在线校正代码用C语言风格注释里写了我踩过的坑。// 热噪点检测与校正函数// raw_in: 输入raw图raw_out: 输出raw图width/height: 图像尺寸// temp: 当前温度摄氏度ref_frame: 上一帧raw图voidhot_pixel_correction(uint16_t*raw_in,uint16_t*raw_out,intwidth,intheight,floattemp,uint16_t*ref_frame){// 根据温度动态调整阈值intthreshold;if(temp40.0f){threshold50;// 低温阈值高只校正明显的}elseif(temp60.0f){threshold30;}else{threshold15;// 高温阈值低全面校正}// 遍历每个像素for(inty1;yheight-1;y){// 边界不处理别越界for(intx1;xwidth-1;x){intidxy*widthx;intdiffabs(raw_in[idx]-ref_frame[idx]);// 帧差检测但需要排除场景运动// 这里简化处理如果整帧平均差值大于100认为场景在运动跳过// 实际工程中需要更精细的运动检测if(diffthreshold){// 判断边缘方向// 计算水平梯度|左-右|intgrad_habs(raw_in[idx-1]-raw_in[idx1]);// 计算垂直梯度|上-下|intgrad_vabs(raw_in[idx-width]-raw_in[idxwidth]);uint16_tcorrected;if(grad_hgrad_v){// 水平边缘取左右中值// 别这样写直接取左右均值会模糊边缘// 应该取中值uint16_tneighbors[2]{raw_in[idx-1],raw_in[idx1]};correctedmedian_2(neighbors);// 2元素中值}elseif(grad_vgrad_h){// 垂直边缘取上下中值uint16_tneighbors[2]{raw_in[idx-width],raw_in[idxwidth]};correctedmedian_2(neighbors);}else{// 平坦区取3x3中值// 这里踩过坑直接用冒泡排序取中值太慢// 应该用快速选择算法或者用硬件加速uint16_tneighbors[9];intn0;for(intdy-1;dy1;dy){for(intdx-1;dx1;dx){neighbors[n]raw_in[(ydy)*width(xdx)];}}correctedmedian_9(neighbors);// 9元素中值用快速选择}raw_out[idx]corrected;}else{raw_out[idx]raw_in[idx];// 正常像素直接复制}}}// 更新参考帧memcpy(ref_frame,raw_in,width*height*sizeof(uint16_t));}这段代码有几个关键点边界像素不处理否则数组越界程序直接崩。中值滤波用快速选择算法nth_element别用冒泡排序否则帧率掉一半。运动检测这里简化了实际工程中建议用帧间SSD平方差和或者光流法。五、性能优化别让校正成为瓶颈在线校正如果处理不当会吃掉大量CPU时间。我们的优化策略硬件加速如果ISP有坏点校正硬件模块比如高通平台的BPC模块优先用硬件。硬件处理一帧只需要几十微秒软件要几毫秒。降采样检测不需要全分辨率检测热噪点。可以先把raw图降采样到1/4分辨率比如用双线性插值在低分辨率图上检测热噪点位置再映射回全分辨率校正。这样检测速度提升4倍准确率几乎不变。分时处理热噪点检测不需要每帧都做。可以每5帧检测一次中间帧直接用上一次的坏点表校正。因为热噪点位置变化很慢温度变化才变没必要每帧都算。六、个人经验给后来者的建议工厂检测别省帧数至少3帧平均最好5帧。省帧数省出来的时间最后都会变成产线返工的时间。OTP存储要留余量坏点表空间至少留50%冗余。有些sensor用久了会“冒”出新坏点OTP写满就没办法了。在线校正阈值要保守宁可漏检几个热噪点也别误判正常像素。误判会导致画面出现“脏点”比热噪点更难看。温度传感器别省热敏电阻成本几毛钱但能解决80%的热噪点问题。没有温度反馈的校正方案就像盲人开车。测试用例要覆盖极端场景低温-20℃下坏点可能“消失”高温70℃下热噪点可能“爆发”。这些场景在实验室很难复现但用户会遇到。建议用温箱做全温度范围测试。最后说一句坏点校正没有银弹。每颗sensor都有自己的“脾气”最好的方案是“工厂标定在线自适应”的组合拳。别指望一套参数打天下那只会让你在产线投诉中焦头烂额。

相关新闻