040、深度学习AF:基于CNN的散焦检测与快速对焦策略

发布时间:2026/7/14 16:53:49
040、深度学习AF:基于CNN的散焦检测与快速对焦策略 040、深度学习AF基于CNN的散焦检测与快速对焦策略一、从一次量产线“跑焦”事故说起2019年某款旗舰机量产前夜产线反馈连续拍摄100张有12张对焦不准。传统反差式AF在暗光下反复拉风箱相位AF在低对比度场景下直接“摆烂”。我蹲在产线三天发现一个规律——所有跑焦的样本散焦程度都落在传统算法“盲区”既不是明显模糊传统算法能快速收敛也不是完全失焦算法会放弃而是那种“看起来还行放大就糊”的中间态。当时团队里有人提议“加个CNN试试”我第一反应是“别扯AF要实时CNN跑得动”但实测结果打脸了——MobileNetV2在骁龙855上推理只要3ms而传统反差式AF一次爬山就要20ms。于是我们开始用CNN做散焦检测把AF从“盲人摸象”变成了“一眼看穿”。二、散焦检测的“老办法”为什么不够用传统散焦检测依赖图像梯度。拉普拉斯算子、Sobel算子、Brenner梯度——这些方法在实验室里表现完美一到真实场景就露怯纹理缺失场景白墙、天空、人脸皮肤——梯度几乎为零算法直接“瞎了”运动模糊干扰手抖产生的运动模糊和散焦模糊在频域上高度相似传统算法分不清局部与全局矛盾画面中心清晰、边缘模糊镜头像场弯曲算法不知道该信哪一块我见过最离谱的案例某款手机在拍树叶时因为树叶边缘有高频纹理传统算法判定“已经清晰”实际上焦平面在树叶后面20cm。这就是梯度法的致命缺陷——它只看“有没有边缘”不看“边缘是不是对的”。三、CNN散焦检测从“看边缘”到“看整体”我们最终采用的方案是用轻量级CNN直接回归散焦程度输出一个0~1的置信度分数。0表示完全失焦1表示完美合焦。3.1 网络结构设计踩过坑的版本Input: 64x64灰度图别用RGB计算量翻三倍效果几乎一样 ↓ Conv3x3, 16通道, stride2 → BN ReLU 这里踩过坑不加BN训练发散 ↓ Depthwise Conv3x3, 32通道, stride2 → BN ReLU 别用普通Conv参数量太大 ↓ Global Average Pooling 关键操作把空间信息压缩成全局特征 ↓ FC 64 → FC 1 → Sigmoid 输出散焦分数为什么用Depthwise Conv因为AF推理必须在5ms内完成普通Conv在移动端跑不动。Depthwise Conv把计算量降到1/9效果只差0.5%。为什么用Global Average Pooling传统方法用全连接层直接拍平特征图参数量爆炸。GAP把每个通道的空间信息压缩成一个值既保留全局感受野又防止过拟合。这里有个血泪教训第一次用FCDropout训练集准确率98%测试集直接掉到72%。换成GAP后测试集稳定在89%。3.2 训练数据生成别偷懒自己造真实场景采集散焦数据太贵了。我们用的方法是从合焦图像反向生成取一张完美合焦的图用高斯模糊模拟不同散焦程度。模糊半径从0.5到15像素步长0.5。这里有个坑高斯模糊和真实镜头散焦不完全等价真实散焦有像差、色散、彗差。后来我们加了“随机像差模拟”——在模糊核上叠加随机相位效果提升5%。多尺度裁剪64x64的patch从原图随机位置裁剪保证网络学到不同区域的散焦特征。注意别只裁中心边缘区域的散焦特征和中心完全不同镜头边缘分辨率下降。标签设计不用“合焦/失焦”二分类而是用连续值。我们定义散焦分数 1 - (模糊半径 / 15)。这样网络能学到“轻微散焦”和“严重散焦”的区别对AF的步长选择至关重要。3.3 推理优化移动端部署的骚操作INT8量化FP32模型3.2MB量化后800KB推理速度从5ms降到2.1ms。这里注意Sigmoid层量化后精度损失严重我们把它改成ReLU6 线性映射量化误差从3%降到0.5%。输入预处理别用OpenCV的resize太慢。我们用NEON指令集手写了一个双线性插值64x64的resize只要0.3ms。多帧融合单帧推理有噪声我们取最近3帧的散焦分数做指数移动平均alpha0.7。效果抖动从±0.15降到±0.03。四、快速对焦策略从“爬山”到“一步到位”有了CNN散焦分数AF策略可以完全重构。传统反差式AF是“爬山算法”——来回移动镜头找梯度最大的位置。CNN方案是“直接预测”——输入当前帧输出散焦分数然后根据分数计算镜头应该移动的方向和步长。4.1 步长映射这里有个坑CNN输出的是散焦分数不是物理距离。我们需要一个映射函数散焦分数 → 镜头步进电机步数。我们用的方法是离线标定。在产线上对每个模组从最近对焦距离到无穷远每隔10步拍一张图记录散焦分数。然后拟合一个二次曲线步数 a * (1 - 分数)^2 b * (1 - 分数) c注意这个曲线不是单调的因为镜头在近端和远端的散焦特性不对称。我们分两段拟合分数0.5用一组参数分数≥0.5用另一组。效果对焦时间从平均300ms降到80ms。4.2 方向判断别写死传统方法需要“试探性移动”来判断方向——先往一个方向走一步看散焦分数是变大还是变小。CNN方案可以直接判断如果分数0.3说明严重失焦直接往“分数变化率”最大的方向移动。我们训练了一个辅助网络输入连续两帧的散焦分数和镜头位置输出“应该往哪个方向移动”。这个网络只有3层FC推理时间0.5ms。效果方向判断准确率从85%提升到97%。4.3 收敛条件别用固定阈值传统AF用“梯度变化小于阈值”作为收敛条件。CNN方案用“散焦分数稳定在0.9以上且连续3帧变化小于0.02”。这里有个细节在暗光下散焦分数会有噪声我们把阈值放宽到0.05同时增加帧数到5帧。效果暗光对焦成功率从70%提升到92%。五、实战效果与踩坑记录5.1 量化结果对焦时间传统反差式AF平均300msCNN方案平均80ms包含CNN推理3ms 步进电机移动时间对焦成功率传统方案在低对比度场景下只有65%CNN方案达到93%功耗CNN推理每次约0.5mJ传统AF每次约2mJ因为需要多次移动镜头5.2 踩坑记录过拟合到训练数据第一次训练网络在实验室场景表现完美一到产线就崩。原因训练数据全是高斯模糊真实镜头的散焦有像差。解决方案在模糊核上叠加随机像差同时采集真实散焦数据做fine-tune。温度漂移手机发热后镜头位置会漂移。CNN预测的散焦分数和实际物理位置对不上。解决方案在模组中集成温度传感器根据温度补偿步长映射曲线。运动模糊干扰用户手持拍摄时运动模糊和散焦模糊混在一起。CNN会把运动模糊误判为散焦。解决方案在输入CNN之前先用陀螺仪数据判断是否运动模糊严重如果是则回退到传统相位AF。六、个人经验性建议别迷信端到端我们试过直接让CNN输出镜头步数效果很差。因为CNN对物理系统的非线性映射能力有限。更好的做法是CNN只做散焦检测步长映射用传统方法。数据生成比网络结构更重要我们试过ResNet18、MobileNetV3、EfficientNet-Lite效果差距不超过2%。但数据生成方式模糊核设计、多尺度裁剪、标签平滑能让效果提升10%以上。部署时考虑硬件特性不同芯片的NPU对算子的支持不同。高通Hexagon对Depthwise Conv优化很好联发科APU对普通Conv更友好。别写死网络结构要能根据硬件动态调整。留一手“保底方案”CNN方案再强也有失效的时候比如极端暗光、镜头遮挡。一定要保留传统反差式AF作为fallback。我们设计了一个“置信度门限”如果CNN输出的散焦分数方差大于0.2说明网络不确定回退到传统算法。产线标定不能省每个模组的光学特性都有差异。我们开发了一个自动化标定工具在产线上用机械臂控制镜头移动自动采集散焦分数-步数映射曲线。整个过程只要3秒但让对焦精度提升了15%。最后说一句深度学习AF不是银弹它解决的是传统算法在“中间态”场景下的盲区。如果你的产品只在强光下拍文档传统AF完全够用。但如果你要做暗光人像、运动抓拍、微距特写——CNN方案值得一试。毕竟用户不会在意你用了什么算法他们只关心“按下快门照片是不是清晰的”。