# 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 }