|
import { PoseLandmarker, FilesetResolver, DrawingUtils } from "https://cdn.skypack.dev/@mediapipe/[email protected]"; |
|
|
|
const demosSection = document.getElementById("demos"); |
|
let poseLandmarker = undefined; |
|
let runningMode = "IMAGE"; |
|
let enableWebcamButton; |
|
let enableCounter; |
|
let webcamRunning = false; |
|
const videoHeight = "360px"; |
|
const videoWidth = "480px"; |
|
let shoulder = []; |
|
let elbow = []; |
|
let wrist = []; |
|
let hip = []; |
|
let ankle = []; |
|
let knee = []; |
|
let stage; |
|
let angle; |
|
let counter = 0; |
|
let starter = 0; |
|
|
|
const createPoseLandmarker = async () => { |
|
const vision = await FilesetResolver.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/[email protected]/wasm"); |
|
poseLandmarker = await PoseLandmarker.createFromOptions(vision, { |
|
baseOptions: { |
|
modelAssetPath: `https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task`, |
|
delegate: "GPU" |
|
}, |
|
runningMode: runningMode, |
|
numPoses: 2 |
|
}); |
|
demosSection.classList.remove("invisible"); |
|
}; |
|
createPoseLandmarker(); |
|
|
|
|
|
const video = document.getElementById("webcam"); |
|
const canvasElement = document.getElementById("output_canvas"); |
|
const canvasCtx = canvasElement.getContext("2d"); |
|
const drawingUtils = new DrawingUtils(canvasCtx); |
|
|
|
|
|
const hasGetUserMedia = () => { var _a; return !!((_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.getUserMedia); }; |
|
|
|
if (hasGetUserMedia()) { |
|
enableWebcamButton = document.getElementById("webcamButton"); |
|
enableWebcamButton.addEventListener("click", enableCam); |
|
} |
|
else { |
|
console.warn("getUserMedia() is not supported by your browser"); |
|
} |
|
|
|
function enableCam(event) { |
|
if (!poseLandmarker) { |
|
console.log("Wait! poseLandmaker not loaded yet."); |
|
return; |
|
} |
|
if (webcamRunning === true) { |
|
webcamRunning = false; |
|
enableWebcamButton.innerText = "ENABLE PREDICTIONS"; |
|
} |
|
else { |
|
webcamRunning = true; |
|
enableWebcamButton.innerText = "DISABLE PREDICTIONS"; |
|
} |
|
|
|
const constraints = { |
|
video: true |
|
}; |
|
|
|
navigator.mediaDevices.getUserMedia(constraints).then((stream) => { |
|
video.srcObject = stream; |
|
video.addEventListener("loadeddata", predictWebcam); |
|
}); |
|
} |
|
let lastVideoTime = -1; |
|
async function predictWebcam() { |
|
canvasElement.style.height = videoHeight; |
|
video.style.height = videoHeight; |
|
canvasElement.style.width = videoWidth; |
|
video.style.width = videoWidth; |
|
|
|
if (runningMode === "IMAGE") { |
|
runningMode = "VIDEO"; |
|
await poseLandmarker.setOptions({ runningMode: "VIDEO" }); |
|
} |
|
let startTimeMs = performance.now(); |
|
if (lastVideoTime !== video.currentTime) { |
|
lastVideoTime = video.currentTime; |
|
poseLandmarker.detectForVideo(video, startTimeMs, (result) => { |
|
canvasCtx.save(); |
|
canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height); |
|
for (const landmark of result.landmarks) { |
|
shoulder = [landmark[11].x, landmark[11].y] |
|
elbow = [landmark[13].x, landmark[13].y] |
|
wrist = [landmark[15].x, landmark[15].y] |
|
hip = [landmark[23].x, landmark[23].y] |
|
knee = [landmark[25].x, landmark[25].y] |
|
ankle = [landmark[27].x, landmark[27].y] |
|
|
|
drawingUtils.drawLandmarks(landmark, { |
|
radius: (data) => DrawingUtils.lerp(data.from.z, -0.15, 0.1, 5, 1) |
|
}); |
|
drawingUtils.drawConnectors(landmark, PoseLandmarker.POSE_CONNECTIONS); |
|
} |
|
canvasCtx.restore(); |
|
}); |
|
} |
|
|
|
function calculateAngle(a, b, c) { |
|
const vecA = new Array(a[0], a[1]); |
|
const vecB = new Array(b[0], b[1]); |
|
const vecC = new Array(c[0], c[1]); |
|
|
|
const radians = Math.atan2(vecC[1] - vecB[1], vecC[0] - vecB[0]) - Math.atan2(vecA[1] - vecB[1], vecA[0] - vecB[0]); |
|
let angle = Math.abs(radians * (180.0 / Math.PI)); |
|
|
|
if (angle > 180.0) { |
|
angle = 360 - angle; |
|
} |
|
|
|
return angle; |
|
} |
|
|
|
const startButton = document.getElementById('startButton'); |
|
startButton.addEventListener('click', () => { |
|
starter = 1 |
|
}); |
|
|
|
const stopButton = document.getElementById('stopButton'); |
|
stopButton.addEventListener('click', () => { |
|
starter = 0 |
|
}); |
|
|
|
const restartButton = document.getElementById('restartButton'); |
|
restartButton.addEventListener('click', () => { |
|
counter = 0 |
|
}); |
|
|
|
if (starter == 1){ |
|
if(document.getElementById('curl').checked) { |
|
angle = calculateAngle(shoulder,elbow,wrist) |
|
|
|
if (angle > 160){ |
|
stage = "down" |
|
} |
|
if (angle < 30 & stage =='down'){ |
|
stage="up" |
|
counter +=1 |
|
} |
|
} |
|
if(document.getElementById('squat').checked) { |
|
angle = calculateAngle(hip,knee,ankle) |
|
|
|
if (angle > 169){ |
|
stage = "up" |
|
} |
|
if (angle < 90 & stage =='up'){ |
|
stage="down" |
|
counter +=1 |
|
} |
|
} |
|
} |
|
|
|
const landmarkValuesDiv = document.getElementById('counter'); |
|
landmarkValuesDiv.innerHTML = `stage: ${stage}, count: ${counter}`; |
|
|
|
|
|
if (webcamRunning === true) { |
|
window.requestAnimationFrame(predictWebcam); |
|
} |
|
} |
|
|