news 2026/9/10 21:22:18

MediaPipe Face Detection 实战指南:基于 BlazeFace 的超快多脸检测解决方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MediaPipe Face Detection 实战指南:基于 BlazeFace 的超快多脸检测解决方案

MediaPipe Face Detection 实战指南:基于 BlazeFace 的超快多脸检测解决方案

【免费下载链接】mediapipeCross-platform, customizable ML solutions for live and streaming media.项目地址: https://gitcode.com/GitHub_Trending/med/mediapipe

本篇技术指南围绕 MediaPipe 官方文档中的人脸检测(Face Detection)解决方案展开,详细介绍其基于 BlazeFace 的模型原理、短距/全距双模型选择机制、跨平台 API(Python / JavaScript / Android)配置参数与完整调用示例,并结合本仓库中的源码(face_detection.py、face_detection.proto、face_detection_mobile_gpu.pbtxt)深入讲解其底层图结构与选项字段的语义。读完你将掌握如何在一台设备的摄像头画面中实时输出多张人脸框与 6 个关键点,并将其作为人脸网格(Face Mesh)、表情分类、人脸区域分割等其他任务的前置"兴趣区域"输入。

说明:本仓库中该文档属于MediaPipe Legacy Solutions系列。官方文档标注,自2023 年 5 月 10 日起该能力已升级为新一代 MediaPipe Solution(Vision 的 Face Detector)。本文介绍的是本仓库快照中遗留的 Python/JavaScript/Android Solution API 与底层 Calculator 图,其架构与参数思想在新旧两代方案中是一脉相承的。


一、解决方案概览:为什么用 BlazeFace 做人脸检测

MediaPipe Face Detection 是一个超快的人脸检测方案,具备两个核心特点:

  1. 6 个关键点(6 landmarks)输出,而非仅输出检测框;
  2. 多脸支持(multi-face support),单帧可检测多个人脸。

检测器底层基于 BlazeFace(论文题为BlazeFace: Sub-millisecond Neural Face Detection on Mobile GPUs)——一个专为移动端 GPU 推理量身定制的轻量级高性能人脸检测器。其超实时(super-realtime)的性能使得它可以应用于任何实时取景器(live viewfinder)体验:只要某个下游任务需要"精确的人脸兴趣区域(ROI)"作为输入,Face Detection 就可以作为第一级检测器来提供,典型下游应用包括:

  • 3D 人脸关键点估计,如 MediaPipe Face Mesh;
  • 人脸特征 / 表情分类;
  • 人脸区域分割(face region segmentation)。

BlazeFace 的网络设计有三个关键点(这也是它在移动端能跑出超实时速度的原因):

  • 轻量级特征提取网络:受 MobileNetV1/V2 启发但与它们不同,去掉了 3D 卷积等重算子;
  • GPU 友好的锚点方案:从 Single Shot MultiBox Detector (SSD) 修改而来,改用更少层数、更稀疏的锚点生成,减少移动端 GPU 上的张量搬运;
  • 改进的 tie resolution 策略:替代传统的非极大值抑制(NMS),用更轻量、更适合移动端推理的冲突消解策略。

事实边界提示:"超快 / 超实时 / 亚毫秒"等表述来自官方文档及 BlazeFace 论文标题的描述,实际帧率取决于设备 GPU、输入分辨率与所选模型(短距 sparse/全距 dense)。


二、Solution API 与配置选项详解

官方文档指出:各平台/语言的命名风格与可用性可能略有差异。下表汇总了全部配置项及其平台适用范围:

配置项类型 / 取值范围平台默认值说明
model_selection整数01Python、Android、C++00选短距模型(最近约 2 米内的人脸最佳);1选全距模型(5 米内最佳),全距选项内部使用 sparse 模型以提升推理速度
model字符串"short"/"full"JavaScript 专用空字符串JS 侧没有model_selection,改用字符串指定;含义同上
selfie_mode布尔值JavaScript 专用false是否对图像/视频帧做水平翻转,用于自拍镜像显示
min_detection_confidence浮点数[0.0, 1.0]全平台0.5人脸检测模型判定"检测成功"的最低置信度阈值
static_image_mode布尔值Android是否按静态图片模式处理(与modelSelection一并出现在 Android 的受支持列表中)

