xxxxxxxxxx
189
// A fair portion of the code is from ml5.js's beginner guide to body pose detection, at docs.ml5js.org/#/reference/bodypose (to get the body detection working)
// Parameters
let targetPose = {
left_wrist: {
x: 70,
y: 220
},
left_elbow: {
x: 150,
y: 380
},
left_shoulder: {
x: 200,
y: 180
},
right_shoulder: {
x: 440,
y: 180
},
right_elbow: {
x: 490,
y: 380
},
right_wrist: {
x: 570,
y: 220
}
}
// Global variables (not parameters)
let detectedPoses = [];
let bodyPose;
let connections;
let webcamVideo;
// Our definitions
// Callback function for when the model returns pose data
function handleDetectedPoses(results) {
// Store the model's results in a global variable
detectedPoses = results;
}
function isPlayerInCorrectPosition() {
if (detectedPoses.length > 0) { // Check to see if we detected any poses
for (let part in targetPose) {
for (let axis of "xy") {
if (detectedPoses[0][part].confidence < 0.1 || Math.abs(targetPose[part][axis] - detectedPoses[0][part][axis]) > 25) {
return false;
}
}
}
} else {
return false;
}
return true;
}
function drawTargetPositionOutline() {
// Draw lines connecting points
stroke(255)
strokeWeight(25)
let previousPart = targetPose[Object.keys(targetPose)[0]]
for (let partKey in targetPose) {
let part = targetPose[partKey]
line(previousPart.x, previousPart.y, part.x, part.y)
previousPart = part
}
// Draw circles at points
fill(255)
stroke(0)
strokeWeight(10)
for (let partKey in targetPose) {
let part = targetPose[partKey]
circle(part.x, part.y, 50)
}
}
// p5's functions
function preload() {
// Load the bodyPose model
bodyPose = ml5.bodyPose({flipped: true});
}
function setup() {
createCanvas(640, 480);
// windowResized(); // Just calling it manually to resize the window without duplicating code // Currently causes issues in draw
// Create the webcamVideo and hide it
webcamVideo = createCapture(VIDEO, {flipped: true});
webcamVideo.size(640, 480);
webcamVideo.hide();
// Start detecting poses in the webcam webcamVideo
bodyPose.detectStart(webcamVideo, handleDetectedPoses);
// Get the skeleton connection information
connections = bodyPose.getSkeleton();
}
function draw() {
// scale(-1, 1); // Horizontally flip the drawing, as that's more natural
// Draw the webcam's video
image(webcamVideo, 0, 0, width, height);
// Draw the target position's outline
drawTargetPositionOutline()
// Display whether the player is in the correct position, and dim the webcam's video, in order to focus more on the skeleton
if (isPlayerInCorrectPosition()) {
fill(0, 16, 0, 232)
} else {
fill(16, 0, 0, 232)
}
rect(0, 0, width, height);
// Iterate through all the poses
for (let i = 0; i < detectedPoses.length; i++) {
let pose = detectedPoses[i];
// Draw the skeleton connections
for (let j = 0; j < connections.length; j++) {
let pointA = pose.keypoints[connections[j][0]];
let pointB = pose.keypoints[connections[j][1]];
// Only draw a line if we have confidence in both points
if (pointA.confidence > 0.1 && pointB.confidence > 0.1) {
stroke(128);
strokeWeight(2);
line(pointA.x, pointA.y, pointB.x, pointB.y);
}
}
// Iterate through all the keypoints for each pose
for (let j = 0; j < pose.keypoints.length; j++) {
let keypoint = pose.keypoints[j];
// Only draw a circle if the keypoint's confidence is greater than 0.1
if (keypoint.confidence > 0.1) {
fill(255);
noStroke();
circle(keypoint.x, keypoint.y, 10);
}
}
}
}
// Currently causes issues (issue is actually in draw, but I'll fix it later)
// Resize the canvas, while preserving the 4/3 aspect ratio
// function windowResized() {
// let newWidth;
// let newHeight;
// if (windowWidth/windowHeight > 4/3) {
// newWidth = windowHeight * 4/3;
// newHeight = windowHeight;
// } else {
// newWidth = windowWidth;
// newHeight = windowWidth * 3/4;
// }
// resizeCanvas(newWidth, newHeight)
// }