Update app.py
Browse files
app.py
CHANGED
@@ -15,7 +15,7 @@ STUMPS_WIDTH = 0.2286 # meters (width of stumps)
|
|
15 |
BALL_DIAMETER = 0.073 # meters (approx. cricket ball diameter)
|
16 |
FRAME_RATE = 30 # Input video frame rate
|
17 |
SLOW_MOTION_FACTOR = 6 # For very slow motion (6x slower)
|
18 |
-
CONF_THRESHOLD = 0.
|
19 |
IMPACT_ZONE_Y = 0.85 # Fraction of frame height where impact is likely (near stumps)
|
20 |
|
21 |
def process_video(video_path):
|
@@ -50,13 +50,33 @@ def process_video(video_path):
|
|
50 |
else:
|
51 |
debug_log.append(f"Total ball detections: {len(ball_positions)}")
|
52 |
|
|
|
|
|
|
|
|
|
53 |
return frames, ball_positions, "\n".join(debug_log)
|
54 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
55 |
def estimate_trajectory(ball_positions, frames):
|
56 |
if len(ball_positions) < 2:
|
57 |
return None, None, None, "Error: Fewer than 2 ball detections for trajectory"
|
58 |
frame_height = frames[0].shape[0]
|
59 |
-
|
60 |
# Extract x, y coordinates
|
61 |
x_coords = [pos[0] for pos in ball_positions]
|
62 |
y_coords = [pos[1] for pos in ball_positions]
|
@@ -71,8 +91,9 @@ def estimate_trajectory(ball_positions, frames):
|
|
71 |
if impact_idx is None:
|
72 |
impact_idx = len(ball_positions) - 1 # Fallback to last detection
|
73 |
|
|
|
74 |
impact_point = ball_positions[impact_idx]
|
75 |
-
|
76 |
# Use positions up to impact for interpolation
|
77 |
x_coords = x_coords[:impact_idx + 1]
|
78 |
y_coords = y_coords[:impact_idx + 1]
|
@@ -88,7 +109,36 @@ def estimate_trajectory(ball_positions, frames):
|
|
88 |
t_full = np.linspace(times[0], times[-1] + 0.5, len(times) + 10)
|
89 |
x_full = fx(t_full)
|
90 |
y_full = fy(t_full)
|
91 |
-
trajectory =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
return f"Not Out (Missing stumps, Pitch at x: {pitch_x:.1f}, y: {pitch_y:.1f}, Impact at x: {impact_x:.1f}, y: {impact_y:.1f})", trajectory, pitch_point, impact_point
|
93 |
|
94 |
def generate_slow_motion(frames, trajectory, pitch_point, impact_point, output_path):
|
|
|
15 |
BALL_DIAMETER = 0.073 # meters (approx. cricket ball diameter)
|
16 |
FRAME_RATE = 30 # Input video frame rate
|
17 |
SLOW_MOTION_FACTOR = 6 # For very slow motion (6x slower)
|
18 |
+
CONF_THRESHOLD = 0.25 # Lowered confidence threshold to improve detection
|
19 |
IMPACT_ZONE_Y = 0.85 # Fraction of frame height where impact is likely (near stumps)
|
20 |
|
21 |
def process_video(video_path):
|
|
|
50 |
else:
|
51 |
debug_log.append(f"Total ball detections: {len(ball_positions)}")
|
52 |
|
53 |
+
# Interpolate missing detections
|
54 |
+
if ball_positions:
|
55 |
+
ball_positions = interpolate_missing_positions(ball_positions, frame_count)
|
56 |
+
|
57 |
return frames, ball_positions, "\n".join(debug_log)
|
58 |
|
59 |
+
def interpolate_missing_positions(ball_positions, total_frames):
|
60 |
+
if len(ball_positions) < 2:
|
61 |
+
return ball_positions
|
62 |
+
times = np.linspace(0, total_frames / FRAME_RATE, total_frames)
|
63 |
+
detected_times = [i / FRAME_RATE for i, _ in enumerate(ball_positions)]
|
64 |
+
x_coords = [pos[0] for pos in ball_positions]
|
65 |
+
y_coords = [pos[1] for pos in ball_positions]
|
66 |
+
|
67 |
+
try:
|
68 |
+
fx = interp1d(detected_times, x_coords, kind='linear', fill_value="extrapolate")
|
69 |
+
fy = interp1d(detected_times, y_coords, kind='linear', fill_value="extrapolate")
|
70 |
+
interpolated_positions = [(fx(t), fy(t)) for t in times if t <= detected_times[-1]]
|
71 |
+
return interpolated_positions
|
72 |
+
except:
|
73 |
+
return ball_positions
|
74 |
+
|
75 |
def estimate_trajectory(ball_positions, frames):
|
76 |
if len(ball_positions) < 2:
|
77 |
return None, None, None, "Error: Fewer than 2 ball detections for trajectory"
|
78 |
frame_height = frames[0].shape[0]
|
79 |
+
|
80 |
# Extract x, y coordinates
|
81 |
x_coords = [pos[0] for pos in ball_positions]
|
82 |
y_coords = [pos[1] for pos in ball_positions]
|
|
|
91 |
if impact_idx is None:
|
92 |
impact_idx = len(ball_positions) - 1 # Fallback to last detection
|
93 |
|
94 |
+
pitch_point = ball_positions[0]
|
95 |
impact_point = ball_positions[impact_idx]
|
96 |
+
|
97 |
# Use positions up to impact for interpolation
|
98 |
x_coords = x_coords[:impact_idx + 1]
|
99 |
y_coords = y_coords[:impact_idx + 1]
|
|
|
109 |
t_full = np.linspace(times[0], times[-1] + 0.5, len(times) + 10)
|
110 |
x_full = fx(t_full)
|
111 |
y_full = fy(t_full)
|
112 |
+
trajectory = list(zip(x_full, y_full))
|
113 |
+
|
114 |
+
return trajectory, pitch_point, impact_point, "Trajectory estimated successfully"
|
115 |
+
|
116 |
+
def lbw_decision(ball_positions, trajectory, frames, pitch_point, impact_point):
|
117 |
+
if not frames:
|
118 |
+
return "Error: No frames processed", None, None, None
|
119 |
+
if not trajectory or len(ball_positions) < 2:
|
120 |
+
return "Not enough data (insufficient ball detections)", None, None, None
|
121 |
+
|
122 |
+
frame_height, frame_width = frames[0].shape[:2]
|
123 |
+
stumps_x = frame_width / 2
|
124 |
+
stumps_y = frame_height * 0.9
|
125 |
+
stumps_width_pixels = frame_width * (STUMPS_WIDTH / 3.0)
|
126 |
+
|
127 |
+
pitch_x, pitch_y = pitch_point
|
128 |
+
impact_x, impact_y = impact_point
|
129 |
+
|
130 |
+
# Check pitching point
|
131 |
+
if pitch_x < stumps_x - stumps_width_pixels / 2 or pitch_x > stumps_x + stumps_width_pixels / 2:
|
132 |
+
return f"Not Out (Pitched outside line at x: {pitch_x:.1f}, y: {pitch_y:.1f})", trajectory, pitch_point, impact_point
|
133 |
+
|
134 |
+
# Check impact point
|
135 |
+
if impact_x < stumps_x - stumps_width_pixels / 2 or impact_x > stumps_x + stumps_width_pixels / 2:
|
136 |
+
return f"Not Out (Impact outside line at x: {impact_x:.1f}, y: {impact_y:.1f})", trajectory, pitch_point, impact_point
|
137 |
+
|
138 |
+
# Check trajectory hitting stumps
|
139 |
+
for x, y in trajectory:
|
140 |
+
if abs(x - stumps_x) < stumps_width_pixels / 2 and abs(y - stumps_y) < frame_height * 0.1:
|
141 |
+
return f"Out (Ball hits stumps, Pitch at x: {pitch_x:.1f}, y: {pitch_y:.1f}, Impact at x: {impact_x:.1f}, y: {impact_y:.1f})", trajectory, pitch_point, impact_point
|
142 |
return f"Not Out (Missing stumps, Pitch at x: {pitch_x:.1f}, y: {pitch_y:.1f}, Impact at x: {impact_x:.1f}, y: {impact_y:.1f})", trajectory, pitch_point, impact_point
|
143 |
|
144 |
def generate_slow_motion(frames, trajectory, pitch_point, impact_point, output_path):
|