2.1model_selection:短距与全距模型如何选择

model_selection0时,选择短距(short-range)模型,对距离摄像头2 米以内的人脸效果最佳;取1时选择全距(full-range)模型,对5 米以内的人脸效果最佳。全距选项会加载sparse(稀疏)模型以换取更快的推理速度。模型的详细对比见模型卡片。

从 Python 端源码可以清晰地看到模型选择的底层实现。在 mediapipe/python/solutions/face_detection.py 中预置了两份图的二进制路径:

_SHORT_RANGE_GRAPH_FILE_PATH = 'mediapipe/modules/face_detection/face_detection_short_range_cpu.binarypb' _FULL_RANGE_GRAPH_FILE_PATH = 'mediapipe/modules/face_detection/face_detection_full_range_cpu.binarypb'

构造函数中通过model_selection == 1二选一加载对应子图(face_detection.py#L67-L88):

binary_graph_path = _FULL_RANGE_GRAPH_FILE_PATH if model_selection == 1 else _SHORT_RANGE_GRAPH_FILE_PATH super().__init__( binary_graph_path=binary_graph_path, graph_options=self.create_graph_options( face_detection_pb2.FaceDetectionOptions(), { 'min_score_thresh': min_detection_confidence, }), outputs=['detections'])

注意这里暴露了一个重要实现细节:Python 层的min_detection_confidence会被透传为图选项里的min_score_thresh,也就是 SSD 解码阶段用于筛框的分数阈值(详见下文 proto 字段说明)。因此调大该阈值 → 要求更高的置信度 → 误检更少但漏检可能增加。

2.2model:JavaScript 的模型字符串写法

JavaScript 侧不支持model_selection整数下标,而是用字符串model

  • "short":短距模型,2 米内最佳;
  • "full":全距模型,5 米内最佳,内部同样使用 sparse 模型提速;
  • 未指定时默认空字符串。

2.3selfie_mode:自拍镜像翻转

布尔值,仅 JavaScript 方案提供。当为true时,图像/视频帧会在处理与输出时水平翻转,从而让摄像头前的人看到自己的"镜像",符合视频通话/自拍类 UI 的习惯。

2.4min_detection_confidence:置信度门槛

取值范围[0.0, 1.0],默认0.5。只有模型输出分数不低于该值的人脸才会被保留。阈值越低召回越高但误检越多,阈值越高越保守。

2.5 全平台命名映射

PythonJavaScriptAndroid (Java)
model_selectionmodelmodelSelection
min_detection_confidenceminDetectionConfidenceminDetectionConfidence
selfieMode
staticImageMode

三、输出结构:detections检测结果详解

所有平台的处理结果中,核心字段是detections——一个检测到的人脸集合。每一张人脸被表示为一个 Detection proto 消息,包含:

3.1 边界框(Bounding Box)

由四部分构成,全部做了归一化处理:

字段归一化分母取值范围
xmin图像宽度[0.0, 1.0]
width图像宽度[0.0, 1.0]
ymin图像高度[0.0, 1.0]
height图像高度[0.0, 1.0]

3.2 六个关键点(Key Points)

每个检测结果携带 6 个关键点,xy分别按图像宽、高归一化到[0.0, 1.0]

  1. 右眼(right eye)
  2. 左眼(left eye)
  3. 鼻尖(nose tip)
  4. 嘴中心(mouth center)
  5. 右耳屏点(right ear tragion)
  6. 左耳屏点(left ear tragion)

Python 侧在 face_detection.py#L46-L53 用FaceKeyPoint枚举精确映射了这 6 个关键点的下标顺序,这与 Detection proto 中relative_keypoints数组的下标一一对应:

class FaceKeyPoint(enum.IntEnum): """The enum type of the six face detection key points.""" RIGHT_EYE = 0 LEFT_EYE = 1 NOSE_TIP = 2 MOUTH_CENTER = 3 RIGHT_EAR_TRAGION = 4 LEFT_EAR_TRAGION = 5

配套的get_key_point(detection, key_point_enum)便捷方法(face_detection.py#L29-L43)正是按下标从detection.location_data.relative_keypoints中取出对应关键点,省去手写下标的麻烦:

def get_key_point( detection: detection_pb2.Detection, key_point_enum: 'FaceKeyPoint' ) -> Union[None, location_data_pb2.LocationData.RelativeKeypoint]: if not detection or not detection.location_data: return None return detection.location_data.relative_keypoints[key_point_enum]

想拿到像素坐标?只需把归一化坐标分别乘以图像宽、高即可。Android 侧文档代码中noseTip.getX() * width就是这么算的(见下文 Android 示例)。


四、Python Solution API

4.1 安装

请先按照通用 Python 安装指引安装 MediaPipe Python 包,然后参考下述用法。

Python 方案支持的配置项:

  • model_selection
  • min_detection_confidence

4.2 静态图片检测示例

import cv2 import mediapipe as mp mp_face_detection = mp.solutions.face_detection mp_drawing = mp.solutions.drawing_utils # For static images: IMAGE_FILES = [] with mp_face_detection.FaceDetection( model_selection=1, min_detection_confidence=0.5) as face_detection: for idx, file in enumerate(IMAGE_FILES): image = cv2.imread(file) # Convert the BGR image to RGB and process it with MediaPipe Face Detection. results = face_detection.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) # Draw face detections of each face. if not results.detections: continue annotated_image = image.copy() for detection in results.detections: print('Nose tip:') print(mp_face_detection.get_key_point( detection, mp_face_detection.FaceKeyPoint.NOSE_TIP)) mp_drawing.draw_detection(annotated_image, detection) cv2.imwrite('/tmp/annotated_image' + str(idx) + '.png', annotated_image)

关键点:

  • FaceDetectionwith上下文管理器使用,退出时自动释放底层图资源;
  • 输入必须是RGB 顺序的 numpy 数组,所以用cv2.cvtColor从 BGR 转 RGB(process()在非三通道输入时会抛ValueError,底层图出错时抛RuntimeError,见 face_detection.py#L90-L105);
  • get_key_point(detection, FaceKeyPoint.NOSE_TIP)用于单独打印鼻尖的归一化坐标;
  • 结果对象是 NamedTuple,唯一的detections字段携带全部检测到的人脸。

4.3 摄像头实时检测示例

import cv2 import mediapipe as mp mp_face_detection = mp.solutions.face_detection mp_drawing = mp.solutions.drawing_utils # For webcam input: cap = cv2.VideoCapture(0) with mp_face_detection.FaceDetection( model_selection=0, min_detection_confidence=0.5) as face_detection: while cap.isOpened(): success, image = cap.read() if not success: print("Ignoring empty camera frame.") # If loading a video, use 'break' instead of 'continue'. continue # To improve performance, optionally mark the image as not writeable to # pass by reference. image.flags.writeable = False image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results = face_detection.process(image) # Draw the face detection annotations on the image. image.flags.writeable = True image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR) if results.detections: for detection in results.detections: mp_drawing.draw_detection(image, detection) # Flip the image horizontally for a selfie-view display. cv2.imshow('MediaPipe Face Detection', cv2.flip(image, 1)) if cv2.waitKey(5) & 0xFF == 27: break cap.release()

实时场景的性能优化技巧(官方代码注释即为佐证):

  • image.flags.writeable = False:在处理前把输入图像标记为"只读",MediaPipe 便能按引用传递(pass by reference),避免一次不必要的拷贝,这是视频循环里重要的提速手段;
  • 处理完后再置回writeable = True并转回 BGR 用于绘制显示;
  • cv2.flip(image, 1)水平翻转实现自拍镜像显示(对应 JS 端由selfie_mode自动完成的翻转)。

五、JavaScript Solution API

请先阅读 MediaPipe 在 JavaScript 侧的通用介绍。JS 方案支持的选项:

  • selfieMode
  • model
  • minDetectionConfidence

5.1 HTML 骨架

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/control_utils/control_utils.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/@mediapipe/face_detection/face_detection.js" crossorigin="anonymous"></script> </head> <body> <div class="container"> <video class="input_video"></video> <canvas class="output_canvas" width="1280px" height="720px"></canvas> </div> </body> </html>

以上script标签按官方文档原样保留:引入@mediapipe/face_detection解决方案本体,以及配套的camera_utils(摄像头驱动)、drawing_utils(绘制工具)等辅助包;生产环境中可改为本地静态托管或受控 CDN 版本号。

5.2 逻辑代码

<script type="module"> const videoElement = document.getElementsByClassName('input_video')[0]; const canvasElement = document.getElementsByClassName('output_canvas')[0]; const canvasCtx = canvasElement.getContext('2d'); const drawingUtils = window; function onResults(results) { // Draw the overlays. canvasCtx.save(); canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height); canvasCtx.drawImage( results.image, 0, 0, canvasElement.width, canvasElement.height); if (results.detections.length > 0) { drawingUtils.drawRectangle( canvasCtx, results.detections[0].boundingBox, {color: 'blue', lineWidth: 4, fillColor: '#00000000'}); drawingUtils.drawLandmarks(canvasCtx, results.detections[0].landmarks, { color: 'red', radius: 5, }); } canvasCtx.restore(); } const faceDetection = new FaceDetection({locateFile: (file) => { return `https://cdn.jsdelivr.net/npm/@mediapipe/face_detection@0.0/${file}`; }}); faceDetection.setOptions({ model: 'short', minDetectionConfidence: 0.5 }); faceDetection.onResults(onResults); const camera = new Camera(videoElement, { onFrame: async () => { await faceDetection.send({image: videoElement}); }, width: 1280, height: 720 }); camera.start(); </script>

JS 侧的结构与用法要点:

  • locateFile决定模型 wasm/二进制文件的获取路径;
  • setOptions({model: 'short', ...})即上文配置表中 JS 专属的model字段;
  • 回调onResults中的results.detections[i].boundingBox是检测框,results.detections[i].landmarks则是关键点集合;
  • 采用"摄像头事件驱动"模型:每来一帧调用一次faceDetection.send({image})

六、Android Solution API

Android 侧请先按照通用 Android Solution 指引添加 MediaPipe Gradle 依赖,并参考对应示例工程运行。

Android 方案支持的配置项:

  • staticImageMode
  • modelSelection

6.1 摄像头输入(OpenGL 渲染)

// For camera input and result rendering with OpenGL. FaceDetectionOptions faceDetectionOptions = FaceDetectionOptions.builder() .setStaticImageMode(false) .setModelSelection(0).build(); FaceDetection faceDetection = new FaceDetection(this, faceDetectionOptions); faceDetection.setErrorListener( (message, e) -> Log.e(TAG, "MediaPipe Face Detection error:" + message)); // Initializes a new CameraInput instance and connects it to MediaPipe Face Detection Solution. CameraInput cameraInput = new CameraInput(this); cameraInput.setNewFrameListener( textureFrame -> faceDetection.send(textureFrame)); // Initializes a new GlSurfaceView with a ResultGlRenderer<FaceDetectionResult> instance // that provides the interfaces to run user-defined OpenGL rendering code. SolutionGlSurfaceView<FaceDetectionResult> glSurfaceView = new SolutionGlSurfaceView<>( this, faceDetection.getGlContext(), faceDetection.getGlMajorVersion()); glSurfaceView.setSolutionResultRenderer(new FaceDetectionResultGlRenderer()); glSurfaceView.setRenderInputImage(true); faceDetection.setResultListener( faceDetectionResult -> { if (faceDetectionResult.multiFaceDetections().isEmpty()) { return; } RelativeKeypoint noseTip = faceDetectionResult .multiFaceDetections() .get(0) .getLocationData() .getRelativeKeypoints(FaceKeypoint.NOSE_TIP); Log.i( TAG, String.format( "MediaPipe Face Detection nose tip normalized coordinates (value range: [0, 1]): x=%f, y=%f", noseTip.getX(), noseTip.getY())); // Request GL rendering. glSurfaceView.setRenderData(faceDetectionResult); glSurfaceView.requestRender(); }); // The runnable to start camera after the GLSurfaceView is attached. glSurfaceView.post( () -> cameraInput.start( this, faceDetection.getGlContext(), CameraInput.CameraFacing.FRONT, glSurfaceView.getWidth(), glSurfaceView.getHeight()));

6.2 相册图片输入(ImageView 绘制)

// For reading images from gallery and drawing the output in an ImageView. FaceDetectionOptions faceDetectionOptions = FaceDetectionOptions.builder() .setStaticImageMode(true) .setModelSelection(0).build(); FaceDetection faceDetection = new FaceDetection(this, faceDetectionOptions); // Connects MediaPipe Face Detection Solution to the user-defined ImageView // instance that allows users to have the custom drawing of the output landmarks // on it. FaceDetectionResultImageView imageView = new FaceDetectionResultImageView(this); faceDetection.setResultListener( faceDetectionResult -> { if (faceDetectionResult.multiFaceDetections().isEmpty()) { return; } int width = faceDetectionResult.inputBitmap().getWidth(); int height = faceDetectionResult.inputBitmap().getHeight(); RelativeKeypoint noseTip = faceDetectionResult .multiFaceDetections() .get(0) .getLocationData() .getRelativeKeypoints(FaceKeypoint.NOSE_TIP); Log.i( TAG, String.format( "MediaPipe Face Detection nose tip coordinates (pixel values): x=%f, y=%f", noseTip.getX() * width, noseTip.getY() * height)); // Request canvas drawing. imageView.setFaceDetectionResult(faceDetectionResult); runOnUiThread(() -> imageView.update()); }); faceDetection.setErrorListener( (message, e) -> Log.e(TAG, "MediaPipe Face Detection error:" + message)); // ActivityResultLauncher to get an image from the gallery as Bitmap. ActivityResultLauncher<Intent> imageGetter = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { Intent resultIntent = result.getData(); if (resultIntent != null && result.getResultCode() == RESULT_OK) { Bitmap bitmap = null; try { bitmap = MediaStore.Images.Media.getBitmap( this.getContentResolver(), resultIntent.getData()); // Please also rotate the Bitmap based on its orientation. } catch (IOException e) { Log.e(TAG, "Bitmap reading error:" + e); } if (bitmap != null) { faceDetection.send(bitmap); } } }); Intent pickImageIntent = new Intent(Intent.ACTION_PICK); pickImageIntent.setDataAndType(MediaStore.Images.Media.INTERNAL_CONTENT_URI, "image/*"); imageGetter.launch(pickImageIntent);

注意:图片模式的结果监听器里,官方用noseTip.getX() * width把归一化坐标换算成像素坐标再打印——正好呼应上文对归一化输出字段的说明。同时记得依据 EXIF 方向旋转 Bitmap,否则结果会出现角度偏差。

6.3 视频文件输入(OpenGL 渲染)

// For video input and result rendering with OpenGL. FaceDetectionOptions faceDetectionOptions = FaceDetectionOptions.builder() .setStaticImageMode(false) .setModelSelection(0).build(); FaceDetection faceDetection = new FaceDetection(this, faceDetectionOptions); faceDetection.setErrorListener( (message, e) -> Log.e(TAG, "MediaPipe Face Detection error:" + message)); // Initializes a new VideoInput instance and connects it to MediaPipe Face Detection Solution. VideoInput videoInput = new VideoInput(this); videoInput.setNewFrameListener( textureFrame -> faceDetection.send(textureFrame)); // Initializes a new GlSurfaceView with a ResultGlRenderer<FaceDetectionResult> instance. SolutionGlSurfaceView<FaceDetectionResult> glSurfaceView = new SolutionGlSurfaceView<>( this, faceDetection.getGlContext(), faceDetection.getGlMajorVersion()); glSurfaceView.setSolutionResultRenderer(new FaceDetectionResultGlRenderer()); glSurfaceView.setRenderInputImage(true); faceDetection.setResultListener( faceDetectionResult -> { if (faceDetectionResult.multiFaceDetections().isEmpty()) { return; } RelativeKeypoint noseTip = faceDetectionResult .multiFaceDetections() .get(0) .getLocationData() .getRelativeKeypoints(FaceKeypoint.NOSE_TIP); Log.i( TAG, String.format( "MediaPipe Face Detection nose tip normalized coordinates (value range: [0, 1]): x=%f, y=%f", noseTip.getX(), noseTip.getY())); // Request GL rendering. glSurfaceView.setRenderData(faceDetectionResult); glSurfaceView.requestRender(); }); ActivityResultLauncher<Intent> videoGetter = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { Intent resultIntent = result.getData(); if (resultIntent != null) { if (result.getResultCode() == RESULT_OK) { glSurfaceView.post( () -> videoInput.start( this, resultIntent.getData(), faceDetection.getGlContext(), glSurfaceView.getWidth(), glSurfaceView.getHeight())); } } }); Intent pickVideoIntent = new Intent(Intent.ACTION_PICK); pickVideoIntent.setDataAndType(MediaStore.Video.Media.INTERNAL_CONTENT_URI, "video/*"); videoGetter.launch(pickVideoIntent);

三种输入方式的共性规律:

  • 结果对象是FaceDetectionResult,取人脸走multiFaceDetections(),关键点走getRelativeKeypoints(FaceKeypoint.XXX)(Android 侧同样有FaceKeypoint枚举);
  • 相机与视频都基于textureFrame -> faceDetection.send(textureFrame)的逐帧回调,渲染统一走SolutionGlSurfaceView<FaceDetectionResult>+ 自定义ResultGlRenderer
  • 图片走faceDetection.send(bitmap)+ 自定义ImageView绘制回调。

七、源码级原理:子图结构、proto 选项与运行管线

7.1 模块子图清单

本仓库中,人脸检测被封装为一组可复用子图(subgraph),集中在 mediapipe/modules/face_detection/ 目录。模块自带 README(mediapipe/modules/face_detection/README.md)给出了四种子图的速查表:

子图适用距离输入 / 推理
FaceDetectionFullRangeCpu5 米内最佳CPU 输入,CPU 推理
FaceDetectionFullRangeGpu5 米内最佳GPU 输入,GPU 推理
FaceDetectionShortRangeCpu2 米内最佳CPU 输入,CPU 推理
FaceDetectionShortRangeGpu2 米内最佳GPU 输入,GPU 推理

以 GPU 短距子图 face_detection_short_range_gpu.pbtxt 为例,它的顶层接口为:

  • 输入流IMAGE:imageGpuBuffer或多后端Image);
  • 输出流DETECTIONS:detectionsstd::vector<Detection>);
  • 声明graph_optionsmediapipe.FaceDetectionOptions
  • 内部委托 GPU 推理,并设置gpu_origin: TOP_LEFT(坐标系原点约定在左上角,保证与图像处理习惯一致)以及delegate.gpu.use_advanced_gpu_api: true
graph_options: { [type.googleapis.com/mediapipe.FaceDetectionOptions] {} } node { calculator: "FaceDetectionShortRange" input_stream: "IMAGE:image" output_stream: "DETECTIONS:detections" node_options: { [type.googleapis.com/mediapipe.FaceDetectionOptions] { gpu_origin: TOP_LEFT delegate: { gpu { use_advanced_gpu_api: true } } } } option_value: "OPTIONS:options" }

7.2FaceDetectionOptionsproto 字段语义

子图的全部可调参数定义在 mediapipe/modules/face_detection/face_detection.proto。虽然 Python/JS/Android 高层 API 只暴露了极少数选项,但底层图支持细粒度调节:

proto 字段类型说明
model_pathstringTF Lite 模型路径
gpu_originGpuOrigin.Mode坐标原点:CONVENTIONALTOP_LEFT
tensor_width/tensor_heightint32送入检测模型的张量尺寸
num_layersint32用于生成锚点的输出特征图层数
stridesrepeated int32每层特征图对应的步长
interpolated_scale_aspect_ratiofloat由 SsdAnchorsCalculator 插值出的锚点宽高比,默认1.0
num_boxesint32检测模型输出的候选框数量
x_scale/y_scale/w_scale/h_scalefloatSSD 解码器的坐标反归一化缩放系数
min_score_threshfloatSSD 检测结果保留的分数阈值(Python 的min_detection_confidence就映射到此字段
delegateInferenceCalculatorOptions.DelegateTFLite 推理委托(CPU/GPU 等)

由此可以看到配置参数的完整链路:高层 API 选项 →FaceDetectionOptions(proto extension,id = 374290926)→ 子图内部 Calculator 选项 → SSD 锚点生成 / 解码 / 阈值过滤。例如,调整锚点生成的num_layersstrides会影响可召回的人脸尺度范围,这正是"短距 2 米 / 全距 5 米"两种模型差异的底层来源之一。

7.3 端到端管线:以移动端 GPU 图为例

上层 example 图把子图、限流与渲染拼装成一条完整管线。见 mediapipe/graphs/face_detection/face_detection_mobile_gpu.pbtxt:

# Input input_stream: "input_video" # GpuBuffer # Outputs output_stream: "output_video" # 叠加了渲染结果的图像 output_stream: "face_detections" # std::vector<Detection>

该图由 4 个环节组成,每个环节都对应真实 Calculator:

  1. FlowLimiterCalculator流量限流:透传首帧,之后等待下游(FINISHED:output_video回边)完成上一帧任务才放行下一帧,中间到达的帧直接丢弃。这保证图中绝大多数区域同时处理的帧数不超过 1,避免实时移动端应用因节点排队造成延迟与内存飙升(图内注释详尽说明了设计动机);
  2. FaceDetectionShortRangeGpu子图:接收throttled_input_video,输出face_detections
  3. DetectionsToRenderDataCalculator:把检测框转换为绘图原语,option 中设定描边thickness: 4.0、颜色color { r: 255 g: 0 b: 0 }(红色框);
  4. AnnotationOverlayCalculator:把渲染数据叠加到原图上输出output_video

如果你需要"只取框,不画框",可以在构建图时省去第 3、4 两个渲染节点,直接把face_detections输出流接到你的下游消费者即可——这也正是把 Face Detection 当作前置 ROI 提供者的标准做法。


八、Example Apps:移动端 / 桌面端 / Coral 的图与构建目标

官方文档为各平台提供了可直接构建运行的示例。以下目标路径均可在本仓库中对应找到:

8.1 移动端 GPU 管线

  • 图:face_detection_mobile_gpu.pbtxt
  • 端到端演示与运行说明可参考 mediapipe/docs/face_detection_mobile_gpu.md(仓库内配套的运行文档)

8.2 移动端 CPU 管线

与 GPU 管线非常相似,差别在于:管线的开头与结尾分别执行 GPU→CPU 与 CPU→GPU 的图像传输,因此图中其余部分(与 GPU 管线共享相同配置)完全在 CPU 上运行。

  • 图:face_detection_mobile_cpu.pbtxt

8.3 桌面端

  • CPU 运行:使用图 face_detection_desktop_live.pbtxt;
  • GPU 运行:桌面端也可复用移动 GPU 图 face_detection_mobile_gpu.pbtxt;
  • 桌面构建目标定义在 mediapipe/examples/desktop/face_detection/BUILD:其中face_detection_cpuface_detection_gpu短距目标把face_detection_short_range.tflite作为 data 打包,还额外提供face_detection_full_range_cpu(依赖face_detection_full_range.tflite与全距桌面实时图face_detection_full_range_desktop_live.pbtxt)——这从侧面印证了"模型选择"不仅是高层 API 概念,而是贯穿到图与 BUILD 目标的真实资源。

运行上述示例前,请先按平台的通用构建指引操作:Android、iOS 与桌面 C++。

提示:查看 / 调试图结构时,可把.pbtxt图文本复制进 MediaPipe Visualizer 可视化(用法见 visualizer 文档),其关联子图会被一并展开显示。

8.4 Coral 边缘设备

如需在 Coral Dev Board 等 EdgeTPU 设备上交叉编译运行,请参考 mediapipe/examples/coral 目录下的说明与构建文件。人脸检测还有专门为 EdgeTPU 量化的模型(face-detector-quantized_edgetpu.tflite,在 模型清单 中列出)。


九、模型对比与选型建议

官方模型卡片章节把人脸检测模型整理为三档:

模型适用距离说明
Short-range 模型2 米内最佳通用场景默认选择
Full-range(dense)模型5 米内最佳相对 sparse 在Recall(召回率)上略优
Full-range(sparse)模型5 米内最佳相对 dense 在Precision(精确率)上更优

文档给出的关键数据(来自模型卡片描述):

  • dense 与 sparse 在F-score 上质量相当,差别体现在细粒度指标:dense 召回略好,sparse 精确率更高;
  • 速度方面:在 CPU 上经由 XNNPACK 执行时,sparse 比 dense 大约快30%;GPU 上两者延迟相近。

因此选型建议很直接:

  • 若应用以近距离自拍 / 视频通话为主且追求极致延迟 →model_selection=0(短距)即可;
  • 若需要覆盖3~5 米的中远距离(如安防、互动大屏、教室等)→ 选全距(model_selection=1),在纯 CPU 部署时可优先 sparse 换取约 30% 的推理加速,在 GPU 上则两者延迟差异不大。

十、小结

MediaPipe Face Detection 的完整工作流可总结为一条链路:

摄像头/图片/视频帧 → (可选限流 FlowLimiter)→ FaceDetection{Short|Full}Range{Cpu|Gpu} 子图 → SSD 锚点检测 + 阈值过滤(min_score_thresh/min_detection_confidence)→detections(归一化边界框 + 6 关键点)→ 下游 ROI 任务 或 叠加渲染

本文覆盖的实践要点速查:

  • 参数:model_selection/model管距离档位与稀疏模型,min_detection_confidence管置信门槛(Python 端透传为min_score_thresh),selfie_mode管镜像翻转;
  • 输出:每张脸 = 归一化 bbox(xmin/width/ymin/height)+ 6 关键点(右眼、左眼、鼻尖、嘴中心、左右耳屏点),像素坐标 = 归一化坐标 × 图像宽/高;
  • 源码佐证:face_detection.py 展示了枚举、便捷取点与模型选择的真实映射;face_detection.proto 与 face_detection_short_range_gpu.pbtxt 展示了底层可调字段;face_detection_mobile_gpu.pbtxt 则演示了"限流 → 检测 → 渲染"的端到端拼图范式。

掌握以上内容后,你可以很自然地把 Face Detection 作为一帧图像的第一级处理单元,把detections中的人脸框与关键点交给 Face Mesh、表情分类或人脸分割等后续任务,构建出完整的实时人脸理解流水线。

【免费下载链接】mediapipeCross-platform, customizable ML solutions for live and streaming media.项目地址: https://gitcode.com/GitHub_Trending/med/mediapipe

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 21:21:47

ONIX音响设备固件升级与降级全攻略

1. 欧尼士ONIX设备固件管理全指南作为一名音响设备发烧友&#xff0c;我使用欧尼士ONIX系列产品已有五年时间&#xff0c;期间经历过无数次固件升级和降级操作。今天我想系统分享一下XM2/XM5/XM10 Mystic和XP1/XST20等机型的固件管理经验&#xff0c;包括如何安全下载固件、正确…

作者头像 李华
网站建设 2026/9/10 21:20:40

CANN/ge KernelLaunchInfo API文档

简介 【免费下载链接】ge GE&#xff08;Graph Engine&#xff09;是面向昇腾的图编译器和执行器&#xff0c;提供了计算图优化、多流并行、内存复用和模型下沉等技术手段&#xff0c;加速模型执行效率&#xff0c;减少模型内存占用。 GE 提供对 PyTorch、TensorFlow 前端的友好…

作者头像 李华
网站建设 2026/9/10 21:16:19

同日宣告:OpenAI称AGI到来,美国国会提案将开发超级AI列为刑事罪

2026年9月3日&#xff0c;两件事同天发生&#xff0c;将AI行业推入一个过去11年从未面对过的处境&#xff1a;OpenAI总裁格雷格布罗克曼在媒体电话会议上宣布"欢迎来到AGI时代"&#xff0c;而同一天&#xff0c;美国参议员伯尼桑德斯与众议员格雷格卡萨联合提出《禁止…

作者头像 李华