Bicep curl counter not working in react js application using tensorflow js(posenet) model

29 Views Asked by At

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.

0

There are 0 best solutions below