3. 对焦窗口(Window)策略:固定窗口、多窗口、自适应窗口的配置方法与适用场景
对焦窗口,说白了就是告诉 ISP:「嘿,你就在这片区域里算对比度,别的地方别管。」
我刚开始调 AF 的时候,总觉得窗口越大越好——全图算对比度,信息量多,总该准吧?结果呢?背景里的树叶、天空的云、甚至镜头上的灰尘,全都在干扰对焦。后来我才明白,窗口选不对,算法再牛也白搭。
这一章,咱们就把三种窗口策略掰开揉碎。固定窗口、多窗口、自适应窗口,各自怎么配、什么时候用、坑在哪,我都会结合项目经验讲清楚。
核心观点: 对焦窗口的本质是「信噪比取舍」。窗口越大,信息越全,但噪声也越多;窗口越小,目标越纯,但容易丢失主体。好的窗口策略,就是在两者之间找到平衡点。
3.1 固定窗口:简单可靠,但别乱用
固定窗口,就是预先在 sensor 输出图像上画一个矩形框,AF 算法只在这个框里算对比度。框的位置和大小,在代码里写死,运行时不变。
配置方法:
在 RK 平台的 HAL 层或 3A 库中,通常通过以下参数设置:
// RK AIQ 中固定窗口配置示例
struct rk_af_window {
uint16_t h_offs; // 水平偏移(像素)
uint16_t v_offs; // 垂直偏移(像素)
uint16_t h_size; // 窗口宽度(像素)
uint16_t v_size; // 窗口高度(像素)
};
// 典型配置:画面中央 1/4 区域
rk_af_window fixed_win = {
.h_offs = 640, // 假设全图 1920x1080
.v_offs = 360,
.h_size = 640,
.v_size = 360
};
适用场景:
- 扫码枪/条码识别: 条码通常在画面中央,固定窗口最稳。
- 显微镜/工业检测: 被摄物体位置固定,窗口不需要动。
- 人脸解锁(前置固定焦): 人脸基本在中央,固定窗口够用。
避坑指南: 我曾经在一个行车记录仪项目里用了固定窗口,结果车子转弯时,主体跑到窗口外面去了,AF 直接对着背景的蓝天对焦,画面糊得一塌糊涂。后来我加了一个「窗口跟随陀螺仪」的补偿逻辑才解决。固定窗口只适合主体位置基本不变的应用,千万别在运动场景里硬用。
3.2 多窗口:多点探测,取最优
多窗口策略,就是在画面里放多个固定窗口,每个窗口独立算对比度,最后选对比度最高的那个窗口作为对焦依据。或者,也可以对多个窗口的对比度做加权融合。
配置方法:
RK 平台支持最多 9 个窗口(不同芯片略有差异)。配置时要注意窗口不能重叠,否则算力浪费。
// RK AIQ 多窗口配置示例
#define MAX_AF_WINDOWS 5
rk_af_window multi_wins[MAX_AF_WINDOWS] = {
{ .h_offs = 400, .v_offs = 200, .h_size = 300, .v_size = 300 }, // 左上
{ .h_offs = 1200, .v_offs = 200, .h_size = 300, .v_size = 300 }, // 右上
{ .h_offs = 400, .v_offs = 600, .h_size = 300, .v_size = 300 }, // 左下
{ .h_offs = 1200, .v_offs = 600, .h_size = 300, .v_size = 300 }, // 右下
{ .h_offs = 760, .v_offs = 400, .h_size = 400, .v_size = 280 } // 中央
};
// 选择策略:取对比度最高的窗口
uint8_t select_best_window(uint32_t *contrast_values, uint8_t num_wins) {
uint8_t best_idx = 0;
for (uint8_t i = 1; i < num_wins; i++) {
if (contrast_values[i] > contrast_values[best_idx]) {
best_idx = i;
}
}
return best_idx;
}
适用场景:
- 安防监控(固定枪机): 画面里可能出现多个移动目标,多窗口能覆盖不同区域。
- 视频会议: 人物可能在画面左侧或右侧,多窗口能自动切换到有人的区域。
- 无人机航拍: 地面景物复杂,多窗口可以避免被单一高对比区域误导。
我的经验: 多窗口的「窗口间距」很关键。我试过把窗口排得太密,结果相邻窗口的对比度曲线几乎一样,等于白算。一般建议窗口之间至少留 10% 画面宽度的间隔。另外,窗口数量不是越多越好——5 个窗口基本够用,再多的话,算力开销上去了,收益却递减。
3.3 自适应窗口:动态跟随,智能裁剪
自适应窗口,就是窗口的位置和大小会随着画面内容变化。最常见的方式是配合人脸检测、物体跟踪或者显著性检测,实时调整窗口。
实现思路:
- 检测阶段: 用 NPU 或 CPU 跑目标检测(人脸、人形、宠物等),得到目标框。
- 映射阶段: 把目标框从检测坐标映射到 AF 窗口坐标(注意缩放和边界裁剪)。
- 平滑阶段: 窗口位置做低通滤波,防止帧间抖动。
- 回退策略: 如果检测丢失,回退到固定窗口或全图窗口。
// 自适应窗口平滑更新示例
typedef struct {
int32_t x, y, w, h; // 当前窗口
float alpha; // 平滑系数 (0.0 ~ 1.0)
} adaptive_window_t;
void update_adaptive_window(adaptive_window_t *win,
int32_t det_x, int32_t det_y,
int32_t det_w, int32_t det_h) {
// 一阶低通滤波,防止窗口突变
win->x = (int32_t)(win->alpha * win->x + (1 - win->alpha) * det_x);
win->y = (int32_t)(win->alpha * win->y + (1 - win->alpha) * det_y);
win->w = (int32_t)(win->alpha * win->w + (1 - win->alpha) * det_w);
win->h = (int32_t)(win->alpha * win->h + (1 - win->alpha) * det_h);
// 边界裁剪,防止窗口超出画面
win->x = CLAMP(win->x, 0, IMAGE_WIDTH - win->w);
win->y = CLAMP(win->y, 0, IMAGE_HEIGHT - win->h);
}
适用场景:
- 手机拍照/录像: 人脸或物体在画面里移动,窗口必须跟着走。
- 智能家居摄像头: 宠物满屋跑,自适应窗口能始终锁定它。
- 运动相机: 用户自拍时,人脸在画面里晃来晃去,固定窗口根本没法用。
注意: 自适应窗口的「回退策略」一定要做好。我遇到过一个问题:人脸检测偶尔漏检一帧,窗口直接跳回中央,AF 马达跟着猛拉一下,画面出现明显的「呼吸效应」。后来我加了检测置信度阈值和窗口位置保持逻辑——检测置信度低于 0.5 时,窗口保持上一帧位置不动,而不是立刻回退。
3.4 三种策略对比
| 策略 | 实现复杂度 | 算力开销 | 场景适应性 | 典型延迟 |
|---|---|---|---|---|
| 固定窗口 | 低 | 低 | 差(仅适合固定场景) | < 1ms |
| 多窗口 | 中 | 中 | 中(可覆盖多个区域) | 1~3ms |
| 自适应窗口 | 高 | 高(需配合检测) | 强(动态跟随主体) | 5~15ms(含检测) |
你想想看,如果场景固定,用自适应窗口就是杀鸡用牛刀;反过来,如果主体满屏跑,用固定窗口就是刻舟求剑。选哪种,得看你的产品定义。
3.5 窗口策略的进阶技巧
在实际项目中,我经常把三种策略组合起来用。举个例子:
- 混合策略: 自适应窗口为主,多窗口为辅。当自适应窗口的检测置信度低时,用多窗口投票结果做补充。
- 窗口权重动态调整: 根据场景亮度调整窗口权重。暗光下,中央窗口权重提高(因为边缘画质下降);亮光下,边缘窗口权重提高(因为细节更丰富)。
- 窗口尺寸自适应: 检测到人脸大(近景),窗口缩小;人脸小(远景),窗口放大。这样可以避免窗口包含太多背景。
一个实用技巧: 在 RK 平台上,AF 窗口的尺寸最好是 16 像素对齐。因为 ISP 内部的对比度计算模块通常以 16x16 块为单位处理。窗口不对齐的话,边缘块会被截断,导致对比度计算偏差。我踩过这个坑,后来在配置窗口时加了对齐宏:
#define ALIGN_16(x) (((x) + 15) & ~15)
3.6 本章知识结构
下面这张图,把三种窗口策略的核心逻辑和适用场景串起来了。你可以把它当作选型参考。
我的建议: 如果你刚开始调 AF,先从固定窗口入手,把对比度曲线调顺了,再切换到多窗口或自适应窗口。别一上来就搞复杂的策略——基础没打好,上层再花哨也是空中楼阁。我在 RK3588 上一个项目就是这么干的,先固定窗口调了三天,确认曲线没问题后,才加的人脸检测自适应窗口,整个流程稳得很。