Uses ml5.js to track 21 hand landmarks and visualize the skeletal structure.
p5.js 2.0 ml5.js 1.0
Camera ml5.js Hand Pose
View Source Code
let video;
let handPose;
let hands = [];
let options = { flipHorizontal: false };
let isModelStarted = false;
let isModelLoaded = false;
function setup() {
createCanvas(windowWidth, windowHeight);
pixelDensity(1);
video = createCapture(VIDEO);
video.size(640, 480);
video.hide();
ml5.handPose(options).then((results) => {
handPose = results;
isModelLoaded = true;
});
}
function gotHands(results) {
hands = results;
}
function draw() {
background(20);
if (
!isModelLoaded ||
!video ||
!video.elt ||
video.elt.readyState < 2 ||
video.elt.videoWidth === 0
) {
fill(255);
textAlign(CENTER, CENTER);
textSize(24);
text("Initializing AI Model... Please wait", width / 2, height / 2);
return;
}
if (!isModelStarted) {
handPose.detectStart(video.elt, gotHands);
isModelStarted = true;
}
push();
translate(width, 0);
scale(-1, 1);
let vW = video.width || video.elt.videoWidth;
let vH = video.height || video.elt.videoHeight;
let aspect = vW / vH;
let drawW = height * aspect;
let drawH = height;
if (drawW > width) {
drawW = width;
drawH = width / aspect;
}
let drawX = (width - drawW) / 2;
let drawY = (height - drawH) / 2;
tint(255, 80);
image(video, drawX, drawY, drawW, drawH);
noTint();
for (let i = 0; i < hands.length; i++) {
let hand = hands[i];
fill(255, 0, 100);
noStroke();
for (let j = 0; j < hand.keypoints.length; j++) {
let keypoint = hand.keypoints[j];
let x = map(keypoint.x, 0, vW, drawX, drawX + drawW);
let y = map(keypoint.y, 0, vH, drawY, drawY + drawH);
circle(x, y, 10);
}
stroke(255, 200);
strokeWeight(2);
drawFinger(hand.keypoints, 0, 4, vW, vH, drawX, drawY, drawW, drawH);
drawFinger(hand.keypoints, 5, 8, vW, vH, drawX, drawY, drawW, drawH);
drawFinger(hand.keypoints, 9, 12, vW, vH, drawX, drawY, drawW, drawH);
drawFinger(hand.keypoints, 13, 16, vW, vH, drawX, drawY, drawW, drawH);
drawFinger(hand.keypoints, 17, 20, vW, vH, drawX, drawY, drawW, drawH);
connect(hand.keypoints, 0, 5, vW, vH, drawX, drawY, drawW, drawH);
connect(hand.keypoints, 0, 17, vW, vH, drawX, drawY, drawW, drawH);
connect(hand.keypoints, 5, 9, vW, vH, drawX, drawY, drawW, drawH);
connect(hand.keypoints, 9, 13, vW, vH, drawX, drawY, drawW, drawH);
connect(hand.keypoints, 13, 17, vW, vH, drawX, drawY, drawW, drawH);
}
pop();
}
function drawFinger(keypoints, start, end, vW, vH, dx, dy, dw, dh) {
for (let i = start; i < end; i++) {
connect(keypoints, i, i + 1, vW, vH, dx, dy, dw, dh);
}
}
function connect(keypoints, i, j, vW, vH, dx, dy, dw, dh) {
let p1 = keypoints[i];
let p2 = keypoints[j];
if (p1 && p2) {
let x1 = map(p1.x, 0, vW, dx, dx + dw);
let y1 = map(p1.y, 0, vH, dy, dy + dh);
let x2 = map(p2.x, 0, vW, dx, dx + dw);
let y2 = map(p2.y, 0, vH, dy, dy + dh);
line(x1, y1, x2, y2);
}
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
}