Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d16f12f

Browse files
author
Aditya Raj
committed
updated requirements, added streamlit to the stack
1 parent 5e46082 commit d16f12f

File tree

3 files changed

+204
-1
lines changed

3 files changed

+204
-1
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
.venv/
22
__pycache__/
3-
.DS_Store
3+
.DS_Store
4+
videos/
5+
processed_videos/

requirements.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
altair==5.4.1
2+
attrs==24.2.0
13
blinker==1.8.2
4+
cachetools==5.5.0
25
certifi==2024.8.30
36
charset-normalizer==3.4.0
47
click==8.1.7
@@ -10,36 +13,55 @@ Flask==3.0.3
1013
Flask-Cors==5.0.0
1114
fonttools==4.54.1
1215
fsspec==2024.10.0
16+
gitdb==4.0.11
17+
GitPython==3.1.43
1318
idna==3.10
1419
imageio==2.36.0
1520
imageio-ffmpeg==0.5.1
1621
itsdangerous==2.2.0
1722
Jinja2==3.1.4
23+
jsonschema==4.23.0
24+
jsonschema-specifications==2024.10.1
1825
kiwisolver==1.4.7
26+
markdown-it-py==3.0.0
1927
MarkupSafe==3.0.2
2028
matplotlib==3.9.2
29+
mdurl==0.1.2
2130
moviepy==1.0.3
2231
mpmath==1.3.0
32+
narwhals==1.10.0
2333
networkx==3.4.2
2434
numpy==1.26.4
2535
opencv-python==4.10.0.84
2636
packaging==24.1
2737
pandas==2.2.3
2838
pillow==10.3.0
2939
proglog==0.1.10
40+
protobuf==5.28.3
3041
psutil==6.1.0
3142
py-cpuinfo==9.0.0
43+
pyarrow==17.0.0
44+
pydeck==0.9.1
45+
Pygments==2.18.0
3246
pyparsing==3.2.0
3347
python-dateutil==2.9.0.post0
3448
pytz==2024.2
3549
PyYAML==6.0.2
50+
referencing==0.35.1
3651
requests==2.32.3
52+
rich==13.9.3
53+
rpds-py==0.20.0
3754
scipy==1.14.1
3855
seaborn==0.13.2
3956
six==1.16.0
57+
smmap==5.0.1
58+
streamlit==1.39.0
4059
sympy==1.13.1
60+
tenacity==9.0.0
61+
toml==0.10.2
4162
torch==2.5.0
4263
torchvision==0.20.0
64+
tornado==6.4.1
4365
tqdm==4.66.5
4466
typing_extensions==4.12.2
4567
tzdata==2024.2

