MediaPipe Pose Landmarker:BlazePose 33 个关键点,跑在设备上

MediaPipe Pose Landmarker: BlazePose 33 Keypoints, Runs On-Device

Tech-Experiment #mediapipe#pose-estimation#computer-vision#blazepose#on-device-ml#google
🇨🇳 中文

先说链接的问题。

google.github.io/mediapipe/solutions/pose.html 是 MediaPipe 的旧版文档,对应的是 Legacy API——mediapipe.solutions.pose。这套 API 已于 2023 年 3 月正式废弃,代码库继续开放、预编译包继续分发,但不再维护。

如果你现在新建项目,要用的是 Tasks API,入口是 mediapipe.tasks.vision.PoseLandmarker


仓库现状

MediaPipe 主仓库已从 google/mediapipe 迁移到 google-ai-edge/mediapipe,旧地址会自动跳转。截至发稿,37,006 stars,Apache-2.0 协议,C++ 实现,最新版本 v1.0.0(2026-07-28 发布)。

github.com/google-ai-edge/mediapipe

BlazePose 是什么

MediaPipe Pose 底层是 BlazePose,Google Research 在 2020 年发表的实时人体姿态估计模型,采用两阶段 Detector-Tracker 流水线:

  1. Detector:在帧内定位人体 ROI(Region of Interest)。找到之后就锁定,后续帧只跑 Tracker,除非人体消失。
  2. Tracker:在 ROI 内预测 33 个关键点坐标 + 可见度评分。

这个设计的好处是帧间开销低——Detector 只在首帧和重定位时跑,大多数帧只跑轻量 Tracker。


33 个关键点

输出固定 33 个关键点,覆盖从头顶到脚趾的全身主要关节:

编号部位编号部位
0鼻子11–12左/右肩
1–4左眼内/外 + 右眼内/外13–14左/右肘
5–6左/右耳15–16左/右腕
7–10嘴角 + 耳廓23–24左/右髋
17–22手指关键点(拇指/食指/小指尖)25–32膝/踝/脚跟/趾尖

每个关键点返回:

  • x, y:图像归一化坐标(0–1)
  • z:相对于髋部中点的深度估计(相对值)
  • visibility:该点是否可见的置信度(0–1)
  • presence:该点是否在帧内的置信度(0–1)

Tasks API 还输出世界坐标系版本(单位:米,以髋部为原点),适合计算关节角度和骨骼长度。


三个模型变体

模型文件名精度速度适用场景
Litepose_landmarker_lite.task较低最快资源受限设备、实时应用
Fullpose_landmarker_full.task中等适中大多数场景的默认选择
Heavypose_landmarker_heavy.task最高最慢精度优先、离线分析

所有模型均可从 Google Storage 下载,也可以通过 Python 包自动拉取。


Tasks API:Python 用法

安装:

pip install mediapipe

图片模式(单张图片):

import mediapipe as mp
from mediapipe.tasks import python
from mediapipe.tasks.python import vision

base_options = python.BaseOptions(
    model_asset_path="pose_landmarker_full.task"
)
options = vision.PoseLandmarkerOptions(
    base_options=base_options,
    output_segmentation_masks=False
)

with vision.PoseLandmarker.create_from_options(options) as landmarker:
    image = mp.Image.create_from_file("photo.jpg")
    result = landmarker.detect(image)

    for idx, pose_landmarks in enumerate(result.pose_landmarks):
        print(f"人物 {idx}:")
        for i, landmark in enumerate(pose_landmarks):
            print(f"  关键点 {i}: x={landmark.x:.3f}, y={landmark.y:.3f}, "
                  f"z={landmark.z:.3f}, vis={landmark.visibility:.3f}")

实时流模式(摄像头):

import mediapipe as mp
from mediapipe.tasks.python import vision
from mediapipe.tasks.python.core.base_options import BaseOptions
import cv2
import time

def result_callback(result, output_image, timestamp_ms):
    if result.pose_landmarks:
        # 处理每帧结果
        for pose_landmarks in result.pose_landmarks:
            pass  # 在这里画骨骼或做分析

base_options = BaseOptions(model_asset_path="pose_landmarker_full.task")
options = vision.PoseLandmarkerOptions(
    base_options=base_options,
    running_mode=vision.RunningMode.LIVE_STREAM,
    result_callback=result_callback,
    num_poses=1
)

