Side-Lying-Leg-Lift Exercise Detection Using MediaPipe OpenCV Python

Muhammad Faisal
20 min readMay 8, 2023

--

What is MediaPipe?

Google created the open-source MediaPipe framework, which offers a customised pipeline for creating real-time video processing pipelines. Developers may build unique pipelines for a variety of use cases, including object detection and tracking, hand and facial identification, position estimation, and more, thanks to the set of pre-built components and flexible architecture it offers. Input sources supported by MediaPipe include video, camera feeds, and picture files. Output formats supported by MediaPipe include images, movies, and data streams. It can be linked with well-known machine learning frameworks like TensorFlow and PyTorch and is frequently used in the domains of computer vision, machine learning, and robotics.

What is Machine Vision (OpenCV Library)?

A well-known open-source computer vision and machine learning software library is called OpenCV. For real-time computer vision applications like image and video processing, object detection, object tracking, and machine learning, it offers a set of programming tools. Originally created by Intel Corporation in 1999, OpenCV is now maintained by a sizable development community. OpenCV is compatible with many programming languages and operating systems, including Windows, Linux, Mac OS, Android, and iOS. These include C++, Python, Java, and MATLAB.

SOME EXAPMPES:

Hand Tracking:

The Hand Tracking solution of MediaPipe employs machine learning (ML) to infer 21 3D landmarks of a hand from just a single frame. This solution can form the basis for sign language understanding and hand gesture control, and can also enable the overlay of digital content and information on top of the physical world in augmented reality. The details of 21 landmarks are explained here:

Landmarks detail of Hand
Sample Hand Tracking by Hand Tracking Solution of MediaPipe

Human Pose Detection & Tracking:

Similar to Hand Tracking, this solution tracks the full-body pose with 32 3D landmarks as shown here:

Human Pose Landmarks Detail

This solution can be used in pose detection/classification for so many human activity related domains. An example estimation is shown in the following figures:

Example of Human Pose Detection

The Project Details:

Pose detection technology has been rapidly advancing in recent years, allowing for the development of a wide range of applications. One such application is the detection of specific exercises during workouts to ensure proper form and reduce the risk of injury.

Our project aims to utilize the pose detection module of Mediapipe to detect the Side Lying Leg Lift exercise and display the correct exercise on a live camera or video.

Introduction:

Side Lying Leg Lift is a popular exercise for strengthening the hip abductors and gluteus medius muscles. The proper form of this exercise is important to get the maximum benefit from it and avoid any injury. In this project, we have developed a pose detection system using Mediapipe to detect the Side Lying Leg Lift exercise and display the correct posture on live camera or video.

Side Lying Leg Lift Example
Side Lying Leg Lift Example

Methodology:

We used Python and the Mediapipe library to build the pose detection system. The Mediapipe library provides pre-trained models for detecting the human body and various body parts, including the hip and the legs. We utilized these pre-trained models to detect the body and body parts in real-time video or live camera feed.

The first step of the process is to capture the video feed from the camera or load a video file. We used OpenCV, a popular computer vision library, to capture video feed from the camera or load a video file.

Next, we used the Mediapipe Pose model to detect the key points of the human body in the video or camera feed. We then identified the body parts required to detect the Side Lying Leg Lift exercise, including the hip, the leg, and the ankle.

After identifying these body parts, we calculated the angle between the hip, the knee, and the ankle to determine the leg’s position. Based on the angle, we can determine whether the leg is in the correct position or not. If the leg is in the correct position, we display the correct posture on the screen. If the leg is not in the correct position, we display an error message on the screen.

Results:

Our system is capable of detecting the Side Lying Leg Lift exercise and displaying the correct posture on live camera or video. The system accurately detects the leg’s position and determines whether the leg is in the correct position or not. The system can be used by anyone, regardless of their fitness level, to ensure that they are performing the exercise correctly and getting the maximum benefit from it.

Conclusion:

In conclusion, our project demonstrates the use of Mediapipe in detecting the Side Lying Leg Lift exercise and displaying the correct posture on live camera or video. This project can be extended to detect other exercises and improve the accuracy of the system. The use of computer vision in fitness can enhance the fitness experience and ensure that individuals are performing the exercises correctly and safely.

