Spaces:
Sleeping
Sleeping
# gully_drs_core/ball_detection.py | |
import cv2 | |
import numpy as np | |
from .model_utils import load_model | |
def find_bounce_point(path): | |
""" | |
Finds the point where the ball bounces by detecting a Y-axis dip. | |
""" | |
for i in range(1, len(path)-1): | |
if path[i-1][1] > path[i][1] < path[i+1][1]: # y dips = bounce | |
return path[i] | |
return None | |
def analyze_video(file_path): | |
model = load_model() | |
cap = cv2.VideoCapture(file_path) | |
fps = cap.get(cv2.CAP_PROP_FPS) | |
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) | |
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) | |
ball_path = [] | |
frames = [] | |
while True: | |
ret, frame = cap.read() | |
if not ret: | |
break | |
results = model(frame) | |
for r in results: | |
for box in r.boxes: | |
cls = int(box.cls[0]) | |
if cls == 32: # cricket ball class | |
x1, y1, x2, y2 = map(int, box.xyxy[0]) | |
cx, cy = (x1 + x2) // 2, (y1 + y2) // 2 | |
ball_path.append((cx, cy)) | |
cv2.circle(frame, (cx, cy), 6, (0, 255, 0), -1) | |
frames.append(frame) | |
cap.release() | |
# Analyze trajectory | |
bounce_point = find_bounce_point(ball_path) | |
impact_point = ball_path[-1] if ball_path else None | |
# Stump zone: middle area at bottom | |
stump_zone = ( | |
width // 2 - 30, # x1 | |
height - 100, # y1 | |
width // 2 + 30, # x2 | |
height # y2 | |
) | |
# LBW Decision: if impact is in stump zone | |
decision = "OUT" if ( | |
impact_point and | |
stump_zone[0] <= impact_point[0] <= stump_zone[2] and | |
stump_zone[1] <= impact_point[1] <= stump_zone[3] | |
) else "NOT OUT" | |
return { | |
"trajectory": ball_path, | |
"fps": fps, | |
"frames": frames, | |
"bounce_point": bounce_point, | |
"impact_point": impact_point, | |
"decision": decision, | |
"stump_zone": stump_zone | |
} | |