I am doing a project to create a react web application that uses human pose estimation models to identify proper workout repetitions. As a starting I wrote the code for a bicep curl counter that calculates the angle between left shoulder, left elbow and left wrist and then uses some bicep curl counter logic to increment the counter value and set the stage of the exercise ie, either 'Up' or 'Down'.
I am able to correctly calculate the angle and the real time value of the angle is being displayed on the console. Its value decreases when I bring my dumbells/hand in upward motion and then it increases when I bring it down to a 180 degree. So the angle calculation is working perfectly fine. But I am not able to display the value of my 'counter' in the console.
import React, { useRef, useState, useEffect } from "react";
import * as tf from "https://cdn.jsdelivr.net/npm/@tensorflow/tfjs";
import * as posenet from "@tensorflow-models/posenet";
import Webcam from "react-webcam";
import { drawKeypoints, drawSkeleton } from "./Utilities";
import "./Detection.css";
import _ from "lodash";
export const Detection = () => {
const webcamRef = useRef(null);
const canvasRef = useRef(null);
const [poseData, setPoseData] = useState({
leftShoulder: null,
leftElbow: null,
leftWrist: null,
});
const [counter, setCounter] = useState(0);
const [stage, setStage] = useState(null);
const throttledDetect = useRef(_.throttle((net) => detect(net), 200)).current;
useEffect(() => {
runPosenet();
}, []);
// Load posenet
const runPosenet = async () => {
const net = await posenet.load({
inputResolution: { width: 320, height: 240 },
scale: 0.8,
});
//
const detectFrame = () => {
throttledDetect(net);
requestAnimationFrame(detectFrame);
};
detectFrame();
};
const detect = async (net) => {
if (
typeof webcamRef.current !== "undefined" &&
webcamRef.current !== null &&
webcamRef.current.video.readyState === 4
) {
// Get Video Properties
const video = webcamRef.current.video;
const videoWidth = webcamRef.current.video.videoWidth;
const videoHeight = webcamRef.current.video.videoHeight;
// Set video width
webcamRef.current.video.width = videoWidth;
webcamRef.current.video.height = videoHeight;
// Make Detections
const pose = await net.estimateSinglePose(video);
let left_shoulder = pose.keypoints[5].position;
let left_elbow = pose.keypoints[7].position;
let left_wrist = pose.keypoints[9].position;
if (left_shoulder && left_elbow && left_wrist) {
setPoseData([
(poseData.leftShoulder = left_shoulder),
(poseData.leftElbow = left_elbow),
(poseData.leftWrist = left_wrist),
]);
const angle = calculateAngle(
poseData.leftShoulder,
poseData.leftElbow,
poseData.leftWrist
);
console.log(angle);
// Bicep curl counter logic
if (angle > 160 && stage !== "down") {
setStage("down");
}
if (angle < 30 && stage === "down") {
setStage("up");
setCounter((prevCounter) => {
console.log(prevCounter + 1);
return prevCounter + 1;
});
}
}
drawCanvas(pose, video, videoWidth, videoHeight, canvasRef);
}
};
const drawCanvas = (pose, video, videoWidth, videoHeight, canvas) => {
const ctx = canvas.current.getContext("2d");
canvas.current.width = videoWidth;
canvas.current.height = videoHeight;
drawKeypoints(pose["keypoints"], 0.6, ctx);
drawSkeleton(pose["keypoints"], 0.7, ctx);
};
const calculateAngle = (a, b, c) => {
a = [a.x, a.y]; // Convert to array
b = [b.x, b.y];
c = [c.x, c.y];
const radians =
Math.atan2(c[1] - b[1], c[0] - b[0]) -
Math.atan2(a[1] - b[1], a[0] - b[0]);
let angle = Math.abs((radians * 180.0) / Math.PI);
if (angle > 180.0) {
angle = 360 - angle;
}
return angle;
};
return (
<div className='App'>
<header className='App-header'>
<Webcam
ref={webcamRef}
style={{
position: "absolute",
marginLeft: "auto",
marginRight: "auto",
left: 0,
right: 0,
textAlign: "center",
zindex: 9,
width: 640,
height: 480,
}}
/>
<canvas
ref={canvasRef}
style={{
position: "absolute",
marginLeft: "auto",
marginRight: "auto",
left: 0,
right: 0,
textAlign: "center",
zindex: 9,
width: 640,
height: 480,
}}
/>
</header>
</div>
);
};
export default Detection;
I expected to get the value of counter in the console. But only the real time values of the angle is being displayed.