Code Implementation in Python:

Step 1: Importing Libraries

# Importing Libraries
import cv2
import mediapipe as mp
import numpy as np
import math

Step 2: Defining Mediapipe Holistic Module

mp_drawing = mp.solutions.drawing_utils    # Assigning drawing_utils from mediapipe as mp_drawing
mp_holistic = mp.solutions.holistic # Assigning holistic from mediapipe as mp_holistic

Step 3: Angle Calculation Function Using Joint Coordinates

This is a function that calculates the angle between two lines given their endpoints. It takes in six parameters: the x and y coordinates of the first point on the first line (x1 and y1), the x and y coordinates of the second point on the first line (x2 and y2), and the x and y coordinates of the third point on the second line (x3 and y3).

First, the function calculates the slopes of the two lines using the slope formula (y2-y1)/(x2-x1) and (y3-y2)/(x3-x2). Then, it uses the arctangent function (math.atan2) to calculate the angle between the two lines using their slopes. Finally, it converts the angle from radians to degrees using the math.degrees function and returns it.

def angle_between_lines(x1, y1, x2, y2, x3, y3):         # Defining a function to calculate angle between lines
# Calculate the slopes of the two lines
slope1 = (y2 - y1) / (x2 - x1)
slope2 = (y3 - y2) / (x3 - x2)

# Calculate the angle between the two lines
angle = math.atan2(slope2 - slope1, 1 + slope1 * slope2) # Calculate the angle using the slopes

# Convert the angle to degrees and return it
return math.degrees(angle)

The exercise movement and the number of repetitions are tracked using these variables. Each time a full repeat of the exercise is discovered, the leglift variable will be increased from its initial value of 0. Three boolean flags called count1, count2, and count3 will be utilised to track the various positions needed for the exercise movement.

leglift = 0           # Initialize a variable to count the number of leg lifts
count1 = False # Initialize a boolean variable to keep track of the first position
count2 = False # Initialize a boolean variable to keep track of the second position
count3 = False # Initialize a boolean variable to keep track of the third position

Main Code Block

This marks the beginning of the main code block, which initialises the Mediapipe Holistic model with the lowest detection and tracking confidence before recording the video from the chosen file or webcam.

When we’re through with the model, the resources are immediately released using the with statement. Initialising the video capture from the “sidelyinglegliftvideo.mp4” file is done by the cv2.VideoCapture function. Alternately, by uncommenting the commented line and uncommenting the preceding line, we can record the webcam’s video (0).

In order to identify the side lying leg lift exercise, we will feed this video into the model as an input.

# Initializing the Holistic model with minimum detection and tracking confidence
with mp_holistic.Holistic(min_detection_confidence=0.5, min_tracking_confidence=0.5) as holistic:

cap = cv2.VideoCapture('sidelyinglegliftvideo.mp4') # Start capturing the video from the file "sidelyinglegliftvideo.mp4"
# cap = cv2.VideoCapture(0) # Alternatively, we can capture the video from the webcam (0)

This code block retrieves the coordinates of the left and right hips and knees after reading frames from a video capture and using the Holistic model to identify landmarks in each frame.

A frame is first read from the video capture by the cap.read() function and allocated to the frame variable. Then, the frame is changed from BGR to RGB, which is the colour space that the Holistic model needs as input, using the cv2.cvtColor() function.

The Holistic model is then applied to the image using the holistic.process() method in order to identify landmarks, and the outcomes are saved in the results variable. The 33 3D landmarks of the pose, 21 3D landmarks of the left hand, and 21 3D landmarks of the right hand were all detected.A copy of the image is then created and saved in annotated_image. Then, using mp_holistic, the mp_drawing.draw_landmarks() function is used to draw the identified landmarks on the annotated_image.To doodle lines tying the landmarks together, use POSE_CONNECTIONS.

The outcomes are next.pose_landmarks.The left_hip, right_hip, left_knee, and right_knee variables are used to hold the coordinates of the left and right hip and knee landmarks, respectively.

