You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Vue.js中使用MediaPipe实现人体姿态检测?

Vue中MediaPipe人体姿态检测实现方案

核心问题说明

  1. results的来源:results是MediaPipe Pose的onResults回调函数的参数,由MediaPipe内部完成姿态检测后自动传入,首次出现就是你定义的onResults(results)函数的参数位置,不需要手动定义。
  2. 你错误地在init方法中直接调用this.results,此时Pose还未启动检测,results根本不存在,这是导致失败的主要原因。
  3. 绘制逻辑必须放在onResults回调内,只有当MediaPipe返回检测结果后,才能基于results进行绘制。
  4. 代码同时混用了ES模块import和CDN全局变量,导致模块冲突,需统一为CDN方式。

修正后的完整代码

HTML部分

<div id="app">
  <div class="container">
    <video class="input_video" autoplay playsinline></video>
    <canvas class="output_canvas" width="1280" height="720"></canvas>
    <div class="landmark-grid-container"></div>
  </div>
</div>

<script src="https://unpkg.com/vue@3"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_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/pose/pose.js" crossorigin="anonymous"></script>

JavaScript部分

const App = {
  name: "App",
  data() {
    return {
      videoElement: null,
      canvasElement: null,
      canvasCtx: null,
      landmarkContainer: null,
      grid: null,
      pose: null
    };
  },
  mounted() {
    this.videoElement = document.querySelector(".input_video");
    this.canvasElement = document.querySelector(".output_canvas");
    this.canvasCtx = this.canvasElement.getContext("2d");
    this.landmarkContainer = document.querySelector(".landmark-grid-container");
    this.grid = new window.LandmarkGrid(this.landmarkContainer);
    this.initPose();
  },
  methods: {
    initPose() {
      // 初始化Pose实例
      this.pose = new window.Pose({
        locateFile: (file) => {
          return `https://cdn.jsdelivr.net/npm/@mediapipe/pose/${file}`;
        },
      });

      // 设置Pose参数
      this.pose.setOptions({
        modelComplexity: 1,
        smoothLandmarks: true,
        enableSegmentation: true,
        smoothSegmentation: true,
        minDetectionConfidence: 0.5,
        minTrackingConfidence: 0.5,
      });

      // 绑定结果回调,确保this指向Vue实例
      this.pose.onResults(this.onResults.bind(this));

      // 启动相机
      const camera = new window.Camera(this.videoElement, {
        onFrame: async () => {
          await this.pose.send({ image: this.videoElement });
        },
        width: 1280,
        height: 720,
      });
      camera.start();
    },
    onResults(results) {
      // 清除画布
      this.canvasCtx.save();
      this.canvasCtx.clearRect(0, 0, this.canvasElement.width, this.canvasElement.height);

      // 绘制分割蒙版(如果开启)
      if (results.segmentationMask) {
        this.canvasCtx.drawImage(results.segmentationMask, 0, 0, this.canvasElement.width, this.canvasElement.height);
        this.canvasCtx.globalCompositeOperation = "source-in";
        this.canvasCtx.fillStyle = "#00FF00";
        this.canvasCtx.fillRect(0, 0, this.canvasElement.width, this.canvasElement.height);
        this.canvasCtx.globalCompositeOperation = "destination-atop";
        this.canvasCtx.drawImage(results.image, 0, 0, this.canvasElement.width, this.canvasElement.height);
        this.canvasCtx.globalCompositeOperation = "source-over";
      } else {
        // 直接绘制原始图像
        this.canvasCtx.drawImage(results.image, 0, 0, this.canvasElement.width, this.canvasElement.height);
      }

      // 绘制姿态连接点和关键点
      if (results.poseLandmarks) {
        window.drawConnectors(this.canvasCtx, results.poseLandmarks, window.POSE_CONNECTIONS, {
          color: "#00FF00",
          lineWidth: 4,
        });
        window.drawLandmarks(this.canvasCtx, results.poseLandmarks, {
          color: "#FF0000",
          lineWidth: 2,
        });
        // 更新3D网格
        this.grid.updateLandmarks(results.poseWorldLandmarks);
      } else {
        this.grid.updateLandmarks([]);
      }

      this.canvasCtx.restore();
    },
  },
};

Vue.createApp(App).mount('#app');

关键修改点说明

  1. 移除ES模块import:HTML中已通过CDN引入MediaPipe脚本,所有API挂载在window对象下,直接使用window.Pose、window.drawConnectors即可。
  2. 绘制逻辑移至onResults:只有MediaPipe返回检测结果results后,才执行画布绘制、关键点渲染操作。
  3. 修正this绑定:用bind(this)确保onResults回调能访问Vue实例属性,避免指向错误。
  4. 规范实例属性声明:将video、canvas等元素引用放到data中,符合Vue开发规范。
  5. 增加兼容性判断:针对分割蒙版是否开启做判断,避免无蒙版时的报错。

内容的提问来源于stack exchange,提问作者Bilal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:09:53