4. 使用Edge TPU在Coral Dev Board上运行姿态估计模型

任务目标

在 Coral Dev Board 上利用 Edge TPU 加速,运行 PoseNet 模型,对摄像头实时画面进行人体姿态关键点检测,并将检测结果(骨架连线与关键点)叠加显示在视频帧上。

环境与依赖

  • 硬件:Coral Dev Board(搭载 Edge TPU 协处理器)
  • 系统: Mendel Linux(Dev Board 出厂系统)
  • Python 包:pycoral、opencv-python、numpy、Pillow
  • 模型文件:posenet_mobilenet_v1_075_353_481_quant_decoder_edgetpu.tflite(含内置解码器,输入尺寸 353×481)

安装依赖:

pip3 install pycoral opencv-python numpy Pillow

模型文件可从 Coral 官方模型库 下载,或使用以下命令获取:

wget https://github.com/google-coral/test_data/raw/master/posenet_mobilenet_v1_075_353_481_quant_decoder_edgetpu.tflite

完整实现代码

以下代码从 USB 摄像头读取帧,缩放至模型输入尺寸后送入 Edge TPU 推理,再将检测到的 17 个关键点坐标映射回原始帧并绘制骨架:

import cv2
import numpy as np
from pycoral.adapters import common
from pycoral.utils.edgetpu import make_interpreter

MODEL = "posenet_mobilenet_v1_075_353_481_quant_decoder_edgetpu.tflite"
INPUT_SIZE = (481, 353)  # (宽, 高)
KEYPOINT_NAMES = [
    "nose", "left_eye", "right_eye", "left_ear", "right_ear",
    "left_shoulder", "right_shoulder", "left_elbow", "right_elbow",
    "left_wrist", "right_wrist", "left_hip", "right_hip",
    "left_knee", "right_knee", "left_ankle", "right_ankle"
]
SKELETON = [
    (0, 1), (0, 2), (1, 3), (2, 4), (5, 6), (5, 7), (7, 9),
    (6, 8), (8, 10), (5, 11), (6, 12), (11, 12), (11, 13),
    (13, 15), (12, 14), (14, 16)
]

def draw_pose(frame, keypoints, threshold=0.3):
    h, w = frame.shape[:2]
    coords = []
    for kp in keypoints:
        y, x, score = kp
        if score > threshold:
            px, py = int(x * w), int(y * h)
            coords.append((px, py))
            cv2.circle(frame, (px, py), 4, (0, 255, 0), -1)
        else:
            coords.append(None)
    for a, b in SKELETON:
        if coords[a] and coords[b]:
            cv2.line(frame, coords[a], coords[b], (255, 0, 0), 2)
    return frame

def main():
    interpreter = make_interpreter(MODEL)
    interpreter.allocate_tensors()
    cap = cv2.VideoCapture(0)
    if not cap.isOpened():
        raise RuntimeError("无法打开摄像头")

    while True:
        ret, frame = cap.read()
        if not ret:
            break
        # 缩放并填充至模型输入尺寸
        resized = cv2.resize(frame, INPUT_SIZE)
        rgb = cv2.cvtColor(resized, cv2.COLOR_BGR2RGB)
        common.set_input(interpreter, rgb)
        interpreter.invoke()

        # 输出张量: [1, 17, 3] -> (y, x, score),已归一化
        output = interpreter.get_output_tensor(0)
        keypoints = output.copy().reshape(17, 3)

        draw_pose(frame, keypoints)
        cv2.imshow("Edge TPU PoseNet", frame)
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break

    cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

运行方式

  1. 将上述代码保存为 posenet_demo.py,与模型文件放在同一目录。
  2. 连接 USB 摄像头至 Dev Board。
  3. 执行:python3 posenet_demo.py

验证方法与判定标准

  • 正常启动:程序无报错,弹出名为 "Edge TPU PoseNet" 的窗口,显示摄像头画面。
  • 检测生效:人站在摄像头前,画面中人体关键点位置出现绿色圆点,相邻关键点之间有蓝色连线。
  • 实时性:移动身体时,骨架跟随动作变化,无明显卡顿(Edge TPU 推理延迟通常在数十毫秒量级)。
  • 退出:按键盘 q 键,窗口关闭,程序正常结束。

若画面无检测结果,请确认人体完整出现在画面中且光线充足;若程序报模型加载错误,检查模型文件名是否与代码一致。

关键说明

PoseNet 输出为每个关键点的归一化坐标 (y, x, score),代码中已按此顺序解析并映射回原始帧分辨率。模型输入尺寸为 353(高)×481(宽),代码使用 cv2.resize 直接缩放,未保持宽高比,因此检测坐标映射回原始帧时可能存在轻微偏移,但对姿态可视化影响可忽略。若需精确映射,应使用 letterbox 填充方案。