Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
|
@@ -23,6 +23,10 @@ TARGET_FPS = 6.0
|
|
| 23 |
# Minimum rep duration in seconds (keeps behavior stable when stride changes)
|
| 24 |
MIN_REP_SECONDS = 0.33
|
| 25 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 26 |
# Downscale only (no crop) for YOLO inference
|
| 27 |
# 640 is a safe default across varying camera angles.
|
| 28 |
MAX_INFER_SIDE = 640
|
|
@@ -132,15 +136,18 @@ def analyze_pushup_video_yolo(video_path: str, out_dir: str):
|
|
| 132 |
frame_stride = max(1, int(round(float(fps) / float(TARGET_FPS))))
|
| 133 |
effective_fps = float(fps) / float(frame_stride)
|
| 134 |
|
| 135 |
-
# Convert time-based
|
| 136 |
min_rep_frames = int(math.ceil(MIN_REP_SECONDS * effective_fps))
|
| 137 |
-
# Clamp so we don't reject real reps at low fps
|
| 138 |
min_rep_frames = max(2, min_rep_frames)
|
| 139 |
|
|
|
|
|
|
|
|
|
|
| 140 |
print(
|
| 141 |
f"[speed] video_fps={fps:.2f} target_fps={TARGET_FPS:.2f} "
|
| 142 |
f"stride={frame_stride} effective_fps={effective_fps:.2f} "
|
| 143 |
-
f"min_rep_frames={min_rep_frames}
|
|
|
|
| 144 |
)
|
| 145 |
|
| 146 |
# 1) First pass: compute angles + confs per sampled frame
|
|
@@ -204,12 +211,15 @@ def analyze_pushup_video_yolo(video_path: str, out_dir: str):
|
|
| 204 |
elif not np.any(mask):
|
| 205 |
raise RuntimeError("No valid pose angles detected.")
|
| 206 |
|
| 207 |
-
# Smooth
|
| 208 |
-
win =
|
| 209 |
-
win = max(
|
|
|
|
|
|
|
|
|
|
| 210 |
angles_smooth = savgol_filter(angles, win, 2)
|
| 211 |
|
| 212 |
-
# 2) Rep detection on smoothed angles
|
| 213 |
reps = []
|
| 214 |
state = "WAIT_DOWN"
|
| 215 |
rep_min = rep_max = rep_conf_sum = rep_len = rep_start = None
|
|
@@ -230,6 +240,11 @@ def analyze_pushup_video_yolo(video_path: str, out_dir: str):
|
|
| 230 |
rep_conf_sum += cf
|
| 231 |
rep_len += 1
|
| 232 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 233 |
if ang >= UP_ANGLE:
|
| 234 |
if rep_len >= min_rep_frames:
|
| 235 |
mean_cf = float(rep_conf_sum / rep_len)
|
|
@@ -369,4 +384,4 @@ with gr.Blocks(title="Pushup API (YOLO)") as demo:
|
|
| 369 |
)
|
| 370 |
|
| 371 |
if __name__ == "__main__":
|
| 372 |
-
demo.launch()
|
|
|
|
| 23 |
# Minimum rep duration in seconds (keeps behavior stable when stride changes)
|
| 24 |
MIN_REP_SECONDS = 0.33
|
| 25 |
|
| 26 |
+
# NEW (from our efficient logic): Maximum rep duration in seconds
|
| 27 |
+
# Prevents very long false reps when tracking fails.
|
| 28 |
+
MAX_REP_SECONDS = 8.0
|
| 29 |
+
|
| 30 |
# Downscale only (no crop) for YOLO inference
|
| 31 |
# 640 is a safe default across varying camera angles.
|
| 32 |
MAX_INFER_SIDE = 640
|
|
|
|
| 136 |
frame_stride = max(1, int(round(float(fps) / float(TARGET_FPS))))
|
| 137 |
effective_fps = float(fps) / float(frame_stride)
|
| 138 |
|
| 139 |
+
# Convert time-based rep duration limits to sampled frames (matches our efficient logic)
|
| 140 |
min_rep_frames = int(math.ceil(MIN_REP_SECONDS * effective_fps))
|
|
|
|
| 141 |
min_rep_frames = max(2, min_rep_frames)
|
| 142 |
|
| 143 |
+
max_rep_frames = int(math.ceil(MAX_REP_SECONDS * effective_fps))
|
| 144 |
+
max_rep_frames = max(min_rep_frames + 2, max_rep_frames)
|
| 145 |
+
|
| 146 |
print(
|
| 147 |
f"[speed] video_fps={fps:.2f} target_fps={TARGET_FPS:.2f} "
|
| 148 |
f"stride={frame_stride} effective_fps={effective_fps:.2f} "
|
| 149 |
+
f"min_rep_frames={min_rep_frames} max_rep_frames={max_rep_frames} "
|
| 150 |
+
f"infer_max_side={MAX_INFER_SIDE}"
|
| 151 |
)
|
| 152 |
|
| 153 |
# 1) First pass: compute angles + confs per sampled frame
|
|
|
|
| 211 |
elif not np.any(mask):
|
| 212 |
raise RuntimeError("No valid pose angles detected.")
|
| 213 |
|
| 214 |
+
# Smooth (updated to match our efficient logic: ~1 second window scaled by effective_fps)
|
| 215 |
+
win = int(round(effective_fps * 1.0))
|
| 216 |
+
win = max(5, win)
|
| 217 |
+
if win % 2 == 0:
|
| 218 |
+
win += 1
|
| 219 |
+
win = min(win, (len(angles) // 2) * 2 + 1)
|
| 220 |
angles_smooth = savgol_filter(angles, win, 2)
|
| 221 |
|
| 222 |
+
# 2) Rep detection on smoothed angles (updated to match our efficient logic)
|
| 223 |
reps = []
|
| 224 |
state = "WAIT_DOWN"
|
| 225 |
rep_min = rep_max = rep_conf_sum = rep_len = rep_start = None
|
|
|
|
| 240 |
rep_conf_sum += cf
|
| 241 |
rep_len += 1
|
| 242 |
|
| 243 |
+
# Abort absurdly long reps (tracking failure / stall)
|
| 244 |
+
if rep_len > max_rep_frames:
|
| 245 |
+
state = "WAIT_DOWN"
|
| 246 |
+
continue
|
| 247 |
+
|
| 248 |
if ang >= UP_ANGLE:
|
| 249 |
if rep_len >= min_rep_frames:
|
| 250 |
mean_cf = float(rep_conf_sum / rep_len)
|
|
|
|
| 384 |
)
|
| 385 |
|
| 386 |
if __name__ == "__main__":
|
| 387 |
+
demo.launch()
|