# 一张大合影里有几张脸 # 智绘鸿蒙·如 7 而至#

## 前言

需求表述为"统计合影人数"，但这句话里有两个未定义项：**"一张脸"的判定条件是什么**，以及**"人数"是否等于检测框数量**。工程上必须先固定这两项，否则任何准确率数字都没有意义。

本文用 Core Vision Kit 的 `faceDetector` 做一组可控实验，把这组问题量化。实验对象是一张**合成**合影——人脸数量、位置、尺寸全部由构造过程给定，因此真值（ground truth）是先验确定的，不存在人工标注带来的误差。

主要结论有三条：其一，返回框描述的是面部区域而非头部区域，宽度约为贴入人脸图块边长的 0.40 倍；其二，存在一个尺寸阈值，落在检出框宽 44~52 像素之间；其三，姿态角 `rollAngle` 不能用于判定人脸是否倒置。

## 1 实验对象与符号定义

图像尺寸 1600×1000 像素。以 3 张底片（记为 a、b、c）裁取正方形人脸图块后贴入，共 13 个图块。每个图块记作 T_i=(x_i, y_i, s_i)，其中 s_i 为贴入边长（像素）。同一底片重复使用，因为本实验只考察**检测**而非**识别**，重复底片不影响计数真值。

13 个图块按条件分为三组：

| 组别 | 成员 | 考察变量 |
| --- | --- | --- |
| 基准组 | normal-a/b/c/a2，边长 230~270 | 无扰动 |
| 边界组 | edge-cut（右侧越界 30 像素）、second-row（第二排） | 出画与排布 |
| 姿态组 | inverted（贴入前旋转 180°） | 倒置 |
| 阶梯组 | size-180/150/130/110/90/70 | 尺寸单调下降 |

检测记作 \hat{F} = \{(\text{rect}_j, \text{pose}_j, \text{prob}_j)\}，其中 \text{rect}_j=(l,t,w,h)。

## 2 方法与判据

调用形式：

```typescript
await faceDetector.init();
const faces: faceDetector.Face[] = await faceDetector.detect({ pixelMap: pm });
```

`Face` 的字段是 `rect`、`pose`、`probability`、`points`、`block?`。注意**没有** `confidenceThreshold` 一类可调入参，也没有返回置信度阈值相关信息，因此本实验无法通过调参改变灵敏度。

**匹配规则**：对每个 T_i 取其中心 c_i，在未被占用的检测结果中选中心曼哈顿距离最小者配对，一对一占用。距离无上限约束——这意味着"错误配对"是可能的，因此下表同时报告中心偏差，偏差过大的命中应视为可疑。

**三项指标**：命中数（配到检测框的图块数）、漏检数、多余检测数（未被任何图块占用的检测框数）。

## 3 结果

单次运行，MatePad Pro（HarmonyOS 7 / API 26）：

```
贴入 13 · 检出 10 · 多余 0 · 267ms
```

| 图块 | 贴入边长 | 判定 | 检出框 (l,t,w,h) | 中心偏差 | pose (P/R/Y) |
| --- | --- | --- | --- | --- | --- |
| normal-a | 260 | 命中 | 176,232,108,160 | 0, 2 | 11 / 2 / 4 |
| normal-b | 240 | 命中 | 492,247,88,125 | −4, −10 | 13 / 2 / 2 |
| normal-c | 270 | 命中 | 816,222,112,162 | −3, −2 | 11 / 4 / 1 |
| normal-a2 | 230 | 命中 | 1124,257,96,135 | −3, 0 | 10 / 3 / 2 |
| edge-cut | 250 | 命中 | 1456,242,88,127 | 10, −9 | 13 / 2 / 0 |
| second-row | 200 | 命中 | 452,657,88,122 | −4, −2 | 11 / 3 / 2 |
| inverted | 180 | 命中 | 948,672,80,100 | 0, −6 | **10 / 17 / −1** |
| size-180 | 180 | 命中 | — | −4, −8 | 12 / 3 / 2 |
| size-150 | 150 | 命中 | — | −3, 0 | 11 / 6 / −1 |
| size-130 | 130 | 命中 | 464,837,52,70 | −5, −3 | 15 / 7 / −6 |
| size-110 | 110 | **漏检** | — | — | — |
| size-90 | 90 | **漏检** | — | — | — |
| size-70 | 70 | **漏检** | — | — | — |

## 4 讨论

### 4.1 检出框描述的是面部，不是头部

比值 w/s 在各图块上高度一致：108/260=0.415、88/240=0.367、112/270=0.415、96/230=0.417、88/200=0.440、52/130=0.400。均值约 **0.41**，且 h/w \approx 1.45，明显是一个纵向拉伸的矩形。

