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__":
|