The subsequent steps in the algorithm make use of these landmarks to identify the side-lying leg stance and determine how many leg lifts the subject in the video has executed.

    while cap.isOpened():                # While the video is being captured
ret, frame = cap.read() # Read the frame from the video

image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # Convert the image to RGB

results = holistic.process(image) # Make a detection using the Holistic model on the image

annotated_image = image.copy() # Make a copy of the image to draw landmarks on

mp_drawing.draw_landmarks(annotated_image, results.pose_landmarks, mp_holistic.POSE_CONNECTIONS) # Draw the detected landmarks on the image

left_hip = results.pose_landmarks.landmark[mp_holistic.PoseLandmark.LEFT_HIP] # Get the coordinates of the left hip
right_hip = results.pose_landmarks.landmark[mp_holistic.PoseLandmark.RIGHT_HIP] # Get the coordinates of the right hip

midpoint = ((left_hip.x + right_hip.x) / 2, (left_hip.y + right_hip.y) / 2) # Calculate the midpoint between the left hip and right hip

left_knee = results.pose_landmarks.landmark[mp_holistic.PoseLandmark.LEFT_KNEE] # Get the coordinates
right_knee = results.pose_landmarks.landmark[mp_holistic.PoseLandmark.RIGHT_KNEE]

Calculating the angle between the lines produced by the left knee, the halfway between the left hip and the right hip, and the right knee as well as keeping track of how many leg lifts the individual in the video performs are the responsibilities of this code block.

The angle_between_lines() function, which accepts the coordinates of the left knee, the midpoint, and the right knee as input and returns the angle in degrees, is used to determine the angle between the lines. To establish whether the user is lifting their leg or not, the angle is then compared to specific criteria. The leg is being lifted if the angle is greater than 60 degrees. higher than 100 degrees indicates that the leg is bent.The leg has been raised to its highest point if the angle is greater than 100 degrees; otherwise, it has been brought back to the ground if the angle is less than 60 degrees.

The leg position is recorded using the variables count1, count2, and count3, and the number of leg lifts is recorded using the variable leglift. Every time a full leg lift is executed, the code block increases the leglift counter and then resets the count1, count2, and count3 variables to begin counting the subsequent leg lift.

The current number of leg lifts is kept in the variable lg, which can be used for output or subsequent processing.

      angle1 = angle_between_lines(left_knee.x, left_knee.y, midpoint[0], midpoint[1], right_knee.x, right_knee.y)
print("Angles :",angle1)

if (angle1 > 60):
count1 = True
if (count1 == True and angle1 > 100):
count2 = True
if (count2 == True and angle1 < 60):
count3 = True
if (count1 == True and count2 == True and count3 == True):
leglift = leglift + 1
count1 = False
count2 = False
count3 = False
lg = leglift

Here, the number of leg lifts being tallied is shown using the print command. Every time a full leg lift action is discovered, the leglift variable is increased.

The hips’ midpoint — calculated as the intersection of the left and right hip coordinates — are marked with a circle using the cv2.circle function. The annotated_image variable, a copy of the original image with the identified landmarks drawn on it, is used to draw the circle. The dimensions of the image are obtained from the annotated_image.shape attribute and the midpoint coordinates’ floating-point values are converted to integers using the int function. The circle’s colour is defined as (255, 0, 0), which is equivalent to the thickness is adjusted to -1 to fill the circle, which is coloured blue in the RGB colour space.

print("Leg Lift : ",leglift)
# Draw a circle at the midpoint
cv2.circle(annotated_image, (int(midpoint[0] * annotated_image.shape[1]), int(midpoint[1] * annotated_image.shape[0])), 5, (255, 0, 0), -1)

Correct Angle:

This code block uses the OpenCV method cv2.putText() to show either “Correct Side Lying Leg Lift Exercise” or “Incorrect Side Lying Leg Lift Exercise” on the image depending on whether the angle between the left knee, midway, and right knee is between 68.85 and 80 degrees.

The phrase “Correct Side Lying Leg Lift Exercise” appears on the screen when the angle is between 68.85 and 80 degrees, indicating that the exercise is being done properly. The message “Incorrect Side Lying Leg Lift Exercise” is presented if the angle is outside of this range, indicating that the exercise is not being done correctly.

