AjaykumarPilla commited on
Commit
6a7c8be
·
verified ·
1 Parent(s): 7e44cd3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +17 -25
app.py CHANGED
@@ -17,7 +17,6 @@ FRAME_RATE = 30 # Input video frame rate
17
  SLOW_MOTION_FACTOR = 6 # For very slow motion (6x slower)
18
  CONF_THRESHOLD = 0.25 # Confidence threshold for detection
19
  IMPACT_ZONE_Y = 0.85 # Fraction of frame height where impact is likely (near stumps)
20
- IMPACT_DELTA_Y = 50 # Pixels for detecting sudden y-position change (impact)
21
 
22
  def process_video(video_path):
23
  if not os.path.exists(video_path):
@@ -55,32 +54,26 @@ def process_video(video_path):
55
 
56
  return frames, ball_positions, detection_frames, "\n".join(debug_log)
57
 
58
- def estimate_trajectory(ball_positions, frames, detection_frames):
59
  if len(ball_positions) < 2:
60
- return None, None, None, None, "Error: Fewer than 2 ball detections for trajectory"
61
  frame_height = frames[0].shape[0]
62
 
63
  # Extract x, y coordinates
64
  x_coords = [pos[0] for pos in ball_positions]
65
  y_coords = [pos[1] for pos in ball_positions]
66
- times = np.array(detection_frames) / FRAME_RATE
67
 
68
- # Identify pitch point (first detection)
69
- pitch_point = ball_positions[0]
70
- pitch_frame = detection_frames[0]
71
-
72
- # Find impact point (sudden change in y or near stumps)
73
  impact_idx = None
74
- impact_frame = None
75
- for i in range(1, len(y_coords)):
76
- if y_coords[i] > frame_height * IMPACT_ZONE_Y or abs(y_coords[i] - y_coords[i-1]) > IMPACT_DELTA_Y:
77
  impact_idx = i
78
- impact_frame = detection_frames[i]
79
  break
80
  if impact_idx is None:
81
- impact_idx = len(ball_positions) - 1
82
- impact_frame = detection_frames[-1]
83
 
 
84
  impact_point = ball_positions[impact_idx]
85
 
86
  # Use positions up to impact for interpolation
@@ -92,7 +85,7 @@ def estimate_trajectory(ball_positions, frames, detection_frames):
92
  fx = interp1d(times, x_coords, kind='linear', fill_value="extrapolate")
93
  fy = interp1d(times, y_coords, kind='quadratic', fill_value="extrapolate")
94
  except Exception as e:
95
- return None, None, None, None, f"Error in trajectory interpolation: {str(e)}"
96
 
97
  # Project trajectory (detected + future for LBW decision)
98
  t_full = np.linspace(times[0], times[-1] + 0.5, len(times) + 10)
@@ -100,8 +93,7 @@ def estimate_trajectory(ball_positions, frames, detection_frames):
100
  y_full = fy(t_full)
101
  trajectory = list(zip(x_full, y_full))
102
 
103
- debug_log = f"Trajectory estimated successfully\nPitch point at frame {pitch_frame + 1}: ({pitch_point[0]:.1f}, {pitch_point[1]:.1f})\nImpact point at frame {impact_frame + 1}: ({impact_point[0]:.1f}, {impact_point[1]:.1f})"
104
- return trajectory, pitch_point, impact_point, pitch_frame, impact_frame, debug_log
105
 
106
  def lbw_decision(ball_positions, trajectory, frames, pitch_point, impact_point):
107
  if not frames:
@@ -131,7 +123,7 @@ def lbw_decision(ball_positions, trajectory, frames, pitch_point, impact_point):
131
  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
132
  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
133
 
134
- def generate_slow_motion(frames, trajectory, pitch_point, impact_point, detection_frames, pitch_frame, impact_frame, output_path):
135
  if not frames:
136
  return None
137
  fourcc = cv2.VideoWriter_fourcc(*'mp4v')