工程含义：若把 `rect` 当作"人头所在区域"去做裁剪或打码，会**漏掉头发、耳朵和下巴**。做隐私打码时建议按 0.41 反推头部尺度，例如横向扩到贴入图块的 0.75 倍、纵向上移 0.35 倍再画框。本实验未直接验证打码覆盖率，这一步需要真实照片复核。

### 4.2 尺寸阈值

单调性成立：130 及以上全部命中，110 及以下全部漏检，中间没有抖动。

按 4.1 的比例关系，s=130 对应检出框宽 52 像素，s=110 对应约 44 像素。因此**以检出框宽度计，阈值落在 44~52 像素之间**。需要强调这是推算：s=110 时模型根本没有返回框，无法直接观察其应有宽度。若要精确定位，应在 110~130 之间以 5 像素步长补测。

换算到真实场景：一张 4000×3000 的合影，人物面部通常占 150~400 像素，全部在阈值之上；但如果先把图缩到 1080 宽再送检，面部可能落到 40~100 像素，**接近或低于阈值**。这解释了"原图能数对、缩图就少人"的常见现象，也意味着：宁可多花一次检测时间，也不要先降分辨率。

### 4.3 姿态角的解释边界

倒置图块（贴入前旋转 180°）被正常检出，其 `pose` 为 pitch=10、**roll=17**、yaw=−1，而正立图块的 roll 在 2~7 之间。

也就是说：模型确实感知到了异常（roll 从个位数升到 17），但**没有把 180° 报成 180°**。若按"roll 接近 180 即为倒置"写判据，会完全失效。合理解释是该角度定义在有界区间内（各正立样本 roll 均为小正数，无法据此区分是 [−90,90] 还是 [0,180]），但本实验样本不足以确定其定义域，只能得出一个可执行的结论：**`rollAngle` 可用作"姿态异常"的弱信号，不可用作朝向的度量。**

### 4.4 计数场景可以直接用框数

本次多余检测数为 0，即没有出现把背景纹理、肩膀、重复底片误判为额外人脸的情况。对"数人数"这个具体需求，`faces.length` 在尺寸达标时是可靠统计量，不需要额外的非极大值抑制或去重逻辑。

## 5 内部效度

必须交代本实验不能外推的部分：

1. 图像是合成的，人脸来自 3 张底片的重复贴入，背景是程序生成的斜纹，**不存在真实合影中的相互遮挡、侧脸、逆光与景深虚化**。真实照片的漏检率只会更高。
2. 底片是正脸证件照，姿态极小；阶梯组因此测到的是"干净正脸"的阈值，不是普通场景的阈值。
3. 每个条件只测一次，未评估同一张图的重复稳定性。
4. 阈值区间由比例推算得到，不是直接观测。

## 真机数据

| 项目 | 实测值 |
| --- | --- |
| 设备 | MatePad Pro（HarmonyOS 7 / API 26，序列号略） |
| 图像 | 1600×1000，贴入 13 个人脸图块 |
| 检出 / 漏检 / 误检 | 10 / 3 / 0 |
| 检测耗时 | 267ms（含 `init` 的首次运行另计） |
| 检出框宽 / 贴入边长 | 0.367 ~ 0.440，均值约 0.41 |
| 中心偏差 | |dx| ≤ 10 像素，|dy| ≤ 10 像素 |
| 尺寸阈值 | 贴入 130 命中、110 漏检；按框宽计约 44~52 像素 |

![逐图块判定结果，命中行给出检出框与中心偏差](assets/01-top.png)

![尺寸阶梯：130 命中，110 起连续三档漏检](assets/02-ladder.png)

## 总结

这套能力适合"人数下限估计 + 人脸定位"类需求：合影自动裁剪、会议签到人数核对、相册按人脸聚类的前置定位、直播连麦人数提示。它给的是框和姿态，不给身份，因此凡是涉及"是谁"的需求，还要叠加 `faceComparator`。

不适合精确计数。真实合影里的相互遮挡会直接压低召回，而接口不提供任何灵敏度旋钮，你无法用调参换回漏掉的人。人数敏感的场景（比如按人头计费）应当把检测结果当作下限，再让人工确认。

> 💡 **一句话**：`faceDetector` 的框只覆盖面部（约为头部图块宽度的 0.41 倍），且贴入边长低于约 110 像素就会整张漏检——数人之前，先别缩图。

## 参考文献

1. 人脸检测（开发指南）：https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/core-vision-face-detector
2. faceDetector（人脸检测）API 参考：https://developer.huawei.com/consumer/cn/doc/harmonyos-references/core-vision-face-detector-api
3. Core Vision Kit 简介：https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/core-vision-introduction
4. Core Vision Kit 错误码：https://developer.huawei.com/consumer/cn/doc/harmonyos-references/errorcode-core-vision
