Загрузка и настройка PoseNet

Для работы с PoseNet необходимо подключить библиотеку ml5.js, которая представляет собой высокоуровневый интерфейс для моделей машинного обучения, работающих поверх TensorFlow.js. Подключение можно выполнить двумя способами: через CDN или через пакетный менеджер npm.

Через CDN:

<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js"></script>
<script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script>

Через npm:

npm install ml5
npm install p5

После установки можно импортировать библиотеку в JavaScript-коде:

import * as ml5 from 'ml5';
import p5 from 'p5';

Важно: ml5.js тесно интегрирована с библиотекой p5.js, особенно для работы с визуализацией и потоковым видео.


Инициализация видеопотока

PoseNet требует видеопоток в качестве источника данных. Для этого используется встроенный объект p5.Video или стандартный HTMLVideoElement.

Пример создания видеопотока через p5.js:

let video;

function setup() {
  createCanvas(640, 480);
  video = createCapture(VIDEO);
  video.size(width, height);
  video.hide();
}
  • createCapture(VIDEO) запускает веб-камеру.
  • video.hide() скрывает элемент <video>, чтобы визуализировать поток через canvas.

Загрузка модели PoseNet

PoseNet может работать в двух режимах: single-pose (одна фигура) и multi-pose (несколько фигур). Настройка модели производится при инициализации.

let poseNet;

function setup() {
  createCanvas(640, 480);
  video = createCapture(VIDEO);
  video.size(width, height);
  video.hide();

  // Загрузка модели PoseNet
  poseNet = ml5.poseNet(video, modelLoaded);

  // Подписка на событие обнаружения поз
  poseNet.on('pose', gotPoses);
}

function modelLoaded() {
  console.log('PoseNet загружен');
}
  • ml5.poseNet(video, options, callback) принимает три параметра: источник видео, объект настроек и callback-функцию после загрузки модели.
  • Метод .on('pose', callback) позволяет получать данные поз каждый раз, когда модель обнаруживает человека.

Настройки PoseNet

Объект настроек предоставляет гибкую конфигурацию модели:

let options = {
  architecture: 'MobileNetV1', // базовая модель: 'MobileNetV1' или 'ResNet50'
  outputStride: 16,            // шаг вывода: 8, 16, 32
  detectionType: 'single',     // 'single' или 'multiple'
  quantBytes: 2,               // размер квантования весов: 1, 2, 4
  minConfidence: 0.5           // минимальная вероятность ключевых точек
};

poseNet = ml5.poseNet(video, options, modelLoaded);

Ключевые параметры:

  • architecture: влияет на точность и скорость. MobileNetV1 быстрее и легче, ResNet50 точнее, но требует больше ресурсов.
  • outputStride: чем меньше, тем точнее модель, но выше нагрузка на GPU/CPU.
  • detectionType: single для одной фигуры, multiple для отслеживания нескольких людей одновременно.
  • quantBytes: влияет на размер загружаемой модели.
  • minConfidence: фильтр для исключения низкокачественных поз.

Получение данных поз

После настройки PoseNet модель возвращает массив объектов поз, каждый объект содержит координаты ключевых точек и их уверенность.

function gotPoses(poses) {
  if (poses.length > 0) {
    let pose = poses[0].pose;

    // Пример доступа к ключевым точкам
    let nose = pose.keypoints.find(k => k.part === 'nose');
    console.log(`Нос: x=${nose.position.x}, y=${nose.position.y}, уверенность=${nose.score}`);
  }
}

Структура ключевых точек:

  • part: имя части тела (например, nose, leftWrist, rightKnee).
  • position: объект с координатами {x, y}.
  • score: вероятность правильного распознавания (от 0 до 1).

Визуализация поз

Canvas позволяет отрисовывать ключевые точки и соединения:

function draw() {
  image(video, 0, 0, width, height);

  if (poses && poses.length > 0) {
    let pose = poses[0].pose;

    // Отрисовка ключевых точек
    for (let keypoint of pose.keypoints) {
      if (keypoint.score > 0.5) {
        fill(255, 0, 0);
        noStroke();
        ellipse(keypoint.position.x, keypoint.position.y, 10, 10);
      }
    }

    // Соединение костей
    stroke(0, 255, 0);
    strokeWeight(2);
    drawSkeleton(pose);
  }
}

function drawSkeleton(pose) {
  const connections = [
    ['leftShoulder', 'rightShoulder'],
    ['leftShoulder', 'leftElbow'],
    ['leftElbow', 'leftWrist'],
    ['rightShoulder', 'rightElbow'],
    ['rightElbow', 'rightWrist'],
    ['leftHip', 'rightHip'],
    ['leftShoulder', 'leftHip'],
    ['rightShoulder', 'rightHip'],
    ['leftHip', 'leftKnee'],
    ['leftKnee', 'leftAnkle'],
    ['rightHip', 'rightKnee'],
    ['rightKnee', 'rightAnkle']
  ];

  for (let [partA, partB] of connections) {
    let pointA = pose.keypoints.find(k => k.part === partA);
    let pointB = pose.keypoints.find(k => k.part === partB);

    if (pointA.score > 0.5 && pointB.score > 0.5) {
      line(pointA.position.x, pointA.position.y, pointB.position.x, pointB.position.y);
    }
  }
}
  • Ключевые точки визуализируются красными кругами.
  • Соединения между костями отображаются зелеными линиями.
  • Фильтр по score позволяет избегать визуализации некорректных точек.

Оптимизация производительности

  • Уменьшение разрешения видео (video.size(width, height)) снижает нагрузку на процессор.
  • Использование MobileNetV1 вместо ResNet50 ускоряет работу в реальном времени.
  • Ограничение количества обновлений визуализации с помощью frameRate() помогает удерживать плавность анимации.
function setup() {
  createCanvas(640, 480);
  frameRate(30);
}
  • Настройка outputStride и quantBytes также влияет на производительность: меньшие значения ускоряют обработку за счет компромисса точности.

Эта конфигурация обеспечивает базовую и устойчивую интеграцию PoseNet с видеопотоком и canvas, создавая основу для последующего анализа движений и реализации интерактивных приложений.