Spaces:
Sleeping
Sleeping
Update utils.py
Browse files
utils.py
CHANGED
@@ -4,15 +4,20 @@ import cv2
|
|
4 |
import numpy as np
|
5 |
|
6 |
def analyze_frame_sequence(frames):
|
|
|
|
|
|
|
7 |
return {
|
8 |
"pitch": "in line",
|
9 |
"impact": "in line",
|
10 |
"trajectory": "hitting",
|
11 |
"shot_offered": True,
|
12 |
-
"pitch_point":
|
13 |
-
"impact_point":
|
14 |
-
"trajectory_curve":
|
15 |
-
"stump_zone": [(
|
|
|
|
|
16 |
}
|
17 |
|
18 |
def make_decision(analysis):
|
@@ -29,65 +34,61 @@ def make_decision(analysis):
|
|
29 |
def overlay_text(frame, text, pos, size=1.0, color=(255,255,255)):
|
30 |
cv2.putText(frame, text, pos, cv2.FONT_HERSHEY_SIMPLEX, size, color, 2, cv2.LINE_AA)
|
31 |
|
32 |
-
def
|
33 |
-
|
34 |
-
|
35 |
-
cv2.circle(frame,
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
shot_icon = "✓" if analysis['shot_offered'] else "✗"
|
45 |
overlay_text(frame, f"Shot Offered: {shot_icon}", (30, 170), 0.8, (0,255,0) if analysis['shot_offered'] else (0,0,255))
|
46 |
|
47 |
-
|
48 |
-
|
49 |
-
for i in range(len(analysis['trajectory_curve'])-1):
|
50 |
-
cv2.line(frame, analysis['trajectory_curve'][i], analysis['trajectory_curve'][i+1], (0,255,0) if analysis['trajectory']=="hitting" else (0,0,255), 2, cv2.LINE_AA)
|
51 |
-
|
52 |
-
# transparent stump zone
|
53 |
-
if 'stump_zone' in analysis:
|
54 |
-
x1, y1 = analysis['stump_zone'][0]
|
55 |
-
x2, y2 = analysis['stump_zone'][1]
|
56 |
-
overlay = frame.copy()
|
57 |
-
cv2.rectangle(overlay, (x1, y1), (x2, y2), (255, 255, 255), -1)
|
58 |
-
alpha = 0.2
|
59 |
-
frame[:] = cv2.addWeighted(overlay, alpha, frame, 1 - alpha, 0)
|
60 |
-
cv2.rectangle(frame, (x1, y1), (x2, y2), (180, 180, 180), 2)
|
61 |
-
|
62 |
-
overlay_text(frame, f"Trajectory: {analysis['trajectory'].capitalize()}", (30, 130), 0.8, (0,255,0) if analysis['trajectory']=="hitting" else (0,0,255))
|
63 |
overlay_text(frame, "ICC LBW Review • Third-Umpire Analysis", (30, frame.shape[0] - 30), 0.6, (180,180,180))
|
64 |
|
65 |
-
|
66 |
def render_annotated_clip(frames, analysis, decision, reason, output_path):
|
67 |
h, w = frames[0].shape[:2]
|
68 |
out = cv2.VideoWriter(output_path, cv2.VideoWriter_fourcc(*'mp4v'), 20.0, (w, h))
|
69 |
|
70 |
-
#
|
71 |
verdict_card = np.zeros_like(frames[0])
|
72 |
overlay_text(verdict_card, f"FINAL DECISION: {decision}", (50, 200), 2.0, (255,255,255))
|
73 |
overlay_text(verdict_card, reason, (50, 250), 0.9, (200,200,200))
|
74 |
for _ in range(20):
|
75 |
out.write(verdict_card)
|
76 |
|
77 |
-
#
|
78 |
-
for
|
79 |
-
annotated =
|
80 |
-
|
81 |
-
out.write(annotated)
|
82 |
-
|
83 |
-
# Slow-motion replay
|
84 |
-
for i in range(0, len(frames), 2):
|
85 |
-
annotated = frames[i].copy()
|
86 |
-
overlay_annotations(annotated, analysis)
|
87 |
-
out.write(annotated)
|
88 |
out.write(annotated)
|
89 |
|
90 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
for _ in range(10):
|
92 |
out.write(verdict_card)
|
93 |
|
|
|
4 |
import numpy as np
|
5 |
|
6 |
def analyze_frame_sequence(frames):
|
7 |
+
# Simulate realistic trajectory
|
8 |
+
h, w = frames[0].shape[:2]
|
9 |
+
trajectory_curve = [(200+i*10, 300 - i*8) for i in range(6)] # sloping downward
|
10 |
return {
|
11 |
"pitch": "in line",
|
12 |
"impact": "in line",
|
13 |
"trajectory": "hitting",
|
14 |
"shot_offered": True,
|
15 |
+
"pitch_point": trajectory_curve[0],
|
16 |
+
"impact_point": trajectory_curve[2],
|
17 |
+
"trajectory_curve": trajectory_curve,
|
18 |
+
"stump_zone": [(trajectory_curve[-1][0] - 20, trajectory_curve[-1][1] - 40),
|
19 |
+
(trajectory_curve[-1][0] + 20, trajectory_curve[-1][1] + 40)],
|
20 |
+
"hit_point": trajectory_curve[-1]
|
21 |
}
|
22 |
|
23 |
def make_decision(analysis):
|
|
|
34 |
def overlay_text(frame, text, pos, size=1.0, color=(255,255,255)):
|
35 |
cv2.putText(frame, text, pos, cv2.FONT_HERSHEY_SIMPLEX, size, color, 2, cv2.LINE_AA)
|
36 |
|
37 |
+
def overlay_annotations_dynamic(frame, analysis, t):
|
38 |
+
if t < len(analysis['trajectory_curve']):
|
39 |
+
ball_pos = analysis['trajectory_curve'][t]
|
40 |
+
cv2.circle(frame, ball_pos, 8, (0, 255, 0) if analysis['trajectory'] == 'hitting' else (0, 0, 255), -1)
|
41 |
+
|
42 |
+
# Draw complete arc
|
43 |
+
for i in range(1, min(t + 1, len(analysis['trajectory_curve']))):
|
44 |
+
cv2.line(frame, analysis['trajectory_curve'][i - 1], analysis['trajectory_curve'][i],
|
45 |
+
(0, 255, 0) if analysis['trajectory'] == 'hitting' else (0, 0, 255), 2)
|
46 |
+
|
47 |
+
# Highlight stumps zone
|
48 |
+
x1, y1 = analysis['stump_zone'][0]
|
49 |
+
x2, y2 = analysis['stump_zone'][1]
|
50 |
+
overlay = frame.copy()
|
51 |
+
cv2.rectangle(overlay, (x1, y1), (x2, y2), (255, 255, 255), -1)
|
52 |
+
alpha = 0.2
|
53 |
+
frame[:] = cv2.addWeighted(overlay, alpha, frame, 1 - alpha, 0)
|
54 |
+
cv2.rectangle(frame, (x1, y1), (x2, y2), (180, 180, 180), 2)
|
55 |
+
|
56 |
+
# Shot
|
57 |
shot_icon = "✓" if analysis['shot_offered'] else "✗"
|
58 |
overlay_text(frame, f"Shot Offered: {shot_icon}", (30, 170), 0.8, (0,255,0) if analysis['shot_offered'] else (0,0,255))
|
59 |
|
60 |
+
overlay_text(frame, f"Trajectory: {analysis['trajectory'].capitalize()}", (30, 130), 0.8,
|
61 |
+
(0, 255, 0) if analysis['trajectory'] == 'hitting' else (0, 0, 255))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
overlay_text(frame, "ICC LBW Review • Third-Umpire Analysis", (30, frame.shape[0] - 30), 0.6, (180,180,180))
|
63 |
|
|
|
64 |
def render_annotated_clip(frames, analysis, decision, reason, output_path):
|
65 |
h, w = frames[0].shape[:2]
|
66 |
out = cv2.VideoWriter(output_path, cv2.VideoWriter_fourcc(*'mp4v'), 20.0, (w, h))
|
67 |
|
68 |
+
# Verdict card (1s)
|
69 |
verdict_card = np.zeros_like(frames[0])
|
70 |
overlay_text(verdict_card, f"FINAL DECISION: {decision}", (50, 200), 2.0, (255,255,255))
|
71 |
overlay_text(verdict_card, reason, (50, 250), 0.9, (200,200,200))
|
72 |
for _ in range(20):
|
73 |
out.write(verdict_card)
|
74 |
|
75 |
+
# Dynamic replay
|
76 |
+
for t, f in enumerate(frames):
|
77 |
+
annotated = f.copy()
|
78 |
+
overlay_annotations_dynamic(annotated, analysis, t)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
79 |
out.write(annotated)
|
80 |
|
81 |
+
# Slow-motion: emphasize final 3 points
|
82 |
+
for pt in analysis['trajectory_curve'][-3:]:
|
83 |
+
for _ in range(2):
|
84 |
+
f = frames[-1].copy()
|
85 |
+
cv2.circle(f, pt, 10, (0,255,0) if analysis['trajectory']=="hitting" else (0,0,255), -1)
|
86 |
+
cv2.rectangle(f, analysis['stump_zone'][0], analysis['stump_zone'][1], (180,180,180), 2)
|
87 |
+
overlay_text(f, "Trajectory End", (pt[0] + 10, pt[1] - 10), 0.8, (255,255,255))
|
88 |
+
overlay_text(f, "ICC LBW Review • Third-Umpire Analysis", (30, h - 30), 0.6, (180,180,180))
|
89 |
+
out.write(f)
|
90 |
+
|
91 |
+
# End card (0.5s)
|
92 |
for _ in range(10):
|
93 |
out.write(verdict_card)
|
94 |
|