AjaykumarPilla commited on
Commit
8f2145c
·
verified ·
1 Parent(s): a0b9622

Update gully_drs_core/ball_detection.py

Browse files
Files changed (1) hide show
  1. gully_drs_core/ball_detection.py +51 -18
gully_drs_core/ball_detection.py CHANGED
@@ -5,14 +5,23 @@ import numpy as np
5
  from .model_utils import load_model
6
 
7
  def find_bounce_point(path):
8
- """
9
- Finds the point where the ball bounces by detecting a Y-axis dip.
10
- """
11
  for i in range(1, len(path)-1):
12
  if path[i-1][1] > path[i][1] < path[i+1][1]: # y dips = bounce
13
  return path[i]
14
  return None
15
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  def analyze_video(file_path):
17
  model = load_model()
18
  cap = cv2.VideoCapture(file_path)
@@ -23,44 +32,67 @@ def analyze_video(file_path):
23
  ball_path = []
24
  frames = []
25
 
 
 
 
 
 
26
  while True:
27
  ret, frame = cap.read()
28
  if not ret:
29
  break
30
 
31
  results = model(frame)
 
 
32
  for r in results:
33
- for box in r.boxes:
34
- cls = int(box.cls[0])
35
- if cls == 32: # cricket ball class
36
- x1, y1, x2, y2 = map(int, box.xyxy[0])
37
- cx, cy = (x1 + x2) // 2, (y1 + y2) // 2
38
- ball_path.append((cx, cy))
39
- cv2.circle(frame, (cx, cy), 6, (0, 255, 0), -1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  frames.append(frame)
 
42
 
43
  cap.release()
44
 
45
- # Analyze trajectory
46
  bounce_point = find_bounce_point(ball_path)
47
  impact_point = ball_path[-1] if ball_path else None
48
 
49
- # Stump zone: middle area at bottom
50
  stump_zone = (
51
- width // 2 - 30, # x1
52
- height - 100, # y1
53
- width // 2 + 30, # x2
54
- height # y2
55
  )
56
 
57
- # LBW Decision: if impact is in stump zone
58
  decision = "OUT" if (
59
  impact_point and
60
  stump_zone[0] <= impact_point[0] <= stump_zone[2] and
61
  stump_zone[1] <= impact_point[1] <= stump_zone[3]
62
  ) else "NOT OUT"
63
 
 
 
64
  return {
65
  "trajectory": ball_path,
66
  "fps": fps,
@@ -68,5 +100,6 @@ def analyze_video(file_path):
68
  "bounce_point": bounce_point,
69
  "impact_point": impact_point,
70
  "decision": decision,
71
- "stump_zone": stump_zone
 
72
  }
 
5
  from .model_utils import load_model
6
 
7
  def find_bounce_point(path):
 
 
 
8
  for i in range(1, len(path)-1):
9
  if path[i-1][1] > path[i][1] < path[i+1][1]: # y dips = bounce
10
  return path[i]
11
  return None
12
 
13
+ def estimate_speed(ball_path, fps, px_to_m=0.01):
14
+ if len(ball_path) < 2:
15
+ return 0.0
16
+ p1 = ball_path[0]
17
+ p2 = ball_path[min(5, len(ball_path)-1)]
18
+ dx, dy = p2[0] - p1[0], p2[1] - p1[1]
19
+ dist_px = (dx**2 + dy**2)**0.5
20
+ dist_m = dist_px * px_to_m
21
+ time_s = (min(5, len(ball_path)-1)) / fps
22
+ speed_kmh = (dist_m / time_s) * 3.6 if time_s > 0 else 0
23
+ return round(speed_kmh, 1)
24
+
25
  def analyze_video(file_path):
26
  model = load_model()
27
  cap = cv2.VideoCapture(file_path)
 
32
  ball_path = []
33
  frames = []
34
 
35
+ max_jump = 100 # max allowed jump (pixels) between consecutive ball detections
36
+
37
+ last_point = None
38
+ frame_idx = 0
39
+
40
  while True:
41
  ret, frame = cap.read()
42
  if not ret:
43
  break
44
 
45
  results = model(frame)
46
+ valid_detection = None
47
+
48
  for r in results:
49
+ # Accept only if exactly one detection of cricket ball class (e.g., class 0)
50
+ ball_detections = [box for box in r.boxes if int(box.cls[0]) == 0]
51
+ if len(ball_detections) == 1:
52
+ box = ball_detections[0]
53
+ x1, y1, x2, y2 = map(int, box.xyxy[0])
54
+ cx, cy = (x1 + x2) // 2, (y1 + y2) // 2
55
+
56
+ # Check jump threshold from last point
57
+ if last_point:
58
+ dx, dy = cx - last_point[0], cy - last_point[1]
59
+ jump = (dx**2 + dy**2)**0.5
60
+ if jump > max_jump:
61
+ # Reject outlier
62
+ frames.append(frame)
63
+ frame_idx += 1
64
+ continue
65
+
66
+ valid_detection = (cx, cy)
67
+ last_point = valid_detection
68
+ cv2.circle(frame, valid_detection, 6, (0, 255, 0), -1)
69
+
70
+ if valid_detection:
71
+ ball_path.append(valid_detection)
72
 
73
  frames.append(frame)
74
+ frame_idx += 1
75
 
76
  cap.release()
77
 
 
78
  bounce_point = find_bounce_point(ball_path)
79
  impact_point = ball_path[-1] if ball_path else None
80
 
 
81
  stump_zone = (
82
+ width // 2 - 30,
83
+ height - 100,
84
+ width // 2 + 30,
85
+ height
86
  )
87
 
 
88
  decision = "OUT" if (
89
  impact_point and
90
  stump_zone[0] <= impact_point[0] <= stump_zone[2] and
91
  stump_zone[1] <= impact_point[1] <= stump_zone[3]
92
  ) else "NOT OUT"
93
 
94
+ speed_kmh = estimate_speed(ball_path, fps)
95
+
96
  return {
97
  "trajectory": ball_path,
98
  "fps": fps,
 
100
  "bounce_point": bounce_point,
101
  "impact_point": impact_point,
102
  "decision": decision,
103
+ "stump_zone": stump_zone,
104
+ "speed_kmh": speed_kmh
105
  }