with vision.PoseLandmarker.create_from_options(options) as landmarker:
    cap = cv2.VideoCapture(0)
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        mp_image = mp.Image(
            image_format=mp.ImageFormat.SRGB,
            data=cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        )
        timestamp_ms = int(time.time() * 1000)
        landmarker.detect_async(mp_image, timestamp_ms)

running_mode 三个值:

  • IMAGE:单张图片,同步
  • VIDEO:视频文件,同步,需要传入时间戳
  • LIVE_STREAM:摄像头实时,异步回调

Tasks API:JavaScript / Web

CDN 或 npm 安装:

npm install @mediapipe/tasks-vision
import { PoseLandmarker, FilesetResolver, DrawingUtils } from "@mediapipe/tasks-vision";

const vision = await FilesetResolver.forVisionTasks(
    "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/wasm"
);

const poseLandmarker = await PoseLandmarker.createFromOptions(vision, {
    baseOptions: {
        modelAssetPath: "https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_full/float16/1/pose_landmarker_full.task",
        delegate: "GPU"  // 或 "CPU"
    },
    runningMode: "VIDEO",
    numPoses: 1
});

// 每帧调用
const result = poseLandmarker.detectForVideo(videoElement, performance.now());
const drawingUtils = new DrawingUtils(canvasCtx);
for (const landmark of result.landmarks) {
    drawingUtils.drawLandmarks(landmark);
    drawingUtils.drawConnectors(landmark, PoseLandmarker.POSE_CONNECTIONS);
}

推理完全在浏览器内运行,WebGL 或 WASM 后端,无需后端服务器。


旧 Legacy API 对应关系

如果你在老代码里看到这种写法:

# Legacy API(已废弃,勿用于新项目)
import mediapipe as mp
mp_pose = mp.solutions.pose
pose = mp_pose.Pose()
results = pose.process(frame_rgb)

对应的 Tasks API 迁移:

LegacyTasks API
mp.solutions.pose.Pose()vision.PoseLandmarker.create_from_options(options)
results.pose_landmarksresult.pose_landmarks[0](第一个人)
results.pose_world_landmarksresult.pose_world_landmarks[0]
mp.solutions.drawing_utils.draw_landmarksDrawingUtils.drawLandmarks()

主要变化:Tasks API 明确支持多人num_poses 参数),输出是 list;Legacy API 只支持单人。


应用场景

  • 健身动作识别:检测深蹲、俯卧撑等动作是否标准
  • 体态分析:实时检测驼背、头前倾等不良姿势
  • 手语识别:结合手部关键点(HandLandmarker)做手语翻译
  • 舞蹈/动作捕捉:低成本动捕方案,无需专用硬件
  • AR 试衣:在虚拟换装应用中对齐服装到人体

几点限制

  • 单目 z 轴不可靠:深度估计是从单目图像推算的,z 值是相对值,不适合做精确3D重建。
  • 遮挡处理有限:部分遮挡的关键点仍会输出但 visibility 会变低,不会自动填补缺失。
  • Heavy 模型实时性差:在端侧设备(手机、树莓派)上 Heavy 模型通常无法保证实时。
  • 非 SMPL 格式:输出的是稀疏 33 点关键点,不是 SMPL/SMPL-X 格式的完整参数化人体模型,不能直接导入 Blender 做绑定。
  • 多人场景 Detector 负担增加num_poses > 1 时,每次都需要 Detector 全图扫描,帧率下降明显。

参考资料

Tasks API 文档:ai.google.dev/edge/mediapipe/solutions/vision/pose_landmarker
GitHub:github.com/google-ai-edge/mediapipe
代码示例:github.com/googlesamples/mediapipe(mediapipe-samples 仓库)

开源代码仅供学习研究,生产部署请注意 model 和 data 的隐私条款(MediaPipe Tasks 有设备端处理声明)。


仓库:github.com/google-ai-edge/mediapipe
版本:v1.0.0 | Stars:37,006 | License:Apache-2.0

🇬🇧 English

First, a note about the link.

google.github.io/mediapipe/solutions/pose.html is the old documentation for the Legacy API — mediapipe.solutions.pose. This API was officially deprecated in March 2023. The codebase remains open and prebuilt binaries continue to be distributed, but it’s no longer maintained.

