Библиотека ml5.js является высокоуровневым интерфейсом для работы с моделями машинного обучения на JavaScript. Она построена поверх TensorFlow.js и предоставляет удобные средства для обработки изображений, видео, аудио и других данных. Одной из практических задач в компьютерном зрении является анализ позиций точек на изображении и вычисление геометрических величин, таких как углы и расстояния.
В ml5.js часто используются предобученные модели, возвращающие наборы
ключевых точек. Примеры включают poseNet для
отслеживания поз и faceApi для детекции лицевых
особенностей. Каждая точка имеет координаты (x, y) в
двумерной плоскости, иногда дополнительно с вероятностью уверенности
confidence.
let nose = pose.keypoints[0].position; // nose.x, nose.y
let leftWrist = pose.keypoints[9].position; // leftWrist.x, leftWrist.y
Ключевой момент: координаты точек всегда выражаются
в пикселях относительно верхнего левого угла холста
(canvas). Для корректных вычислений важно учитывать масштаб
изображения.
Расстояние между двумя точками A(x1, y1) и
B(x2, y2) в двумерном пространстве вычисляется по формуле
Евклидова расстояния:
[ d = ]
Пример функции на JavaScript с использованием ml5.js:
function getDistance(pointA, pointB) {
let dx = pointB.x - pointA.x;
let dy = pointB.y - pointA.y;
return Math.sqrt(dx * dx + dy * dy);
}
let distance = getDistance(nose, leftWrist);
console.log("Расстояние:", distance);
Совет: для оптимизации можно использовать
Math.hypot(dx, dy), что повышает читаемость кода и
предотвращает ошибки при больших значениях координат.
Для трех точек A, B, C угол в
вершине B определяется через векторное
представление:
Создаются два вектора: [ = (x_A - x_B, y_A - y_B), = (x_C - x_B, y_C - y_B)]
Вычисляется угол с помощью скалярного произведения: [ = ]
Перевод в градусы: [ = () ]
Пример функции:
function getAngle(A, B, C) {
let BAx = A.x - B.x;
let BAy = A.y - B.y;
let BCx = C.x - B.x;
let BCy = C.y - B.y;
let dotProduct = BAx * BCx + BAy * BCy;
let magnitudeBA = Math.hypot(BAx, BAy);
let magnitudeBC = Math.hypot(BCx, BCy);
let cosTheta = dotProduct / (magnitudeBA * magnitudeBC);
cosTheta = Math.min(1, Math.max(-1, cosTheta)); // защита от ошибок округления
let angle = Math.acos(cosTheta) * (180 / Math.PI);
return angle;
}
let elbowAngle = getAngle(leftShoulder, leftElbow, leftWrist);
console.log("Угол локтя:", elbowAngle);
Особенности:
Math.min и Math.max
предотвращает появление NaN при погрешностях вычислений.Для вычисления углов и расстояний между точками удобно подключить poseNet следующим образом:
let video;
let poseNet;
let poses = [];
function setup() {
createCanvas(640, 480);
video = createCapture(VIDEO);
video.hide();
poseNet = ml5.poseNet(video, modelReady);
poseNet.on('pose', function(results) {
poses = results;
});
}
function modelReady() {
console.log("poseNet загружен");
}
function draw() {
image(video, 0, 0, width, height);
if (poses.length > 0) {
let pose = poses[0].pose;
let leftElbow = pose.keypoints[7].position;
let leftShoulder = pose.keypoints[5].position;
let leftWrist = pose.keypoints[9].position;
let angle = getAngle(leftShoulder, leftElbow, leftWrist);
let distance = getDistance(leftShoulder, leftWrist);
fill(255, 0, 0);
textSize(16);
text(`Угол локтя: ${angle.toFixed(1)}°`, 10, 20);
text(`Расстояние плечо-запястье: ${distance.toFixed(1)}`, 10, 40);
}
}
Ключевые моменты интеграции:
poseNet.on('pose', callback) предоставляет массив всех
найденных поз.keypoints с
координатами.draw, что обеспечивает
обновление данных в реальном времени.