人脸检测引擎技术架构(2026-07)

重要变更(2026-07-05):NCNN 路径已按激进策略完全移除。当前仅保留 MEDIAPIPEMNN 双引擎,代码、模型配置、设置选项、so 库及 runtime 依赖中均不再包含 NCNN。

1. 概述

PicMe 当前采用双引擎人脸检测架构:MEDIAPIPEMNN

零拷贝优化(2026-06 新增,2026-07 调整为 MNN 独占): - MediaPipe Image 路径:CameraX ImageProxyMPImage,跳过 YUV→ARGB 转换,节省约 5ms - MNN NV21 路径:DirectByteBuffer → C++ 层一体式预处理+推理,跳过 Bitmap→RGB 转换(约 3-5ms)

并发优化(2026-06):MNN ROI/Landmark 检测器初始化从阻塞 synchronized 切换为非阻塞 AtomicBoolean CAS 模式,重型模型加载从 ResourceManager 回调中延迟到下一次 detect 调用,避免阻塞渲染线程。

架构目标:

2. 代码落点(当前实现)

2.1 对外契约层

beauty-api/src/main/java/com/mamba/picme/beauty/api/facedetect/

2.2 内部实现层

beauty-engine/src/main/java/com/mamba/picme/beauty/internal/facedetect/

2.3 C++ 原生层

beauty-engine/src/main/cpp/

2.4 App 集成层

3. 运行流程

3.1 预览实时检测(双路径)

路径 A:MediaPipe Image 零拷贝(首选,~5ms 节省)

CameraX ImageProxy
  -> FaceDetectorManager.detectFromImage(image, rotation, lensFacing)
     (跳过 YUV→ARGB CPU 转换)
  -> MediaPipeFaceDetector.detect(mediaImage: Image, ...)
     (MediaImageBuilder 包装为 MPImage,C++ 层原生消费 YUV)
  -> MediaPipe468Adapter:468 -> 106
  -> Face106ToWarpParams.convert()
  -> BeautyRenderer 使用 FaceWarpParams

路径 B:MNN NV21 零拷贝(ROI + Landmark 双阶段)

CameraX ImageProxy
  -> FaceDetectorManager.detectRoiFromNv21(yuvData, width, height, ...)
     (DirectByteBuffer 零拷贝 → MNN C++ 层)
  -> MnnRoiDetector.detectRoiFromYuv(): letterbox → 原图坐标逆映射
  -> FaceDetectorManager.detectLandmarksFromNv21WithRoi()(基于 ROI 裁剪区域)
  -> MnnLandmarkAdapter:106 点重排
  -> Face106ToWarpParams.convert()
  -> BeautyRenderer 使用 FaceWarpParams

路径 C:Bitmap 降级路径(Legacy)

CameraX ImageProxy
  -> 转 Bitmap(YUV→ARGB CPU 转换)
  -> FaceDetectorManager.detect(bitmap, rotation, lensFacing)
      -> 按 EngineType 分流
         - MEDIAPIPE: MediaPipeFaceDetector.detect(bitmap)
         - MNN: RoiDetector.detectRoi() + LandmarkDetector.detectLandmarks()
      -> 通过 Adapter 统一到 106 点
  -> Face106ToWarpParams.convert()
  -> BeautyRenderer 使用 FaceWarpParams

3.2 静态图检测(拍照后)

FaceDetector.detectPhoto(bitmap, lensFacing) 当前实现按配置走 MediaPipeLandmarkDetector 或 MNN 完整检测管线。

说明:静态图链路不会走 FaceDetectorManagerEngineType 分支。detectFromImage()detectRoiFromNv21() 零拷贝路径目前仅用于预览实时检测。

4. 引擎与流水线配置

4.1 引擎选择(EngineType)

NCNN 枚举值与相关实现已于 2026-07-05 完全移除。

4.2 MNN 流水线组合(DetectionPipelineConfig)

⚠️ 审计备注(2026-07):原 InsightFace ONNX 路径与 NCNN 路径均已移除。当前仅 MNN 备选引擎使用独立 ROI+Landmark 配置。

ROI 检测器:

Landmark 检测器:

5. 关键映射与坐标约束

5.1 MediaPipe 468 -> 统一 106

MediaPipe468Adapter 实现:

参考:docs/03-TECHNICAL-SPECS/FACE_LANDMARKS.md

5.2 MNN 原生 106 -> 统一 106

MnnLandmarkAdapter 实现:使用 FULL_REMAP 对 106 点完整重排。不存在 index -> same index 直通点。前置镜头:x = 1 - x

⚠️ 已移除(2026-07):原 NcnnLandmarkAdapter.ktNcnnRoiDetector.ktNcnnLandmarkDetector.ktncnn/NcnnFaceDetector.kt 及 C++ NCNN 实现均已删除。

6. 当前行为边界(避免文档误读)

6.1 当前没有检测引擎自动冷却回退状态机

FaceDetectorManager 当前行为是:

6.2 当前有以下降级行为

7. 性能相关实现点与优化

7.1 零拷贝优化(2026-06 新增,2026-07 调整为 MNN 独占)

优化项 实现方式 预期收益
MediaPipe Image 路径 CameraX ImageProxyMediaImageBuilderMPImage 跳过 YUV→ARGB 转换(约 5ms)
MNN NV21 路径 CameraX DirectByteBuffer → C++ 预处理+推理 跳过 Bitmap→RGB 拷贝(约 3-5ms)
C++ 一体式预处理 BT.601 颜色转换 + 双线性缩放 + letterbox + 归一化 减少 CPU 端多次数据搬运

7.2 MNN 并发初始化优化(2026-06)

优化项 旧行为 新行为
懒加载同步方式 synchronized 阻塞调用线程 AtomicBoolean CAS 非阻塞,初始中进行中跳过本帧
重型模型加载时机 ResourceManager.onLoad() 回调中同步执行(约 1s+) 回调中仅重置标记,推迟到下一次 detect() 调用
线程行为 初始化进行中时其他线程被阻塞等待 其他线程立即返回 false,跳过本帧不阻塞渲染

7.3 Perf 日志体系

8. 相关文档

9. 零拷贝路径选择策略(2026-07)

FaceDetectorManager 按以下优先级选择检测路径:

  1. 若配置为 MediaPipe 统一管线 → 走 detectFromImage()(MediaPipe Image 零拷贝)
  2. 若配置 MNN ROI + Landmark 组合 → 走 detectRoiFromNv21()(MNN NV21 零拷贝 ROI → NV21 Landmark)
  3. Bitmap 降级(仅当零拷贝路径不可用时)

文档版本: v4.0 (2026-07-05) 维护者: RD Team
说明: 本文档已按 2026-07 NCNN 移除重构更新。当前架构为 MediaPipe/MNN 双引擎。