streamlit.py

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import os
2+
import logging
3+
import cv2
4+
from ultralytics import YOLO
5+
import streamlit as st
6+
7+
# Set up logging
8+
logging.basicConfig(level=logging.DEBUG)
9+
10+
# Load YOLO models
11+
yolo_models = {
12+
'regular_deadlift': YOLO("muscleAi_weights/best.pt"),
13+
'sumo_deadlift': YOLO("muscleAi_weights/sumo_best.pt"),
14+
'squat': YOLO("muscleAi_weights/squats_best.pt"),
15+
'romanian_deadlift': YOLO("muscleAi_weights/best_romanian.pt"),
16+
"zercher_squat": YOLO("muscleAi_weights/zercher_best.pt"),
17+
"front_squat": YOLO("muscleAi_weights/front_squats_best.pt")
18+
}
19+
20+
# Function to check for injury risk
21+
def check_injury_risk(labels, exercise_type):
22+
if exercise_type in ['regular_deadlift', 'squat']:
23+
ibw_value = labels.get('ibw', 1.0)
24+
down_value = labels.get('down', 1.0)
25+
else:
26+
ibw_value = labels.get('up', 1.0)
27+
down_value = labels.get('down', 1.0)
28+
29+
return "stop right now to prevent injury" if ibw_value < 0.80 or down_value < 0.70 else "No significant risk"
30+
31+
# Function to draw keypoints on the frame
32+
def draw_keypoints(frame, keypoints):
33+
for point in keypoints:
34+
x, y = int(point[0]), int(point[1])
35+
cv2.circle(frame, (x, y), 5, (0, 255, 0), -1)
36+
return frame
37+
38+
# Function to process video with YOLO
39+
def process_video_with_yolo(video_path, exercise_type):
40+
processed_frames = []
41+
42+
yolo_model = yolo_models[exercise_type]
43+
44+
cap = cv2.VideoCapture(video_path)
45+
46+
if not cap.isOpened():
47+
st.error("Error opening video file")
48+
return None
49+
50+
last_ibw_label = None
51+
rep_count = 0
52+
rep_started = False
53+
54+
while True:
55+
ret, frame = cap.read()
56+
if not ret:
57+
break
58+
59+
results = yolo_model(source=frame, stream=True, conf=0.3)
60+
61+
for result in results:
62+
frame = result.orig_img
63+
64+
labels = {result.names[int(box.cls)]: float(box.conf) for box in result.boxes} if result.boxes is not None else {}
65+
injury_risk = check_injury_risk(labels, exercise_type)
66+
67+
current_ibw_label = labels.get('ibw') if exercise_type in ['regular_deadlift', 'squat'] else labels.get('up')
68+
69+
if last_ibw_label is not None and current_ibw_label is not None:
70+
if not rep_started:
71+
if last_ibw_label > 0.89 and current_ibw_label <= 0.89:
72+
rep_started = True
73+
else:
74+
if last_ibw_label <= 0.89 and current_ibw_label > 0.89:
75+
rep_count += 1
76+
rep_started = False
77+
78+
last_ibw_label = current_ibw_label
79+
80+
# Draw keypoints on the frame if available
81+
if hasattr(result, 'keypoints') and result.keypoints is not None:
82+
keypoints = result.keypoints.xy[0]
83+
frame = draw_keypoints(frame, keypoints)
84+
85+
cv2.putText(frame, f"Injury Risk: {injury_risk}", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
86+
cv2.putText(frame, f"Repetitions: {rep_count}", (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
87+
88+
processed_frames.append(frame)
89+
90+
cap.release()
91+
92+
return processed_frames
93+
94+
# Function to process live video stream
95+
def process_live_video(exercise_type):
96+
cap = cv2.VideoCapture(0)
97+
98+
if not cap.isOpened():
99+
st.error("Error opening webcam")
100+
return
101+
102+
stframe = st.empty()
103+
104+
last_ibw_label = None
105+
rep_count = 0
106+
rep_started = False
107+
108+
while True:
109+
ret, frame = cap.read()
110+
if not ret:
111+
break
112+
113+
results = yolo_models[exercise_type](source=frame, stream=True, conf=0.3)
114+
115+
for result in results:
116+
frame = result.orig_img
117+
118+
labels = {result.names[int(box.cls)]: float(box.conf) for box in result.boxes} if result.boxes is not None else {}
119+
injury_risk = check_injury_risk(labels, exercise_type)
120+
121+
current_ibw_label = labels.get('ibw') if exercise_type in ['regular_deadlift', 'squat'] else labels.get('up')
122+
123+
if last_ibw_label is not None and current_ibw_label is not None:
124+
if not rep_started:
125+
if last_ibw_label > 0.89 and current_ibw_label <= 0.89:
126+
rep_started = True
127+
else:
128+
if last_ibw_label <= 0.89 and current_ibw_label > 0.89:
129+
rep_count += 1
130+
rep_started = False
131+
132+
last_ibw_label = current_ibw_label
133+
134+
# Draw keypoints on the frame if available
135+
if hasattr(result, 'keypoints') and result.keypoints is not None:
136+
keypoints = result.keypoints.xy[0]
137+
frame = draw_keypoints(frame, keypoints)
138+
139+
cv2.putText(frame, f"Injury Risk: {injury_risk}", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
140+
cv2.putText(frame, f"Repetitions: {rep_count}", (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
141+
142+
# Update the Streamlit frame with the processed frame
143+
stframe.image(frame, channels="BGR")
144+
145+
cap.release()
146+
147+
# Streamlit UI
148+
st.title("Exercise Video Analysis")
149+
150+
exercise_type = st.selectbox("Select Exercise Type", list(yolo_models.keys()))
151+
152+
uploaded_file = st.file_uploader("Upload a Video", type=["mp4", "mov"])
153+
154+
if uploaded_file is not None:
155+
video_path = os.path.join('./videos', uploaded_file.name)
156+
157+
# Save uploaded video
158+
with open(video_path, "wb") as f:
159+
f.write(uploaded_file.getbuffer())
160+
161+
st.video(uploaded_file)
162+
163+
if st.button("Process Video"):
164+
processed_frames = process_video_with_yolo(video_path, exercise_type)
165+
166+
if processed_frames is not None:
167+
output_video_path = os.path.join('./processed_videos', f'processed_{uploaded_file.name}')
168+
out = cv2.VideoWriter(output_video_path, cv2.VideoWriter_fourcc(*'XVID'), 30,
169+
(processed_frames[0].shape[1], processed_frames[0].shape[0]))
170+
171+
for frame in processed_frames:
172+
out.write(frame)
173+
out.release()
174+
175+
st.success(f"Video processed successfully! You can download it [here](./processed_videos/processed_{uploaded_file.name})")
176+
177+
if st.button("Start Live Stream"):
178+
process_live_video(exercise_type)
179+

0 commit comments

Comments
 (0)