4. 评价函数性能评估:准确性、单调性、无偏性、灵敏度、计算复杂度

评价函数(也叫对焦评价函数、清晰度评价函数)是整个AF系统的“眼睛”。你想想看,如果眼睛看东西都是花的,那后面的搜索算法再快也没用。所以,怎么科学地评价一个评价函数好不好,是我们做AF算法首先要解决的问题。

我入行那会儿,踩过一个坑:选了一个计算量很小的评价函数,跑起来飞快,但实际拍照时经常对不准。后来才明白,评价函数的性能评估,不能只看“快不快”,得从多个维度去衡量。

这一章,我们就来拆解评价函数的五个核心指标:准确性、单调性、无偏性、灵敏度、计算复杂度。最后再聊聊怎么用ROC曲线与AUC做综合评估。

4.1 五个核心指标详解

这五个指标,说白了就是回答五个问题:

  • 准确性:它找到的峰值,是不是真正的合焦位置?
  • 单调性:从离焦到合焦,曲线是不是一路向上,没有“假峰”?
  • 无偏性:峰值位置会不会因为场景变化而偏移?
  • 灵敏度:在合焦点附近,曲线变化够不够陡?
  • 计算复杂度:算一次评价函数,要花多少时间?

下面我们逐个来看。

4.1.1 准确性(Accuracy)

准确性是最直观的指标。它衡量的是:评价函数计算出的最佳对焦位置,与真实合焦位置之间的偏差。

我习惯用均方根误差(RMSE)来量化这个偏差:

RMSE = sqrt( (1/N) * Σ (p_pred_i - p_true_i)^2 )

其中,p_pred_i是算法预测的峰值位置,p_true_i是实际合焦位置(通常用高精度标定或人工确认得到)。

经验之谈:在实际项目中,我一般要求RMSE小于1个步长(比如步进电机的一个微步)。如果超过2个步长,这个评价函数基本就不能用了。

4.1.2 单调性(Monotonicity)

单调性描述的是:从远离合焦点到接近合焦点的过程中,评价函数值是否单调递增(或递减)。

如果曲线有多个峰值(多峰性),AF算法很容易陷入局部最优,导致对焦失败。我遇到过最头疼的情况是:在拍摄带有规则纹理(比如百叶窗、栅栏)的场景时,评价函数会出现周期性假峰。

衡量单调性的常用指标是单调性比率(MR):

MR = (单调递增的区间长度) / (总区间长度)

MR越接近1,说明单调性越好。我个人建议,MR至少要大于0.85,才能保证搜索算法的稳定性。

避坑指南:我曾经在一个项目中,只看了准确性指标,忽略了单调性。结果在拍摄金属网格时,AF系统反复在假峰附近震荡,就是找不到真正的合焦点。后来加了一个单调性预检,才解决了这个问题。

4.1.3 无偏性(Unbiasedness)

无偏性关注的是:评价函数的峰值位置,会不会因为图像内容(如亮度、对比度、颜色)的变化而发生偏移。

一个理想的评价函数,应该只对“清晰度”敏感,而对其他因素不敏感。但实际上,很多评价函数都有偏。比如,基于梯度的评价函数,在低光照条件下,峰值位置可能会向某个方向漂移。

我通常用偏移量标准差(σ_offset)来评估无偏性:

σ_offset = std( p_pred_i - p_true_i )

σ_offset越小,说明评价函数越稳定,无偏性越好。

场景类型 理想偏移量(像素) 可接受偏移量(像素)
高对比度纹理 0 ≤ 1
低对比度纹理 0 ≤ 2
重复纹理 0 ≤ 3
低光照 0 ≤ 2

4.1.4 灵敏度(Sensitivity)

灵敏度描述的是:在合焦点附近,评价函数值随镜头位置变化的剧烈程度。

灵敏度越高,AF系统对微小离焦的响应越敏感,对焦精度也就越高。我常用峰值陡度(Peak Sharpness)来量化:

Peak Sharpness = (F_peak - F_neighbor) / Δstep

其中,F_peak是峰值处的评价函数值,F_neighbor是相邻位置的值,Δstep是步长。

小技巧:如果灵敏度不够,可以考虑在合焦点附近做亚像素插值。我常用的方法是抛物线拟合,用峰值点及其左右两个点的值,拟合出一条抛物线,然后取抛物线的顶点作为精确峰值位置。这样可以把精度从像素级提升到亚像素级。

4.1.5 计算复杂度(Computational Complexity)

计算复杂度直接决定了评价函数能不能在实时系统中跑起来。我一般从两个维度来衡量:

  • 时间复杂度:处理一帧图像需要多少时间(ms)。
  • 空间复杂度:需要多少额外的内存(KB)。

下面是一个常见的评价函数计算复杂度对比:

