AjaykumarPilla commited on
Commit
57e48fa
Β·
verified Β·
1 Parent(s): 016496d

Update gully_drs_core/ball_detection.py

Browse files
Files changed (1) hide show
  1. gully_drs_core/ball_detection.py +48 -105
gully_drs_core/ball_detection.py CHANGED
@@ -1,105 +1,48 @@
1
- # gully_drs_core/ball_detection.py
2
-
3
- import cv2
4
- import numpy as np
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)
28
- fps = cap.get(cv2.CAP_PROP_FPS)
29
- width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
30
- height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
31
-
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,
99
- "frames": frames,
100
- "bounce_point": bounce_point,
101
- "impact_point": impact_point,
102
- "decision": decision,
103
- "stump_zone": stump_zone,
104
- "speed_kmh": speed_kmh
105
- }
 
1
+ import streamlit as st
2
+ import tempfile
3
+ import os
4
+ from gully_drs_core import ball_detection, replay_utils
5
+
6
+ st.set_page_config(page_title="GullyDRS – LBW Review", layout="centered")
7
+ st.title("🏏 GullyDRS – LBW Decision Review System")
8
+
9
+ st.markdown("""
10
+ Upload a cricket match video and let AI analyze whether it's **OUT** or **NOT OUT**
11
+ based on ball trajectory, bounce point, and stump zone detection.
12
+ """)
13
+
14
+ video_file = st.file_uploader("πŸŽ₯ Upload your match video", type=["mp4", "avi"])
15
+
16
+ if video_file:
17
+ tfile = tempfile.NamedTemporaryFile(delete=False)
18
+ tfile.write(video_file.read())
19
+ st.video(video_file)
20
+
21
+ if st.button("🧠 Analyze Video"):
22
+ with st.spinner("Analyzing with AI..."):
23
+ result = ball_detection.analyze_video(tfile.name)
24
+
25
+ st.write(f"πŸ” Trajectory points: {len(result['trajectory'])}")
26
+ st.write(f"🏁 Final Decision: **{result['decision']}**")
27
+ st.write(f"πŸš€ Ball Speed: **{result['speed_kmh']} km/h**")
28
+ if result["bounce_point"]:
29
+ st.info(f"πŸ“ Bounce detected at: {result['bounce_point']}")
30
+ if result["impact_point"]:
31
+ st.info(f"🎯 Impact point: {result['impact_point']}")
32
+
33
+ replay_path = replay_utils.generate_replay(
34
+ frames=result["frames"],
35
+ ball_path=result["trajectory"],
36
+ bounce_point=result["bounce_point"],
37
+ impact_point=result["impact_point"],
38
+ decision=result["decision"],
39
+ stump_zone=result["stump_zone"],
40
+ speed_kmh=result["speed_kmh"],
41
+ fps=result["fps"]
42
+ )
43
+
44
+ if replay_path and os.path.exists(replay_path):
45
+ st.success("βœ… Replay generated successfully!")
46
+ st.video(replay_path)
47
+ else:
48
+ st.error("⚠️ Replay generation failed or produced no video.")