If you’re building something new, you want the Tasks API: mediapipe.tasks.vision.PoseLandmarker.


Repository status

The MediaPipe repository has migrated from google/mediapipe to google-ai-edge/mediapipe — the old URL redirects automatically. At time of writing: 37,006 stars, Apache-2.0 license, C++ implementation, latest release v1.0.0 (published 2026-07-28).

github.com/google-ai-edge/mediapipe

What BlazePose is

MediaPipe Pose uses BlazePose, a real-time body pose estimation model published by Google Research in 2020. It uses a two-stage Detector-Tracker pipeline:

  1. Detector: locates the person’s ROI (Region of Interest) within the frame. Once found, the ROI is locked for subsequent frames — the Detector only re-runs if the person disappears.
  2. Tracker: predicts 33 keypoint coordinates and visibility scores within the ROI.

The design keeps per-frame cost low: the Detector runs only on the first frame and on re-localization; most frames only run the lightweight Tracker.


33 keypoints

The output is always 33 fixed keypoints covering major joints from head to toes:

IndexLandmarkIndexLandmark
0Nose11–12Left/right shoulder
1–4Left/right eye inner/outer13–14Left/right elbow
5–6Left/right ear15–16Left/right wrist
7–10Mouth corners + ear tragion23–24Left/right hip
17–22Fingertip keypoints25–32Knee/ankle/heel/toe tip

Each keypoint returns:

  • x, y: normalized image coordinates (0–1)
  • z: depth relative to the hip midpoint (relative units)
  • visibility: confidence that the point is visible (0–1)
  • presence: confidence that the point is within the frame (0–1)

The Tasks API also outputs world coordinates (meters, origin at hip midpoint) — useful for computing joint angles and bone lengths.


Three model variants

ModelFilenameAccuracySpeedUse case
Litepose_landmarker_lite.taskLowerFastestResource-constrained devices, real-time
Fullpose_landmarker_full.taskMediumModerateDefault for most scenarios
Heavypose_landmarker_heavy.taskHighestSlowestAccuracy-first, offline analysis

All models can be downloaded from Google Storage or pulled automatically via the Python package.


Tasks API: Python

Install:

pip install mediapipe

Image mode (single image):

import mediapipe as mp
from mediapipe.tasks import python
from mediapipe.tasks.python import vision

base_options = python.BaseOptions(
    model_asset_path="pose_landmarker_full.task"
)
options = vision.PoseLandmarkerOptions(
    base_options=base_options,
    output_segmentation_masks=False
)

with vision.PoseLandmarker.create_from_options(options) as landmarker:
    image = mp.Image.create_from_file("photo.jpg")
    result = landmarker.detect(image)

    for idx, pose_landmarks in enumerate(result.pose_landmarks):
        print(f"Person {idx}:")
        for i, landmark in enumerate(pose_landmarks):
            print(f"  Keypoint {i}: x={landmark.x:.3f}, y={landmark.y:.3f}, "
                  f"z={landmark.z:.3f}, vis={landmark.visibility:.3f}")

Live stream mode (webcam):

import mediapipe as mp
from mediapipe.tasks.python import vision
from mediapipe.tasks.python.core.base_options import BaseOptions
import cv2, time

def result_callback(result, output_image, timestamp_ms):
    if result.pose_landmarks:
        for pose_landmarks in result.pose_landmarks:
            pass  # draw skeleton or run analysis here

base_options = BaseOptions(model_asset_path="pose_landmarker_full.task")
options = vision.PoseLandmarkerOptions(
    base_options=base_options,
    running_mode=vision.RunningMode.LIVE_STREAM,
    result_callback=result_callback,
    num_poses=1
)

with vision.PoseLandmarker.create_from_options(options) as landmarker:
    cap = cv2.VideoCapture(0)
    while True:
        ret, frame = cap.read()
        if not ret:
            break
        mp_image = mp.Image(
            image_format=mp.ImageFormat.SRGB,
            data=cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        )
        landmarker.detect_async(mp_image, int(time.time() * 1000))

Three running_mode values:

  • IMAGE: single image, synchronous
  • VIDEO: video file, synchronous, pass timestamp
  • LIVE_STREAM: webcam, async callback

Tasks API: JavaScript / Web

