1. 自动对焦概述:对焦原理、评价函数基础、对焦窗口选择策略
自动对焦,说白了就是让镜头自己找到最清晰的那个位置。你想想看,手机拍照时轻轻一点,画面就清楚了——背后其实是一套算法在拼命算“到底哪张图最锐利”。
我刚开始做这个方向时,以为自动对焦就是找个最大值那么简单。结果第一次在户外强光下调试,镜头来回震荡,死活定不住。嗯,从那以后我才真正开始理解:对焦这件事,远比你想象的要复杂。
1.1 对焦原理:从物理到数字
传统相机靠拧镜头来找焦点。数字相机呢?它靠的是图像传感器上的对比度变化。
核心逻辑就一句话:图像越清晰,相邻像素的亮度差异越大。反过来,图像越模糊,像素之间就越“平”。
对焦的本质:在镜头移动范围内,找到使图像“高频信息”最大的那个位置。
我习惯把这个过程拆成三步:
- 移动镜头——步进电机带着镜头从近到远扫一遍
- 计算清晰度——每到一个位置,抓一帧图,算一个分数
- 寻找峰值——分数最高的位置,就是焦点
听起来简单?但实际项目中,噪声、光照变化、运动物体都会让这个“峰值”变得面目全非。我曾经在一个监控项目里,因为风吹树叶的晃动,对焦曲线出现了三个假峰……那周我几乎每天都在看曲线图。
1.2 评价函数基础:怎么算“清晰”
评价函数(Focus Measure)就是用来给图像清晰度打分的。不同的函数,敏感度、计算量、抗噪能力都不一样。
我个人最常用的三类:
| 类别 | 代表算法 | 核心思路 | 我常用的场景 |
|---|---|---|---|
| 梯度类 | Tenengrad、Laplacian、Sobel | 计算图像边缘的强度 | 日常拍照、文档扫描 |
| 频域类 | FFT高频能量、DCT系数 | 分析图像中高频成分多少 | 工业检测、显微镜 |
| 统计类 | 方差、熵、自相关 | 衡量像素值的离散程度 | 低光照、纹理简单场景 |
我的经验:梯度类函数在纹理丰富的场景下表现最好,但遇到纯色墙面就抓瞎。频域类更稳定,但计算量大,移动端扛不住。实际项目中我通常先用梯度类做粗搜,再用频域类做精搜——这叫“粗精结合”。
给你看一段最简单的 Tenengrad 实现:
// 简化版 Tenengrad 评价函数
float tenengrad_score(unsigned char* img, int w, int h) {
float score = 0.0f;
for (int y = 1; y < h-1; y++) {
for (int x = 1; x < w-1; x++) {
// Sobel 水平梯度
int gx = -img[(y-1)*w + (x-1)] + img[(y-1)*w + (x+1)]
-2*img[y*w + (x-1)] + 2*img[y*w + (x+1)]
-img[(y+1)*w + (x-1)] + img[(y+1)*w + (x+1)];
// Sobel 垂直梯度
int gy = -img[(y-1)*w + (x-1)] -2*img[(y-1)*w + x] - img[(y-1)*w + (x+1)]
+img[(y+1)*w + (x-1)] +2*img[(y+1)*w + x] + img[(y+1)*w + (x+1)];
score += sqrtf(gx*gx + gy*gy);
}
}
return score / (w * h);
}
这段代码我用了很多年。核心就是算每个像素的梯度幅值,然后累加取平均。分数越高,图像越清晰。
注意:评价函数对噪声极其敏感。我曾经在一个夜间监控项目里,直接用原始图像算 Tenengrad,结果噪声被当成“清晰度”放大了三倍。后来加了高斯滤波前置处理,曲线才恢复正常。
1.3 对焦窗口选择策略:别算整张图
为什么不能算整张图?两个原因:
- 计算量太大——1080p 图像全算一遍,手机功耗扛不住
- 背景干扰——你只想对焦主体,但背景的纹理可能更丰富,算法会被带偏
所以,我们需要选一个“窗口”,只在这个区域内算清晰度。
我总结了几种常用策略:
| 策略 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 中心固定窗 | 取图像中心 1/3 区域 | 简单、稳定 | 主体不在中心时失效 |
| 多区域加权 | 划分 3x3 或 5x5 网格,中心权重高 | 兼顾中心和边缘 | 参数调起来麻烦 |
| 人脸/主体检测 | 先检测主体,再围绕主体开窗 | 精准、用户体验好 | 依赖检测算法,有延迟 |
| 自适应窗口 | 根据图像内容动态调整窗口大小和位置 | 最灵活 | 实现复杂,容易出 bug |
我的建议:项目初期先用中心固定窗,把对焦曲线调平滑了,再上自适应策略。一上来就搞复杂窗口,出了问题你都不知道是窗口的问题还是评价函数的问题。
我曾经在一个扫码枪项目里,用了中心固定窗。结果用户经常扫条码时,条码在画面边缘,对焦全对到背景上去了。后来改成多区域加权,中心权重 0.5,四角各 0.125,问题就解决了。
1.4 本章知识结构
下面这张图,是我自己梳理的自动对焦基础框架。每次带新人时,我都会先让他们看这张图:
这张图我每次培训都会用。你注意看:对焦不是单一算法,而是“移动-计算-决策”的闭环。任何一个环节出问题,最终焦点都会偏。
调试小技巧:刚开始调试时,先把窗口固定,只调评价函数。等曲线形状对了,再动窗口。一次只改一个变量——这是我踩过无数坑之后总结出来的铁律。
好了,这一章的内容就到这里。对焦原理、评价函数、窗口策略——这三块是后面所有章节的基石。你先把它们吃透,后面讲爬山算法、激光辅助、多摄融合时,才能跟得上。