To make sure they are completing the exercise correctly and preventing injury, people can find this feedback helpful.

        # check if angle is between 68.85 to 80 and display "Correct Exercise" on screen
if 68.85 <= angle1 <= 80:
cv2.putText(annotated_image, "Correct Side Lying Leg Lift Exercise", (20, 110), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
else:
cv2.putText(annotated_image, "Incorrect Side Lying Leg Lift Exercise", (20, 110), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

This code is a computer vision program that uses the OpenCV library to detect and track the human pose in a video. It is specifically designed to detect and track the Side Lying Leg Lift exercise.

The code first opens the video file and reads each frame of the video. It then converts each frame from the default color space (BGR) to RGB color space to be used by the Holistic model.

The Holistic model is then used to make detections of human poses in each frame. The resulting landmarks are used to identify the key points of the pose, such as the hip and knee joints.

The code then calculates the angle between the left knee and the right knee relative to the midpoint between the left and right hip. It checks whether the angle is within a certain range and counts the number of correct leg lifts.

Finally, the program displays the angle and leg lift count on the screen, as well as whether the exercise is being performed correctly or not.

Overall, this program is a good example of how computer vision can be used to track human poses and movements in real-time. It can be used to automatically monitor and assess exercise routines, and provide feedback to the user to help them improve their form.

        # Display the value of angle1 and leglift on the output screen
cv2.putText(annotated_image, "Angle: " + str(round(angle1, 2)), (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
# Display the value of angle1 and leglift on the output screen
cv2.putText(annotated_image, "Leg Lift: " + str(round(lg, 2)), (20, 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)

The annotated image with the identified landmarks and the text indicating whether the exercise is being carried out correctly or poorly are displayed using the cv2.imshow() function. The function’s first argument is the window name, which is currently set to “MediaPipe Holistic”. The annotated image itself serves as the second argument. The feature shows the image on the screen in a window. Until the cv2.waitKey() function is used, the window is active.

        # Show the annotated image
cv2.imshow('MediaPipe Holistic', annotated_image)

This line of code checks if the user has pressed the ‘q’ key on their keyboard. If the user has pressed the ‘q’ key, the code breaks out of the while loop and the program stops running. This is a common technique used to terminate programs that are running indefinitely or in a loop.

        # Exit if the user presses the 'q' key
if cv2.waitKey(10) & 0xFF == ord('q'):
break

Final Solution:

This is the final part of the code that releases the webcam and closes the window once the video is done being processed. The cap.release() line releases the capture object and frees up the webcam, while cv2.destroyAllWindows() destroys all the windows that were created in the program. This ensures that no resources are being held up unnecessarily after the program is done executing.


# Release the webcam and close the window
cap.release()
cv2.destroyAllWindows()

COMPLETE CODE IN PYTHON:

# Registratioin Number : 2021-MC-77
# Name : Muhammad Faisal
# Registratioin Number : 2021-MC-61
# Name : Muhammad Ahmad
# Section : B
# Home Work : PBL - CP - II
# Date : 8th May 2023
# Submitted To : Sir Doctor Muhammad Ahsan Naeem

# Importing Libraries
import cv2
import mediapipe as mp
import numpy as np
import math

mp_drawing = mp.solutions.drawing_utils # Assigning drawing_utils from mediapipe as mp_drawing
mp_holistic = mp.solutions.holistic # Assigning holistic from mediapipe as mp_holistic

def angle_between_lines(x1, y1, x2, y2, x3, y3): # Defining a function to calculate angle between lines
# Calculate the slopes of the two lines
slope1 = (y2 - y1) / (x2 - x1)
slope2 = (y3 - y2) / (x3 - x2)

# Calculate the angle between the two lines
angle = math.atan2(slope2 - slope1, 1 + slope1 * slope2) # Calculate the angle using the slopes

# Convert the angle to degrees and return it
return math.degrees(angle) # Return the angle in degrees

leglift = 0 # Initialize a variable to count the number of leg lifts
count1 = False # Initialize a boolean variable to keep track of the first position
count2 = False # Initialize a boolean variable to keep track of the second position
count3 = False # Initialize a boolean variable to keep track of the third position

# Initializing the Holistic model with minimum detection and tracking confidence
with mp_holistic.Holistic(min_detection_confidence=0.5, min_tracking_confidence=0.5) as holistic:

cap = cv2.VideoCapture('sidelyinglegliftvideo.mp4') # Start capturing the video from the file "sidelyinglegliftvideo.mp4"
# cap = cv2.VideoCapture(0) # Alternatively, we can capture the video from the webcam (0)

while cap.isOpened(): # While the video is being captured
ret, frame = cap.read() # Read the frame from the video

image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) # Convert the image to RGB

results = holistic.process(image) # Make a detection using the Holistic model on the image

annotated_image = image.copy() # Make a copy of the image to draw landmarks on

mp_drawing.draw_landmarks(annotated_image, results.pose_landmarks, mp_holistic.POSE_CONNECTIONS) # Draw the detected landmarks on the image

left_hip = results.pose_landmarks.landmark[mp_holistic.PoseLandmark.LEFT_HIP] # Get the coordinates of the left hip
right_hip = results.pose_landmarks.landmark[mp_holistic.PoseLandmark.RIGHT_HIP] # Get the coordinates of the right hip

midpoint = ((left_hip.x + right_hip.x) / 2, (left_hip.y + right_hip.y) / 2) # Calculate the midpoint between the left hip and right hip

left_knee = results.pose_landmarks.landmark[mp_holistic.PoseLandmark.LEFT_KNEE] # Get the coordinates
right_knee = results.pose_landmarks.landmark[mp_holistic.PoseLandmark.RIGHT_KNEE]

angle1 = angle_between_lines(left_knee.x, left_knee.y, midpoint[0], midpoint[1], right_knee.x, right_knee.y)
print("Angles :",angle1)

if (angle1 > 60):
count1 = True
if (count1 == True and angle1 > 100):
count2 = True
if (count2 == True and angle1 < 60):
count3 = True
if (count1 == True and count2 == True and count3 == True):
leglift = leglift + 1
count1 = False
count2 = False
count3 = False
lg = leglift

print("Leg Lift : ",leglift)
# Draw a circle at the midpoint
cv2.circle(annotated_image, (int(midpoint[0] * annotated_image.shape[1]), int(midpoint[1] * annotated_image.shape[0])), 5, (255, 0, 0), -1)

# check if angle is between 68.85 to 80 and display "Correct Exercise" on screen
if 68.85 <= angle1 <= 80:
cv2.putText(annotated_image, "Correct Side Lying Leg Lift Exercise", (20, 110), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
else:
cv2.putText(annotated_image, "Incorrect Side Lying Leg Lift Exercise", (20, 110), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

# Display the value of angle1 and leglift on the output screen
cv2.putText(annotated_image, "Angle: " + str(round(angle1, 2)), (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
# Display the value of angle1 and leglift on the output screen
cv2.putText(annotated_image, "Leg Lift: " + str(round(lg, 2)), (20, 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)

# Show the annotated image
cv2.imshow('MediaPipe Holistic', annotated_image)

# Exit if the user presses the 'q' key
if cv2.waitKey(10) & 0xFF == ord('q'):
break

# Release the webcam and close the window
cap.release()
cv2.destroyAllWindows()

Results using this code:

Incorrect Exercise
Correct Exercise

Compltete code using Class(OOP) Method:

What is OOP?

OOP stands for Object-Oriented Programming. It is a programming paradigm that focuses on creating reusable and modular code by organizing data and code into objects, which can interact with one another to accomplish tasks. In OOP, an object is an instance of a class, which defines a set of attributes (data) and methods (functions) that describe the object’s behavior and interactions with other objects. OOP is widely used in modern programming languages like Python, Java, C++, and Ruby, among others, and offers benefits such as encapsulation, inheritance, and polymorphism.

Why OOP?

Object-Oriented Programming (OOP) offers several advantages over other programming paradigms such as procedural programming. Here are some reasons why OOP is used:

  1. Modularity: OOP breaks down complex programming problems into smaller, more manageable problems by dividing a large program into smaller objects. These objects can be developed and tested independently, making the overall development process more manageable and efficient.
  2. Reusability: OOP allows developers to create reusable code through inheritance. Inheritance enables new classes to be derived from existing classes, which means that the new classes inherit all of the attributes and methods of the original class. This reduces the amount of code that needs to be written and makes maintenance easier.
  3. Encapsulation: OOP provides a way to encapsulate data and behavior within an object. This means that the internal workings of an object can be hidden from other parts of the program, making it easier to maintain and update the code.
  4. Abstraction: OOP allows developers to create abstract classes and interfaces that define the behavior of objects without providing any implementation details. This helps to reduce complexity and makes the code more flexible and adaptable.
  5. Polymorphism: OOP allows different objects to respond to the same message in different ways. This makes it possible to write code that can work with objects of different classes, making the code more flexible and extensible.
# Registratioin Number : 2021-MC-77
# Name : Muhammad Faisal
# Registratioin Number : 2021-MC-61
# Name : Muhammad Ahmad
# Section : B
# Home Work : PBL - CP - II
# Date : 8th May 2023
# Submitted To : Sir Doctor Muhammad Ahsan Naeem

import cv2
import mediapipe as mp
import numpy as np
import math

def angle_between_lines(x1, y1, x2, y2, x3, y3): # Defining a function to calculate angle between lines
# Calculate the slopes of the two lines
slope1 = (y2 - y1) / (x2 - x1)
slope2 = (y3 - y2) / (x3 - x2)

# Calculate the angle between the two lines
angle = math.atan2(slope2 - slope1, 1 + slope1 * slope2) # Calculate the angle using the slopes

# Convert the angle to degrees and return it
return math.degrees(angle) # Return the angle in degrees

class LegLiftDetector:
def __init__(self, video_path, min_detection_confidence=0.5, min_tracking_confidence=0.5):
self.mp_drawing = mp.solutions.drawing_utils
self.mp_holistic = mp.solutions.holistic
self.leg_lift_count = 0
self.count1 = False
self.count2 = False
self.count3 = False

self.cap = cv2.VideoCapture("sidelyinglegliftvideo.mp4")
self.holistic = self.mp_holistic.Holistic(min_detection_confidence=min_detection_confidence, min_tracking_confidence=min_tracking_confidence)

def run(self):
while self.cap.isOpened():
ret, frame = self.cap.read()
if not ret:
break

image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = self.holistic.process(image)

annotated_image = image.copy()
self.mp_drawing.draw_landmarks(annotated_image, results.pose_landmarks, self.mp_holistic.POSE_CONNECTIONS)

left_hip = results.pose_landmarks.landmark[self.mp_holistic.PoseLandmark.LEFT_HIP]
right_hip = results.pose_landmarks.landmark[self.mp_holistic.PoseLandmark.RIGHT_HIP]

midpoint = ((left_hip.x + right_hip.x) / 2, (left_hip.y + right_hip.y) / 2)

left_knee = results.pose_landmarks.landmark[self.mp_holistic.PoseLandmark.LEFT_KNEE]
right_knee = results.pose_landmarks.landmark[self.mp_holistic.PoseLandmark.RIGHT_KNEE]

angle1 = angle_between_lines(left_knee.x, left_knee.y, midpoint[0], midpoint[1], right_knee.x, right_knee.y)

if (angle1 > 60):
self.count1 = True
if (self.count1 == True and angle1 > 100):
self.count2 = True
if (self.count2 == True and angle1 < 60):
self.count3 = True
if (self.count1 == True and self.count2 == True and self.count3 == True):
self.leg_lift_count = self.leg_lift_count + 1
self.count1 = False
self.count2 = False
self.count3 = False

print("Leg Lift : ",self.leg_lift_count)

cv2.circle(annotated_image, (int(midpoint[0] * annotated_image.shape[1]), int(midpoint[1] * annotated_image.shape[0])), 5, (255, 0, 0), -1)

if 68.85 <= angle1 <= 80:
cv2.putText(annotated_image, "Correct Side Lying Leg Lift Exercise", (20, 110), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
else:
cv2.putText(annotated_image, "Incorrect Side Lying Leg Lift Exercise", (20, 110), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)

cv2.putText(annotated_image, "Angle: " + str(round(angle1, 2)), (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
# # Display the value of angle1 and leglift on the output screen
# cv2.putText(annotated_image, "Leg Lift: " + str(round(lg, 2)), (20, 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
cv2.putText(annotated_image, "Leg Lift: " + str(round(self.leg_lift_count, 2)), (20, 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)

# Show the annotated image
cv2.imshow('MediaPipe Holistic', annotated_image)

# Exit if the user presses the 'q' key
if cv2.waitKey(10) & 0xFF == ord('q'):
break

# Release the webcam and close the window
cap.release()
cv2.destroyAllWindows()

detector = LegLiftDetector('sidelyinglegliftvideo.mp4')
detector.run()

Final Complete Code Using Class(OOP) and GUI:

What is GUI?

GUI stands for Graphical User Interface. It is a type of user interface that allows users to interact with electronic devices or software through graphical elements such as icons, buttons, and windows, rather than through text commands.

GUIs are used in many types of software, including operating systems, web browsers, and office productivity suites. They provide a more intuitive and user-friendly way to interact with complex software, making it easier for users to perform tasks and access features.

GUIs typically include visual components such as menus, toolbars, buttons, text boxes, and dialog boxes. Users interact with these components using a mouse, keyboard, or touch screen. The graphical elements and layout of a GUI can vary widely depending on the software and the preferences of the developer, but the general goal is to make the software easy to use and navigate.

Why GUI in this code?

GUI is used in this code to provide a graphical user interface for the user to interact with the LegLiftDetector class and its methods. The GUI is created using the tkinter library and provides buttons for starting, stopping, and uploading a video, as well as labels to display the leg lift count and the angle of the leg lift exercise. Additionally, the GUI displays the video frames processed by the LegLiftDetector class, which are annotated with the pose landmarks and the angle of the leg lift. The GUI also provides a visual indication of whether the leg lift is being performed correctly, by changing the color of the angle label to red when the angle falls within the correct range.

## Class Method with GUI 
import cv2
import mediapipe as mp
import numpy as np
import math
import tkinter as tk
from PIL import Image, ImageTk
import threading
from tkinter import filedialog

class LegLiftDetectorGUI:
def __init__(self, master, video_path, min_detection_confidence=0.5, min_tracking_confidence=0.5):
self.mp_drawing = mp.solutions.drawing_utils
self.mp_holistic = mp.solutions.holistic
self.leg_lift_count = 0
self.count1 = False
self.count2 = False
self.count3 = False

self.cap = cv2.VideoCapture(video_path)
self.holistic = self.mp_holistic.Holistic(min_detection_confidence=min_detection_confidence, min_tracking_confidence=min_tracking_confidence)

self.master = master
self.master.title("Side Lying Leg Lift Detector")

self.canvas = tk.Canvas(self.master, width=640, height=480)
self.canvas.pack()

self.button_frame = tk.Frame(self.master)
self.button_frame.pack(side=tk.LEFT)

self.start_button = tk.Button(self.button_frame, text="Start", command=self.start_video, width=10, height=4, bg="yellow", font=("Arial", 12, "bold"))
self.start_button.pack(side=tk.LEFT)

self.stop_button = tk.Button(self.button_frame, text="Stop", command=self.stop_video, width=10, height=4, bg="red", font=("Arial", 12, "bold"))
self.stop_button.pack(side=tk.LEFT)

self.upload_button = tk.Button(self.button_frame, text="Upload Video", command=self.upload_video, width=10, height=4, bg="green", font=("Arial", 12, "bold"))
self.upload_button.pack(side=tk.LEFT)

self.leg_lift_count_label = tk.Label(self.master, text="Leg Lift Count: 0", foreground="black", font=("Arial", 12, "bold"))
self.leg_lift_count_label.pack(side=tk.LEFT, anchor=tk.CENTER)

self.angle_label = tk.Label(self.master, text="Angle: 0", foreground="blue", font=("Arial", 12, "bold"))
self.angle_label.pack(side=tk.BOTTOM, anchor=tk.CENTER)

self.leg_lift_image = None
self.video_running = False
self.update_video()

def upload_video(self):
file_path = filedialog.askopenfilename()
if file_path:
self.cap = cv2.VideoCapture(file_path)

def increment_leg_lift_count(self,angle1,count1,count2,count3):
if (angle1 > 60):
self.count1 = True
if (self.count1 == True and angle1 > 100):
self.count2 = True
if (self.count2 == True and angle1 < 60):
self.count3 = True
if (self.count1 == True and self.count2 == True and self.count3 == True):
self.leg_lift_count = self.leg_lift_count + 1
self.count1 = False
self.count2 = False
self.count3 = False
self.leg_lift_count_label.config(text="Leg Lift Count: {}".format(self.leg_lift_count))

def start_video(self):
self.video_running = True
# Start a new thread to read and display video frames continuously
threading.Thread(target=self.update_video).start()

def stop_video(self):
self.video_running = False

def update_video(self):
ret, frame = self.cap.read()
if ret:
image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = self.holistic.process(image)

annotated_image = image.copy()
self.mp_drawing.draw_landmarks(annotated_image, results.pose_landmarks, self.mp_holistic.POSE_CONNECTIONS)

left_hip = results.pose_landmarks.landmark[self.mp_holistic.PoseLandmark.LEFT_HIP]
right_hip = results.pose_landmarks.landmark[self.mp_holistic.PoseLandmark.RIGHT_HIP]

midpoint = ((left_hip.x + right_hip.x) / 2, (left_hip.y + right_hip.y) / 2)

left_knee = results.pose_landmarks.landmark[self.mp_holistic.PoseLandmark.LEFT_KNEE]
right_knee = results.pose_landmarks.landmark[self.mp_holistic.PoseLandmark.RIGHT_KNEE]

angle1 = angle_between_lines(left_knee.x, left_knee.y, midpoint[0], midpoint[1], right_knee.x, right_knee.y)

self.increment_leg_lift_count(angle1,count1,count2,count3)

self.angle_label.config(text="Angle: {:.2f}".format(angle1))

cv2.circle(annotated_image, (int(midpoint[0] * annotated_image.shape[1]), int(midpoint[1] * annotated_image.shape[0])), 5, (255, 0, 0), -1)

if angle1 >= 100 and angle1 <= 120:
self.angle_label.config(fg="red", text="Angle: {:.2f}\nCorrect Exercise".format(angle1), font=("Arial", 28, "bold"))
self.increment_leg_lift_count(angle1,count1,count2,count3)
else:
self.angle_label.config(fg="black", text="Angle: {:.2f}\nIncorrect Exercise".format(angle1), font=("Arial", 28, "bold"))

# Resize the image to match the size of the canvas
resized_image = cv2.resize(annotated_image, (640, 480))
self.leg_lift_image = ImageTk.PhotoImage(Image.fromarray(resized_image))
self.canvas.create_image(0, 0, anchor=tk.NW, image=self.leg_lift_image)

if self.video_running:
self.master.after(10, self.update_video)

def __del__(self):
self.cap.release()
cv2.destroyAllWindows()

def angle_between_lines(x1, y1, x2, y2, x3, y3):
slope1 = (y2 - y1) / (x2 - x1)
slope2 = (y3 - y2) / (x3 - x2)
angle = math.atan2(slope2 - slope1, 1 + slope1 * slope2)
return math.degrees(angle)

if __name__ == "__main__":
root = tk.Tk()
count1 = False
count2 = False
count3 = False
app = LegLiftDetectorGUI(root, 0)
root.configure(background='purple')
root.mainloop()
Correct Exercise Detection using GUI
Incorrect Exercise Detection using GUI

COMPLETE CODE ON GITHUB GIST:

https://gist.github.com/faisal-777/3d59d85f99cd0454ee79a4cc9af53c14

REFERENCES:

https://quillbot.com/

https://chat.openai.com/

https://mediapipe.dev/index.html

OpenCV: OpenCV modules

https://youtu.be/01sAkU_NvOY

--

--