Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -7,6 +7,7 @@ from scipy.interpolate import interp1d
|
|
7 |
import plotly.graph_objects as go
|
8 |
import uuid
|
9 |
import os
|
|
|
10 |
|
11 |
# Load the trained YOLOv8n model with optimizations
|
12 |
model = YOLO("best.pt")
|
@@ -17,14 +18,13 @@ STUMPS_WIDTH = 0.2286 # meters (width of stumps)
|
|
17 |
BALL_DIAMETER = 0.073 # meters (approx. cricket ball diameter)
|
18 |
FRAME_RATE = 20 # Default frame rate, updated dynamically
|
19 |
SLOW_MOTION_FACTOR = 1.5 # Faster replay (e.g., 30 / 1.5 = 20 FPS)
|
20 |
-
CONF_THRESHOLD = 0.
|
21 |
IMPACT_ZONE_Y = 0.9 # Adjusted to 90% of frame height for impact zone
|
22 |
-
IMPACT_VELOCITY_THRESHOLD = 500 # Reduced for better impact detection
|
23 |
PITCH_LENGTH = 20.12 # meters (standard cricket pitch length)
|
24 |
STUMPS_HEIGHT = 0.71 # meters (stumps height)
|
25 |
CAMERA_HEIGHT = 2.0 # meters (assumed camera height)
|
26 |
CAMERA_DISTANCE = 10.0 # meters (assumed camera distance from pitch)
|
27 |
-
MAX_POSITION_JUMP =
|
28 |
|
29 |
def process_video(video_path):
|
30 |
if not os.path.exists(video_path):
|
@@ -50,10 +50,11 @@ def process_video(video_path):
|
|
50 |
break
|
51 |
frame_count += 1
|
52 |
frames.append(frame.copy())
|
53 |
-
# Enhance frame contrast and
|
54 |
-
frame = cv2.convertScaleAbs(frame, alpha=1.
|
55 |
-
|
56 |
-
frame = cv2.
|
|
|
57 |
results = model.predict(frame, conf=CONF_THRESHOLD, imgsz=(img_height, img_width), iou=0.5, max_det=3)
|
58 |
detections = sum(1 for detection in results[0].boxes if detection.cls == 0)
|
59 |
if detections == 1: # Only process frames with exactly one ball detection
|
@@ -99,6 +100,7 @@ def estimate_trajectory(ball_positions, frames, detection_frames):
|
|
99 |
if len(ball_positions) < 2:
|
100 |
return None, None, None, None, None, None, None, None, None, "Error: Fewer than 2 frames with one ball detection"
|
101 |
frame_height, frame_width = frames[0].shape[:2]
|
|
|
102 |
|
103 |
# Filter out sudden changes in position for continuous trajectory
|
104 |
filtered_positions = [ball_positions[0]]
|
@@ -121,24 +123,28 @@ def estimate_trajectory(ball_positions, frames, detection_frames):
|
|
121 |
y_coords = [pos[1] for pos in filtered_positions]
|
122 |
times = np.array(filtered_frames) / FRAME_RATE
|
123 |
|
|
|
|
|
|
|
|
|
124 |
# Convert to 3D for visualization
|
125 |
-
detections_3d = [pixel_to_3d(x, y, frame_height, frame_width) for x, y in
|
126 |
|
127 |
# Pitch point: Detection with lowest y-coordinate (near bowler's end)
|
128 |
-
pitch_idx = min(range(len(filtered_positions)), key=lambda i:
|
129 |
-
pitch_point =
|
130 |
pitch_frame = filtered_frames[pitch_idx]
|
131 |
|
132 |
# Impact point: Detection with highest y-coordinate after pitch point (near stumps)
|
133 |
post_pitch_indices = [i for i in range(len(filtered_positions)) if filtered_frames[i] > pitch_frame]
|
134 |
if not post_pitch_indices:
|
135 |
return None, None, None, None, None, None, None, None, None, "Error: No detections after pitch point"
|
136 |
-
impact_idx = max(post_pitch_indices, key=lambda i:
|
137 |
-
impact_point =
|
138 |
impact_frame = filtered_frames[impact_idx]
|
139 |
|
140 |
try:
|
141 |
-
# Use linear interpolation for
|
142 |
fx = interp1d(times, x_coords, kind='linear', fill_value="extrapolate")
|
143 |
fy = interp1d(times, y_coords, kind='linear', fill_value="extrapolate")
|
144 |
except Exception as e:
|
@@ -156,13 +162,13 @@ def estimate_trajectory(ball_positions, frames, detection_frames):
|
|
156 |
impact_point_3d = pixel_to_3d(impact_point[0], impact_point[1], frame_height, frame_width)
|
157 |
|
158 |
# Debug trajectory and points
|
159 |
-
debug_log
|
160 |
f"Trajectory estimated successfully",
|
161 |
f"Pitch point at frame {pitch_frame + 1}: ({pitch_point[0]:.1f}, {pitch_point[1]:.1f}), 3D: {pitch_point_3d}",
|
162 |
f"Impact point at frame {impact_frame + 1}: ({impact_point[0]:.1f}, {impact_point[1]:.1f}), 3D: {impact_point_3d}",
|
163 |
f"Detections in frames: {filtered_frames}",
|
164 |
-
f"
|
165 |
-
]
|
166 |
# Save trajectory plot for debugging
|
167 |
import matplotlib.pyplot as plt
|
168 |
plt.plot(x_coords, y_coords, 'bo-', label='Filtered Detections')
|
|
|
7 |
import plotly.graph_objects as go
|
8 |
import uuid
|
9 |
import os
|
10 |
+
from scipy.ndimage import uniform_filter1d
|
11 |
|
12 |
# Load the trained YOLOv8n model with optimizations
|
13 |
model = YOLO("best.pt")
|
|
|
18 |
BALL_DIAMETER = 0.073 # meters (approx. cricket ball diameter)
|
19 |
FRAME_RATE = 20 # Default frame rate, updated dynamically
|
20 |
SLOW_MOTION_FACTOR = 1.5 # Faster replay (e.g., 30 / 1.5 = 20 FPS)
|
21 |
+
CONF_THRESHOLD = 0.2 # Lowered for better detection
|
22 |
IMPACT_ZONE_Y = 0.9 # Adjusted to 90% of frame height for impact zone
|
|
|
23 |
PITCH_LENGTH = 20.12 # meters (standard cricket pitch length)
|
24 |
STUMPS_HEIGHT = 0.71 # meters (stumps height)
|
25 |
CAMERA_HEIGHT = 2.0 # meters (assumed camera height)
|
26 |
CAMERA_DISTANCE = 10.0 # meters (assumed camera distance from pitch)
|
27 |
+
MAX_POSITION_JUMP = 200 # Increased to include more detections
|
28 |
|
29 |
def process_video(video_path):
|
30 |
if not os.path.exists(video_path):
|
|
|
50 |
break
|
51 |
frame_count += 1
|
52 |
frames.append(frame.copy())
|
53 |
+
# Enhance frame contrast and apply adaptive thresholding
|
54 |
+
frame = cv2.convertScaleAbs(frame, alpha=1.3, beta=10)
|
55 |
+
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
56 |
+
frame = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 11, 2)
|
57 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)
|
58 |
results = model.predict(frame, conf=CONF_THRESHOLD, imgsz=(img_height, img_width), iou=0.5, max_det=3)
|
59 |
detections = sum(1 for detection in results[0].boxes if detection.cls == 0)
|
60 |
if detections == 1: # Only process frames with exactly one ball detection
|
|
|
100 |
if len(ball_positions) < 2:
|
101 |
return None, None, None, None, None, None, None, None, None, "Error: Fewer than 2 frames with one ball detection"
|
102 |
frame_height, frame_width = frames[0].shape[:2]
|
103 |
+
debug_log = []
|
104 |
|
105 |
# Filter out sudden changes in position for continuous trajectory
|
106 |
filtered_positions = [ball_positions[0]]
|
|
|
123 |
y_coords = [pos[1] for pos in filtered_positions]
|
124 |
times = np.array(filtered_frames) / FRAME_RATE
|
125 |
|
126 |
+
# Smooth coordinates to avoid sudden jumps
|
127 |
+
x_coords = uniform_filter1d(x_coords, size=3)
|
128 |
+
y_coords = uniform_filter1d(y_coords, size=3)
|
129 |
+
|
130 |
# Convert to 3D for visualization
|
131 |
+
detections_3d = [pixel_to_3d(x, y, frame_height, frame_width) for x, y in zip(x_coords, y_coords)]
|
132 |
|
133 |
# Pitch point: Detection with lowest y-coordinate (near bowler's end)
|
134 |
+
pitch_idx = min(range(len(filtered_positions)), key=lambda i: y_coords[i])
|
135 |
+
pitch_point = (x_coords[pitch_idx], y_coords[pitch_idx])
|
136 |
pitch_frame = filtered_frames[pitch_idx]
|
137 |
|
138 |
# Impact point: Detection with highest y-coordinate after pitch point (near stumps)
|
139 |
post_pitch_indices = [i for i in range(len(filtered_positions)) if filtered_frames[i] > pitch_frame]
|
140 |
if not post_pitch_indices:
|
141 |
return None, None, None, None, None, None, None, None, None, "Error: No detections after pitch point"
|
142 |
+
impact_idx = max(post_pitch_indices, key=lambda i: y_coords[i])
|
143 |
+
impact_point = (x_coords[impact_idx], y_coords[impact_idx])
|
144 |
impact_frame = filtered_frames[impact_idx]
|
145 |
|
146 |
try:
|
147 |
+
# Use linear interpolation for stable trajectory
|
148 |
fx = interp1d(times, x_coords, kind='linear', fill_value="extrapolate")
|
149 |
fy = interp1d(times, y_coords, kind='linear', fill_value="extrapolate")
|
150 |
except Exception as e:
|
|
|
162 |
impact_point_3d = pixel_to_3d(impact_point[0], impact_point[1], frame_height, frame_width)
|
163 |
|
164 |
# Debug trajectory and points
|
165 |
+
debug_log.extend([
|
166 |
f"Trajectory estimated successfully",
|
167 |
f"Pitch point at frame {pitch_frame + 1}: ({pitch_point[0]:.1f}, {pitch_point[1]:.1f}), 3D: {pitch_point_3d}",
|
168 |
f"Impact point at frame {impact_frame + 1}: ({impact_point[0]:.1f}, {impact_point[1]:.1f}), 3D: {impact_point_3d}",
|
169 |
f"Detections in frames: {filtered_frames}",
|
170 |
+
f"Total filtered detections: {len(filtered_frames)}"
|
171 |
+
])
|
172 |
# Save trajectory plot for debugging
|
173 |
import matplotlib.pyplot as plt
|
174 |
plt.plot(x_coords, y_coords, 'bo-', label='Filtered Detections')
|