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系统中,我们可以用它来评估评价函数区分“合焦”和“离焦”的能力。
具体做法是:
- 设定一个阈值T。如果评价函数值大于T,判定为“合焦”;否则判定为“离焦”。
- 改变T的值,计算每个T下的真阳性率(TPR)和假阳性率(FPR)。
- 以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曲线的步骤其实不复杂:
- 准备测试数据集:包含大量合焦和离焦的图像,以及对应的评价函数值。
- 对评价函数值进行排序。
- 从最小值到最大值,依次作为阈值T。
- 对每个T,计算TPR和FPR。
- 以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 知识体系总览
为了让你更直观地理解这一章的知识结构,我画了一张图:
4.4 综合评估流程
在实际项目中,我不会只看单一指标。我总结了一套综合评估流程,分享给你:
- 初筛:用AUC快速过滤。AUC < 0.85的直接淘汰。
- 复杂度评估:在目标硬件上实测计算时间。超过帧率预算的淘汰。
- 单调性测试:在典型场景(纹理、光照、运动)下测试MR。MR < 0.85的淘汰。
- 无偏性测试:在不同场景下测试σ_offset。σ_offset超过阈值的淘汰。
- 灵敏度微调:对通过前四轮的候选函数,用峰值陡度做最终排序。
小建议:如果你时间有限,可以只做前三步。AUC、计算复杂度和单调性,这三个指标基本能覆盖90%的场景。无偏性和灵敏度,可以在后续优化阶段再深入。