关键点检测与姿态估计 本节摘要:姿态就是一组有序关键点,关键点检测器就是一个热图回归器,剩下的都是簿记工作。本节区分自顶向下(先检测人再逐框姿态)与自底向上(一次前向预测所有关键点再分组)两种范式,讲清为每个关键点回归高斯热图、推理时取 argmax 出坐标的全流程;解释 OpenPose 的部件亲和场(PAF)如何把关键点关联成实例;认识 COCO 17 关键点与 OKS 指标;并用 MediaPipe Pose、MMPose、YOLOv8-pose 做生产级估计。读完本节,你能为健身 App、动作捕捉、手势控制、AR 试穿选对姿态栈。 对应原课程:Phase 4 · Lesson 21 · (原英文 )。
本节摘要:姿态就是一组有序关键点,关键点检测器就是一个热图回归器,剩下的都是簿记工作。本节区分自顶向下(先检测人再逐框姿态)与自底向上(一次前向预测所有关键点再分组)两种范式,讲清为每个关键点回归高斯热图、推理时取 argmax 出坐标的全流程;解释 OpenPose 的部件亲和场(PAF)如何把关键点关联成实例;认识 COCO 17 关键点与 OKS 指标;并用 MediaPipe Pose、MMPose、YOLOv8-pose 做生产级估计。读完本节,你能为健身 App、动作捕捉、手势控制、AR 试穿选对姿态栈。
对应原课程:Phase 4 · Lesson 21 ·
keypoint-pose(原英文phases/04-computer-vision/21-keypoint-pose/docs/en.md)。
阅读完本节,你应当能够:
关键点任务有许多别名:人体姿态(17 个关节)、人脸关键点(68 或 478 点)、手部(21 点)、动物姿态、机器人物体姿态、医学解剖标志。它们结构相同:在一个物体上检测 K 个离散点,输出它们的 (x, y) 坐标。
姿态估计是动作捕捉、健身应用、运动分析、手势控制、动画、AR 试穿、机器人抓取的基础。2D 情形已成熟;3D 姿态(从单相机估计世界坐标下的关节位置)是当前研究前沿。
工程问题是规模。单图单人姿态是 20ms 的问题;30fps 人群中的多人姿态是另一个问题,需要不同架构。
自顶向下(HRNet、ViTPose)是精度领头羊;自底向上(OpenPose、HigherHRNet)是拥挤场景的吞吐领头羊。
与其直接回归 (x, y),不如每个关键点预测一张 H×W 热图,在真实位置中心一个高斯斑。
target[k, y, x] = exp(-((x - cx_k)^2 + (y - cy_k)^2) / (2 sigma^2))
推理时每张热图的 argmax 就是预测关键点位置。
热图为何比直接回归好:网络的空间结构(卷积特征图)与空间输出自然对齐;高斯目标还正则化——小的定位误差产生小损失,而非零。
argmax 给整数坐标。要亚像素精度,可在 argmax 及邻域拟合抛物线精修,或用熟知的偏移 (dx, dy) = 0.25 * (heatmap[y, x+1] − heatmap[y, x−1], ...) 方向。
OpenPose 自底向上关联的招。对每对相连关键点(如左肩到左肘),预测一个 2 通道场,编码从一个指向另一个的单位向量。要把一个肩与它的肘关联,沿候选对连线积分 PAF,积分最高的那对就匹配。
对每条连接(肢体): PAF 通道: 2(单位向量 x, y) 线积分: 对采样点求和 (PAF · 线方向) 积分越高 = 匹配越强
优雅,且无需逐人裁剪就能扩展到任意人群规模。
标准人体姿态数据集:每人 17 个关键点,PCK(正确关键点百分比)和 OKS(物体关键点相似度)作指标。OKS 是关键点版的 IoU,COCO mAP@OKS 报的就是它。
import numpy as np import torch def gaussian_heatmap(size, cx, cy, sigma=2.0): yy, xx = np.meshgrid(np.arange(size), np.arange(size), indexing="ij") return np.exp(-((xx - cx) ** 2 + (yy - cy) ** 2) / (2 * sigma ** 2)).astype(np.float32) hm = gaussian_heatmap(64, 32, 32, sigma=2.0) print(f"峰值: {hm.max():.3f} 在 ({hm.argmax() % 64}, {hm.argmax() // 64})")
每关键点热图沿通道轴堆叠得到完整目标张量。
一个 U-Net 风格模型,输出 K 个热图通道。
import torch.nn as nn import torch.nn.functional as F class TinyKeypointNet(nn.Module): def __init__(self, num_keypoints=4, base=16): super().__init__() self.down1 = nn.Sequential(nn.Conv2d(3, base, 3, 2, 1), nn.ReLU(inplace=True)) self.down2 = nn.Sequential(nn.Conv2d(base, base * 2, 3, 2, 1), nn.ReLU(inplace=True)) self.mid = nn.Sequential(nn.Conv2d(base * 2, base * 2, 3, 1, 1), nn.ReLU(inplace=True)) self.up1 = nn.ConvTranspose2d(base * 2, base, 2, 2) self.up2 = nn.ConvTranspose2d(base, num_keypoints, 2, 2) def forward(self, x): h1 = self.down1(x) h2 = self.down2(h1) h3 = self.mid(h2) u1 = self.up1(h3) return self.up2(u1)
输入 (N, 3, H, W),输出 (N, K, H, W),损失是对高斯目标的逐像素 MSE。
def heatmap_to_coords(heatmaps): """ heatmaps: (N, K, H, W) 返回: (N, K, 2) 图像像素 float 坐标 """ N, K, H, W = heatmaps.shape hm = heatmaps.reshape(N, K, -1) idx = hm.argmax(dim=-1) ys = (idx // W).float() xs = (idx % W).float() return torch.stack([xs, ys], dim=-1) coords = heatmap_to_coords(torch.randn(2, 4, 32, 32)) print(f"坐标: {coords.shape}") # (2, 4, 2)
推理时一行。要亚像素精修,在 argmax 周围插值。
简单:在白画布上画四个点,学着预测它们。
def make_synthetic_sample(size=64): img = np.ones((3, size, size), dtype=np.float32) rng = np.random.default_rng() kps = rng.integers(8, size - 8, size=(4, 2)) for cx, cy in kps: img[:, cy - 2:cy + 2, cx - 2:cx + 2] = 0.0 hms = np.stack([gaussian_heatmap(size, cx, cy) for cx, cy in kps]) return img, hms, kps
简单到微型模型一分钟就能学会。
model = TinyKeypointNet(num_keypoints=4) opt = torch.optim.Adam(model.parameters(), lr=3e-3) for step in range(200): batch = [make_synthetic_sample() for _ in range(16)] imgs = torch.from_numpy(np.stack([b[0] for b in batch])) hms = torch.from_numpy(np.stack([b[1] for b in batch])) pred = model(imgs) # 把 pred 上采样到全分辨率 pred = F.interpolate(pred, size=hms.shape[-2:], mode="bilinear", align_corners=False) loss = F.mse_loss(pred, hms) opt.zero_grad(); loss.backward(); opt.step()
本节产出两个可复用文件(位于原课程 outputs/):
prompt-pose-stack-picker.md:一个提示词——给定延迟、人群大小、2D vs 3D 需求,在 MediaPipe / YOLOv8-pose / HRNet / ViTPose 间挑。skill-heatmap-to-coords.md:一个技能——写出每个生产姿态模型都在用的亚像素热图转坐标例程。下一节进入 3D 高斯泼溅——用数百万个 3D 高斯替代 NeRF,实现分钟级训练、实时渲染的新一代 3D 重建。