npm install @mediapipe/tasks-vision
import { PoseLandmarker, FilesetResolver, DrawingUtils } from "@mediapipe/tasks-vision";

const vision = await FilesetResolver.forVisionTasks(
    "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision/wasm"
);

const poseLandmarker = await PoseLandmarker.createFromOptions(vision, {
    baseOptions: {
        modelAssetPath: "https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_full/float16/1/pose_landmarker_full.task",
        delegate: "GPU"
    },
    runningMode: "VIDEO",
    numPoses: 1
});

const result = poseLandmarker.detectForVideo(videoElement, performance.now());
const drawingUtils = new DrawingUtils(canvasCtx);
for (const landmark of result.landmarks) {
    drawingUtils.drawLandmarks(landmark);
    drawingUtils.drawConnectors(landmark, PoseLandmarker.POSE_CONNECTIONS);
}

Inference runs entirely in the browser — WebGL or WASM backend, no server needed.


Legacy → Tasks API migration

If you see old code:

# Legacy API (deprecated — don't use for new projects)
import mediapipe as mp
mp_pose = mp.solutions.pose
pose = mp_pose.Pose()
results = pose.process(frame_rgb)

Migration guide:

LegacyTasks API
mp.solutions.pose.Pose()vision.PoseLandmarker.create_from_options(options)
results.pose_landmarksresult.pose_landmarks[0] (first person)
results.pose_world_landmarksresult.pose_world_landmarks[0]
mp.solutions.drawing_utils.draw_landmarksDrawingUtils.drawLandmarks()

Main difference: Tasks API explicitly supports multiple people (num_poses parameter); results are a list. Legacy API only supported one person.


Key limitations

  • Monocular z-axis is unreliable: depth is estimated from a single image — z values are relative, not suitable for accurate 3D reconstruction.
  • Limited occlusion handling: partially occluded keypoints still output but with lower visibility scores — missing points aren’t auto-filled.
  • Heavy model isn’t real-time on edge devices: phones and Raspberry Pi typically can’t maintain real-time throughput with the Heavy model.
  • Not SMPL format: the output is 33 sparse keypoints, not a parameterized body model like SMPL/SMPL-X — can’t be directly imported into Blender for rigging.
  • Multi-person performance drops: num_poses > 1 requires a full-frame Detector scan every time, significantly reducing frame rate.

Repository: github.com/google-ai-edge/mediapipe
Version: v1.0.0 | Stars: 37,006 | License: Apache-2.0
Docs: ai.google.dev/edge/mediapipe/solutions/vision/pose_landmarker
Samples: github.com/googlesamples/mediapipe

💬 评论与讨论

使用 GitHub 账号登录后发表评论

关于本站 · 免责声明

🍄 Mushroom Research Blog 是非营利、免费公开的个人科技观察博客与公众号 XStack18,不接受商业合作、不代表任何企业或机构立场,也不谋求商业利益。我们以个人视角客观中立地记录和分析 AI、Web3 等领域的最新模型发布与技术动态——不止转述新闻标题或二手信息,而是给出有独立思考的深入分析,希望帮更多人获得有价值的一手科技认知。

⚠️ 文中介绍的开源代码与模型,仅供学习交流与技术借鉴。它们大多仍处于早期阶段,有待进一步研究和验证,请勿直接用于工作或生产环境;如需采用,请先自行充分测试,并核实其许可证与安全性。
Open-source code and models featured here are shared for learning and reference only. Most are early-stage and still need further study and verification — please don't use them directly in your work or in production. Test them thoroughly and check their licenses and security first.

  1. 本站文章均为作者基于公开信息的个人研究与观点整理,不代表文中提及的任何公司、产品、模型的官方立场,未与其构成商业关联或合作关系。
  2. 科技行业信息更新极快,我们尽力保证内容准确、及时,但不对完整性、实时性做绝对保证,具体请以相关企业/项目官方公告为准。
  3. 文中引用的第三方商标、产品名称、图片、数据等版权归原权利人所有,我们会尽量注明来源;如你认为存在版权疑问或侵权,请通过下方邮箱联系我们,收到通知后会尽快核实处理(更正、加注来源或删除)。
  4. 文章内容仅为技术科普与个人观点,不构成投资、法律或其他专业建议,据此进行任何决策的后果需自行判断和承担。

📮 侵权 / 勘误 / 合作咨询:[email protected]