@@ -145,15 +137,15 @@ def generate_slow_motion(frames, trajectory, pitch_point, impact_point, detectio
145
  if i in detection_frames and trajectory_points.size > 0:
146
  cv2.polylines(frame, [trajectory_points[:detection_frames.index(i) + 1]], False, (255, 0, 0), 2)
147
 
148
- # Draw pitch point (red circle with label) only in pitch frame
149
- if pitch_point and i == pitch_frame:
150
  x, y = pitch_point
151
  cv2.circle(frame, (int(x), int(y)), 8, (0, 0, 255), -1)
152
  cv2.putText(frame, "Pitch Point", (int(x) + 10, int(y) - 10),
153
  cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
154
 
155
- # Draw impact point (yellow circle with label) only in impact frame
156
- if impact_point and i == impact_frame:
157
  x, y = impact_point
158
  cv2.circle(frame, (int(x), int(y)), 8, (0, 255, 255), -1)
159
  cv2.putText(frame, "Impact Point", (int(x) + 10, int(y) + 20),
@@ -168,11 +160,11 @@ def drs_review(video):
168
  frames, ball_positions, detection_frames, debug_log = process_video(video)
169
  if not frames:
170
  return f"Error: Failed to process video\nDebug Log:\n{debug_log}", None
171
- trajectory, pitch_point, impact_point, pitch_frame, impact_frame, trajectory_log = estimate_trajectory(ball_positions, frames, detection_frames)
172
  decision, trajectory, pitch_point, impact_point = lbw_decision(ball_positions, trajectory, frames, pitch_point, impact_point)
173
 
174
  output_path = f"output_{uuid.uuid4()}.mp4"
175
- slow_motion_path = generate_slow_motion(frames, trajectory, pitch_point, impact_point, detection_frames, pitch_frame, impact_frame, output_path)
176
 
177
  debug_output = f"{debug_log}\n{trajectory_log}"
178
  return f"DRS Decision: {decision}\nDebug Log:\n{debug_output}", slow_motion_path
 
17
  SLOW_MOTION_FACTOR = 6 # For very slow motion (6x slower)
18
  CONF_THRESHOLD = 0.25 # Confidence threshold for detection
19
  IMPACT_ZONE_Y = 0.85 # Fraction of frame height where impact is likely (near stumps)
 
20
 
21
  def process_video(video_path):
22
  if not os.path.exists(video_path):
 
54
 
55
  return frames, ball_positions, detection_frames, "\n".join(debug_log)
56
 
57
+ def estimate_trajectory(ball_positions, frames):
58
  if len(ball_positions) < 2:
59
+ return None, None, None, "Error: Fewer than 2 ball detections for trajectory"
60
  frame_height = frames[0].shape[0]
61
 
62
  # Extract x, y coordinates
63
  x_coords = [pos[0] for pos in ball_positions]
64
  y_coords = [pos[1] for pos in ball_positions]
65
+ times = np.arange(len(ball_positions)) / FRAME_RATE
66
 
67
+ # Find impact point (closest to batsman, near stumps)
 
 
 
 
68
  impact_idx = None
69
+ for i, y in enumerate(y_coords):
70
+ if y > frame_height * IMPACT_ZONE_Y: # Ball is near stumps/batsman
 
71
  impact_idx = i
 
72
  break
73
  if impact_idx is None:
74
+ impact_idx = len(ball_positions) - 1 # Fallback to last detection
 
75
 
76
+ pitch_point = ball_positions[0]
77
  impact_point = ball_positions[impact_idx]
78
 
79
  # Use positions up to impact for interpolation
 
85
  fx = interp1d(times, x_coords, kind='linear', fill_value="extrapolate")
86
  fy = interp1d(times, y_coords, kind='quadratic', fill_value="extrapolate")
87
  except Exception as e:
88
+ return None, None, None, f"Error in trajectory interpolation: {str(e)}"
89
 
90
  # Project trajectory (detected + future for LBW decision)
91
  t_full = np.linspace(times[0], times[-1] + 0.5, len(times) + 10)
 
93
  y_full = fy(t_full)
94
  trajectory = list(zip(x_full, y_full))
95
 
96
+ return trajectory, pitch_point, impact_point, "Trajectory estimated successfully"
 
97
 
98
  def lbw_decision(ball_positions, trajectory, frames, pitch_point, impact_point):
99
  if not frames:
 
123
  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
124
  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
125
 
126
+ def generate_slow_motion(frames, trajectory, pitch_point, impact_point, detection_frames, output_path):
127
  if not frames:
128
  return None
129
  fourcc = cv2.VideoWriter_fourcc(*'mp4v')
 
137
  if i in detection_frames and trajectory_points.size > 0:
138
  cv2.polylines(frame, [trajectory_points[:detection_frames.index(i) + 1]], False, (255, 0, 0), 2)
139
 
140
+ # Draw pitch point (red circle with label)
141
+ if pitch_point and i >= detection_frames[0]:
142
  x, y = pitch_point
143
  cv2.circle(frame, (int(x), int(y)), 8, (0, 0, 255), -1)
144
  cv2.putText(frame, "Pitch Point", (int(x) + 10, int(y) - 10),
145
  cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
146
 
147
+ # Draw impact point (yellow circle with label) only in frames after impact
148
+ if impact_point and i >= detection_frames[min(len(detection_frames) - 1, detection_frames.index(detection_frames[-1]))]:
149
  x, y = impact_point
150
  cv2.circle(frame, (int(x), int(y)), 8, (0, 255, 255), -1)
151
  cv2.putText(frame, "Impact Point", (int(x) + 10, int(y) + 20),
 
160
  frames, ball_positions, detection_frames, debug_log = process_video(video)
161
  if not frames:
162
  return f"Error: Failed to process video\nDebug Log:\n{debug_log}", None
163
+ trajectory, pitch_point, impact_point, trajectory_log = estimate_trajectory(ball_positions, frames)
164
  decision, trajectory, pitch_point, impact_point = lbw_decision(ball_positions, trajectory, frames, pitch_point, impact_point)
165
 
166
  output_path = f"output_{uuid.uuid4()}.mp4"
167
+ slow_motion_path = generate_slow_motion(frames, trajectory, pitch_point, impact_point, detection_frames, output_path)
168
 
169
  debug_output = f"{debug_log}\n{trajectory_log}"
170
  return f"DRS Decision: {decision}\nDebug Log:\n{debug_output}", slow_motion_path