评价函数 时间复杂度(相对值) 空间复杂度 适用场景
Tenengrad(梯度) 高 低 高精度对焦
Laplacian(拉普拉斯) 中 低 通用场景
Brenner(梯度) 低 低 实时系统
方差(Variance) 低 低 简单场景
FFT(频域) 非常高 高 离线分析

嗯,这里要注意:时间复杂度低的不一定好,关键要看你的硬件平台和帧率要求。我在一个嵌入式项目里,CPU主频只有200MHz,最后选了Brenner函数,因为它只需要做水平方向的差分运算,计算量极小。

4.2 ROC曲线与AUC指标

前面五个指标是从不同角度单独评估的。但实际应用中,我们需要一个综合性的评估方法。ROC曲线和AUC就是干这个的。

4.2.1 什么是ROC曲线?

ROC(Receiver Operating Characteristic)曲线,最初是用于雷达信号检测的。在AF系统中,我们可以用它来评估评价函数区分“合焦”和“离焦”的能力。

具体做法是:

  1. 设定一个阈值T。如果评价函数值大于T,判定为“合焦”;否则判定为“离焦”。
  2. 改变T的值,计算每个T下的真阳性率(TPR)和假阳性率(FPR)。
  3. 以FPR为横轴,TPR为纵轴,画出曲线。

TPR和FPR的定义如下:

TPR = TP / (TP + FN)   // 真正例率,也叫召回率
FPR = FP / (FP + TN)   // 假正例率

其中:

  • TP:正确判定为合焦的样本数
  • FN:漏判的合焦样本数
  • FP:误判为合焦的离焦样本数
  • TN:正确判定为离焦的样本数

4.2.2 AUC:曲线下的面积

AUC(Area Under the Curve)就是ROC曲线下的面积。它的取值范围是0.5到1.0。

  • AUC = 0.5:相当于随机猜测,评价函数没有区分能力。
  • AUC = 1.0:完美区分,所有合焦和离焦样本都能正确分开。
  • AUC > 0.9:一般认为评价函数有很高的实用价值。

我的经验:在项目选型时,我会先看AUC。如果AUC低于0.85,这个评价函数基本就不考虑了。AUC在0.85-0.95之间的,可以进入下一轮筛选。AUC大于0.95的,再结合计算复杂度和灵敏度做最终决策。

4.2.3 如何生成ROC曲线?

生成ROC曲线的步骤其实不复杂:

  1. 准备测试数据集:包含大量合焦和离焦的图像,以及对应的评价函数值。
  2. 对评价函数值进行排序。
  3. 从最小值到最大值,依次作为阈值T。
  4. 对每个T,计算TPR和FPR。
  5. 以FPR为x轴,TPR为y轴,绘制曲线。

下面是一个简单的Python伪代码示例:

def compute_roc(scores, labels):
    # scores: 评价函数值列表
    # labels: 真实标签,1表示合焦,0表示离焦
    thresholds = sorted(set(scores))
    tpr_list = []
    fpr_list = []
    for t in thresholds:
        tp = sum((s >= t) and (l == 1) for s, l in zip(scores, labels))
        fp = sum((s >= t) and (l == 0) for s, l in zip(scores, labels))
        fn = sum((s < t) and (l == 1) for s, l in zip(scores, labels))
        tn = sum((s < t) and (l == 0) for s, l in zip(scores, labels))
        tpr = tp / (tp + fn) if (tp + fn) > 0 else 0
        fpr = fp / (fp + tn) if (fp + tn) > 0 else 0
        tpr_list.append(tpr)
        fpr_list.append(fpr)
    return fpr_list, tpr_list

4.3 知识体系总览

为了让你更直观地理解这一章的知识结构,我画了一张图:

评价函数性能评估知识体系 评价函数性能评估知识体系 评价函数性能评估 准确性 单调性 无偏性 灵敏度 计算复杂度 综合评估方法 ROC曲线 AUC指标 五个核心指标 + ROC/AUC = 完整的评价函数评估体系 选型时:先看AUC,再看计算复杂度,最后用灵敏度做微调

4.4 综合评估流程

在实际项目中,我不会只看单一指标。我总结了一套综合评估流程,分享给你:

  1. 初筛:用AUC快速过滤。AUC < 0.85的直接淘汰。
  2. 复杂度评估:在目标硬件上实测计算时间。超过帧率预算的淘汰。
  3. 单调性测试:在典型场景(纹理、光照、运动)下测试MR。MR < 0.85的淘汰。
  4. 无偏性测试:在不同场景下测试σ_offset。σ_offset超过阈值的淘汰。
  5. 灵敏度微调:对通过前四轮的候选函数,用峰值陡度做最终排序。

小建议:如果你时间有限,可以只做前三步。AUC、计算复杂度和单调性,这三个指标基本能覆盖90%的场景。无偏性和灵敏度,可以在后续优化阶段再深入。