Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -133,6 +133,59 @@ def lbw_decision(ball_positions, full_trajectory, frames, pitch_point, impact_po
|
|
| 133 |
return f"Out (Ball hits stumps)", full_trajectory, pitch_point, impact_point
|
| 134 |
return f"Not Out (Missing stumps)", full_trajectory, pitch_point, impact_point
|
| 135 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
def draw_3d_scene(trajectory, pitch_point, impact_point, decision):
|
| 137 |
if not HAS_OPENGL:
|
| 138 |
return
|
|
@@ -198,6 +251,10 @@ def drs_review(video):
|
|
| 198 |
full_trajectory, vis_trajectory, pitch_point, pitch_frame, impact_point, impact_frame, trajectory_log = estimate_trajectory_3d(ball_positions, detection_frames, frames)
|
| 199 |
decision, full_trajectory, pitch_point, impact_point = lbw_decision(ball_positions, full_trajectory, frames, pitch_point, impact_point)
|
| 200 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 201 |
if HAS_OPENGL:
|
| 202 |
init_3d_window(800, 600)
|
| 203 |
from OpenGL.GLUT import glutInit, glutSolidSphere
|
|
@@ -206,9 +263,6 @@ def drs_review(video):
|
|
| 206 |
draw_3d_scene(full_trajectory, pitch_point, impact_point, decision)
|
| 207 |
event.pump()
|
| 208 |
|
| 209 |
-
output_path = f"output_{uuid.uuid4()}.mp4"
|
| 210 |
-
slow_motion_path = None # To be enhanced with 3D export
|
| 211 |
-
|
| 212 |
debug_output = f"{debug_log}\n{trajectory_log}"
|
| 213 |
return f"DRS Decision: {decision}\nDebug Log:\n{debug_output}", slow_motion_path
|
| 214 |
|
|
@@ -218,10 +272,10 @@ iface = gr.Interface(
|
|
| 218 |
inputs=gr.Video(label="Upload Video Clip"),
|
| 219 |
outputs=[
|
| 220 |
gr.Textbox(label="DRS Decision and Debug Log"),
|
| 221 |
-
gr.Video(label="
|
| 222 |
],
|
| 223 |
title="AI-Powered 3D DRS for LBW",
|
| 224 |
-
description="Upload a video clip for 3D DRS analysis with pitching (green), impact (red), and wickets (orange) visualization."
|
| 225 |
)
|
| 226 |
|
| 227 |
if __name__ == "__main__":
|
|
|
|
| 133 |
return f"Out (Ball hits stumps)", full_trajectory, pitch_point, impact_point
|
| 134 |
return f"Not Out (Missing stumps)", full_trajectory, pitch_point, impact_point
|
| 135 |
|
| 136 |
+
def generate_slow_motion(frames, vis_trajectory, pitch_point, pitch_frame, impact_point, impact_frame, detection_frames, output_path, decision, frame_width, frame_height):
|
| 137 |
+
if not frames:
|
| 138 |
+
return None
|
| 139 |
+
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
|
| 140 |
+
out = cv2.VideoWriter(output_path, fourcc, FRAME_RATE / SLOW_MOTION_FACTOR, (frame_width, frame_height))
|
| 141 |
+
|
| 142 |
+
trajectory_points = np.array([[p[0] * frame_width / PITCH_LENGTH, frame_height - (p[1] * frame_height / (STUMPS_HEIGHT * 2))] for p in vis_trajectory], dtype=np.int32).reshape((-1, 1, 2))
|
| 143 |
+
|
| 144 |
+
for i, frame in enumerate(frames):
|
| 145 |
+
# Draw stumps outline (scaled back to pixel coordinates)
|
| 146 |
+
stumps_x = frame_width / 2
|
| 147 |
+
stumps_y = frame_height * 0.8
|
| 148 |
+
stumps_width_pixels = frame_width * (STUMPS_WIDTH / PITCH_LENGTH)
|
| 149 |
+
stumps_height_pixels = frame_height * (STUMPS_HEIGHT / (STUMPS_HEIGHT * 2))
|
| 150 |
+
cv2.line(frame, (int(stumps_x - stumps_width_pixels / 2), int(stumps_y)),
|
| 151 |
+
(int(stumps_x + stumps_width_pixels / 2), int(stumps_y)), (255, 255, 255), 2)
|
| 152 |
+
cv2.line(frame, (int(stumps_x - stumps_width_pixels / 2), int(stumps_y - stumps_height_pixels)),
|
| 153 |
+
(int(stumps_x - stumps_width_pixels / 2), int(stumps_y)), (255, 255, 255), 2)
|
| 154 |
+
cv2.line(frame, (int(stumps_x + stumps_width_pixels / 2), int(stumps_y - stumps_height_pixels)),
|
| 155 |
+
(int(stumps_x + stumps_width_pixels / 2), int(stumps_y)), (255, 255, 255), 2)
|
| 156 |
+
|
| 157 |
+
# Draw crease line
|
| 158 |
+
cv2.line(frame, (int(stumps_x - stumps_width_pixels / 2), int(stumps_y)),
|
| 159 |
+
(int(stumps_x + stumps_width_pixels / 2), int(stumps_y)), (255, 255, 0), 2)
|
| 160 |
+
|
| 161 |
+
if i in detection_frames and trajectory_points.size > 0:
|
| 162 |
+
idx = detection_frames.index(i) + 1
|
| 163 |
+
if idx <= len(trajectory_points):
|
| 164 |
+
cv2.polylines(frame, [trajectory_points[:idx]], False, (0, 0, 255), 2) # Blue trajectory
|
| 165 |
+
|
| 166 |
+
if pitch_point and i == pitch_frame:
|
| 167 |
+
x = pitch_point[0] * frame_width / PITCH_LENGTH
|
| 168 |
+
y = frame_height - (pitch_point[1] * frame_height / (STUMPS_HEIGHT * 2))
|
| 169 |
+
cv2.circle(frame, (int(x), int(y)), 8, (0, 255, 0), -1) # Green for pitching
|
| 170 |
+
cv2.putText(frame, "Pitching", (int(x) + 10, int(y) - 10),
|
| 171 |
+
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
|
| 172 |
+
|
| 173 |
+
if impact_point and i == impact_frame:
|
| 174 |
+
x = impact_point[0] * frame_width / PITCH_LENGTH
|
| 175 |
+
y = frame_height - (impact_point[1] * frame_height / (STUMPS_HEIGHT * 2))
|
| 176 |
+
cv2.circle(frame, (int(x), int(y)), 8, (0, 0, 255), -1) # Red for impact
|
| 177 |
+
cv2.putText(frame, "Impact", (int(x) + 10, int(y) + 20),
|
| 178 |
+
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
|
| 179 |
+
|
| 180 |
+
if impact_point and i == impact_frame and "Out" in decision:
|
| 181 |
+
cv2.putText(frame, "Wickets", (int(stumps_x) - 50, int(stumps_y) - 20),
|
| 182 |
+
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 165, 255), 1) # Orange for wickets
|
| 183 |
+
|
| 184 |
+
for _ in range(SLOW_MOTION_FACTOR):
|
| 185 |
+
out.write(frame)
|
| 186 |
+
out.release()
|
| 187 |
+
return output_path
|
| 188 |
+
|
| 189 |
def draw_3d_scene(trajectory, pitch_point, impact_point, decision):
|
| 190 |
if not HAS_OPENGL:
|
| 191 |
return
|
|
|
|
| 251 |
full_trajectory, vis_trajectory, pitch_point, pitch_frame, impact_point, impact_frame, trajectory_log = estimate_trajectory_3d(ball_positions, detection_frames, frames)
|
| 252 |
decision, full_trajectory, pitch_point, impact_point = lbw_decision(ball_positions, full_trajectory, frames, pitch_point, impact_point)
|
| 253 |
|
| 254 |
+
frame_height, frame_width = frames[0].shape[:2]
|
| 255 |
+
output_path = f"output_{uuid.uuid4()}.mp4"
|
| 256 |
+
slow_motion_path = generate_slow_motion(frames, vis_trajectory, pitch_point, pitch_frame, impact_point, impact_frame, detection_frames, output_path, decision, frame_width, frame_height)
|
| 257 |
+
|
| 258 |
if HAS_OPENGL:
|
| 259 |
init_3d_window(800, 600)
|
| 260 |
from OpenGL.GLUT import glutInit, glutSolidSphere
|
|
|
|
| 263 |
draw_3d_scene(full_trajectory, pitch_point, impact_point, decision)
|
| 264 |
event.pump()
|
| 265 |
|
|
|
|
|
|
|
|
|
|
| 266 |
debug_output = f"{debug_log}\n{trajectory_log}"
|
| 267 |
return f"DRS Decision: {decision}\nDebug Log:\n{debug_output}", slow_motion_path
|
| 268 |
|
|
|
|
| 272 |
inputs=gr.Video(label="Upload Video Clip"),
|
| 273 |
outputs=[
|
| 274 |
gr.Textbox(label="DRS Decision and Debug Log"),
|
| 275 |
+
gr.Video(label="Slow-Motion Replay with 2D Annotations")
|
| 276 |
],
|
| 277 |
title="AI-Powered 3D DRS for LBW",
|
| 278 |
+
description="Upload a video clip for 3D DRS analysis with pitching (green), impact (red), and wickets (orange) visualization, and 2D annotated video output."
|
| 279 |
)
|
| 280 |
|
| 281 |
if __name__ == "__main__":
|