dschandra commited on
Commit
456db98
·
verified ·
1 Parent(s): cb6edeb

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +24 -67
app.py CHANGED
@@ -34,6 +34,11 @@ paths and heavy downloads are avoided wherever possible. The code is
34
  fully self contained and uses only packages available in this runtime.
35
  """
36
 
 
 
 
 
 
37
  from __future__ import annotations
38
 
39
  import os
@@ -55,61 +60,31 @@ from drs_modules.visualization import (
55
 
56
 
57
  def analyse_appeal(video_path: str, review_seconds: int = 8) -> Tuple[str, Dict[str, Any]]:
58
- """Analyse the last few seconds of a match video and return DRS results.
59
-
60
- Parameters
61
- ----------
62
- video_path: str
63
- Path to the full match video recorded on the Live Match Recording page.
64
- review_seconds: int, optional
65
- Number of seconds from the end of the video to analyse. Defaults to 8.
66
-
67
- Returns
68
- -------
69
- Tuple[str, Dict[str, Any]]
70
- A message summarising the decision and a dictionary with the
71
- underlying data for display (decision text, ball speed, impact
72
- frame number, annotated video path and trajectory plot path).
73
- """
74
- # Create a temporary directory to hold intermediate files
75
  temp_dir = tempfile.mkdtemp()
76
  trimmed_path = os.path.join(temp_dir, "trimmed.mp4")
77
 
78
- # Step 1: Trim the last N seconds of the input video
79
  trim_last_seconds(video_path, trimmed_path, review_seconds)
80
-
81
- # Step 2: Detect and track the ball through the trimmed segment
82
  tracking_data = detect_and_track_ball(trimmed_path)
83
-
84
- # Step 3: Estimate the ball's trajectory (2D for simplicity) and predict
85
- # whether it will hit the stumps
86
  trajectory_model = estimate_trajectory(tracking_data["centers"], tracking_data["timestamps"])
87
  will_hit_stumps = predict_stumps_intersection(trajectory_model)
88
-
89
- # Step 4: Make a decision based on trajectory and impact detection
90
  decision, impact_frame_idx = make_lbw_decision(
91
- tracking_data["centers"],
92
- trajectory_model,
93
- will_hit_stumps,
94
  )
95
 
96
- # Step 5: Calculate ball speed (pixels per second scaled to km/h)
97
  total_distance_px = 0.0
98
  for i in range(1, len(tracking_data["centers"])):
99
  cx0, cy0 = tracking_data["centers"][i - 1]
100
  cx1, cy1 = tracking_data["centers"][i]
101
  total_distance_px += ((cx1 - cx0) ** 2 + (cy1 - cy0) ** 2) ** 0.5
102
- # Duration of captured frames
103
  duration = tracking_data["timestamps"][-1] - tracking_data["timestamps"][0]
104
  if duration <= 0:
105
  speed_kmh = 0.0
106
  else:
107
- # Convert pixel distance per second to km/h using an assumed scale
108
  pixels_per_metre = 50.0
109
  speed_mps = (total_distance_px / pixels_per_metre) / duration
110
  speed_kmh = speed_mps * 3.6
111
 
112
- # Step 6: Generate annotated replay video and trajectory plot
113
  annotated_video_path = os.path.join(temp_dir, "annotated.mp4")
114
  annotate_video_with_tracking(
115
  trimmed_path,
@@ -124,7 +99,6 @@ def analyse_appeal(video_path: str, review_seconds: int = 8) -> Tuple[str, Dict[
124
  tracking_data["centers"], trajectory_model, will_hit_stumps, plot_path
125
  )
126
 
127
- # Compose the message and result dictionary
128
  decision_message = f"Decision: {decision}"
129
  result = {
130
  "decision": decision,
@@ -138,48 +112,37 @@ def analyse_appeal(video_path: str, review_seconds: int = 8) -> Tuple[str, Dict[
138
 
139
 
140
  def build_interface() -> gr.Blocks:
141
- """Construct the Gradio interface with multiple pages."""
142
  with gr.Blocks(title="Cricket LBW DRS Demo") as demo:
143
  gr.Markdown(
144
  """# Digital Review System (LBW)
145
-
146
- This demo illustrates how a simplified digital review system can be
147
- implemented using computer vision techniques. You can record or
148
- upload match footage, and when an appeal occurs, the system will
149
- analyse the last few seconds to decide whether the batsman is **OUT**
150
- or **NOT OUT**. Alongside the decision you will receive an
151
- annotated replay, a 3D trajectory plot and an estimate of the ball
152
- speed.
153
- """
154
  )
155
 
156
  with gr.Tab("Live Match Recording"):
157
  video_input = gr.Video(
158
  label="Record or upload match video",
159
- sources=["upload", "webcam"],
160
- # Do not specify `type` because some versions of Gradio
161
- # reject that argument. The file path is available via
162
- # video_file.name in the callback.
163
  )
164
  out_video_path = gr.State()
165
 
166
  def on_video_upload(video_file):
167
  if video_file is None:
168
  return None
169
- file_path = video_file.name if hasattr(video_file, "name")else video_file
170
- #save_path = save_uploaded_video(video_file, video_file)
171
  return save_uploaded_video(file_path, video_file)
172
 
173
- video_input = gr.Video(
174
- label = "Record or Upload match video",
175
- sources =["upload", "webcam"]
 
176
  )
177
 
178
  gr.Markdown(
179
  """
180
- After recording or uploading a video, switch to the **LBW Review**
181
- tab and press **Analyse Appeal** to review the last 8 seconds.
182
- """
183
  )
184
 
185
  with gr.Tab("LBW Review"):
@@ -188,19 +151,12 @@ def build_interface() -> gr.Blocks:
188
  review_seconds = gr.Number(
189
  value=8, label="Seconds to review", minimum=2, maximum=20
190
  )
 
191
  decision_output = gr.Textbox(label="Decision", lines=1)
192
- ball_speed_output = gr.Textbox(
193
- label="Ball speed (km/h)", lines=1, interactive=False
194
- )
195
- impact_frame_output = gr.Textbox(
196
- label="Impact frame index", lines=1, interactive=False
197
- )
198
- annotated_video_output = gr.Video(
199
- label="Annotated replay video"
200
- )
201
- trajectory_plot_output = gr.Image(
202
- label="3D Trajectory plot"
203
- )
204
 
205
  def on_analyse(_):
206
  video_path = out_video_path.value
@@ -239,3 +195,4 @@ def build_interface() -> gr.Blocks:
239
  if __name__ == "__main__":
240
  demo = build_interface()
241
  demo.launch()
 
 
34
  fully self contained and uses only packages available in this runtime.
35
  """
36
 
37
+ """
38
+ Digital Review System (DRS) application for LBW decisions
39
+ ========================================================
40
+ """
41
+
42
  from __future__ import annotations
43
 
44
  import os
 
60
 
61
 
62
  def analyse_appeal(video_path: str, review_seconds: int = 8) -> Tuple[str, Dict[str, Any]]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  temp_dir = tempfile.mkdtemp()
64
  trimmed_path = os.path.join(temp_dir, "trimmed.mp4")
65
 
 
66
  trim_last_seconds(video_path, trimmed_path, review_seconds)
 
 
67
  tracking_data = detect_and_track_ball(trimmed_path)
 
 
 
68
  trajectory_model = estimate_trajectory(tracking_data["centers"], tracking_data["timestamps"])
69
  will_hit_stumps = predict_stumps_intersection(trajectory_model)
 
 
70
  decision, impact_frame_idx = make_lbw_decision(
71
+ tracking_data["centers"], trajectory_model, will_hit_stumps
 
 
72
  )
73
 
 
74
  total_distance_px = 0.0
75
  for i in range(1, len(tracking_data["centers"])):
76
  cx0, cy0 = tracking_data["centers"][i - 1]
77
  cx1, cy1 = tracking_data["centers"][i]
78
  total_distance_px += ((cx1 - cx0) ** 2 + (cy1 - cy0) ** 2) ** 0.5
79
+
80
  duration = tracking_data["timestamps"][-1] - tracking_data["timestamps"][0]
81
  if duration <= 0:
82
  speed_kmh = 0.0
83
  else:
 
84
  pixels_per_metre = 50.0
85
  speed_mps = (total_distance_px / pixels_per_metre) / duration
86
  speed_kmh = speed_mps * 3.6
87
 
 
88
  annotated_video_path = os.path.join(temp_dir, "annotated.mp4")
89
  annotate_video_with_tracking(
90
  trimmed_path,
 
99
  tracking_data["centers"], trajectory_model, will_hit_stumps, plot_path
100
  )
101
 
 
102
  decision_message = f"Decision: {decision}"
103
  result = {
104
  "decision": decision,
 
112
 
113
 
114
  def build_interface() -> gr.Blocks:
 
115
  with gr.Blocks(title="Cricket LBW DRS Demo") as demo:
116
  gr.Markdown(
117
  """# Digital Review System (LBW)
118
+ This demo lets you record or upload cricket match footage and analyse LBW appeals.
119
+ You'll get a 3D trajectory plot, annotated replay, and OUT/NOT OUT decision.
120
+ """
 
 
 
 
 
 
121
  )
122
 
123
  with gr.Tab("Live Match Recording"):
124
  video_input = gr.Video(
125
  label="Record or upload match video",
126
+ sources=["upload", "webcam"]
 
 
 
127
  )
128
  out_video_path = gr.State()
129
 
130
  def on_video_upload(video_file):
131
  if video_file is None:
132
  return None
133
+ file_path = video_file.name if hasattr(video_file, "name") else video_file
 
134
  return save_uploaded_video(file_path, video_file)
135
 
136
+ video_input.change(
137
+ fn=on_video_upload,
138
+ inputs=[video_input],
139
+ outputs=[out_video_path],
140
  )
141
 
142
  gr.Markdown(
143
  """
144
+ After recording or uploading a video, switch to the **LBW Review** tab and click **Analyse Appeal**.
145
+ """
 
146
  )
147
 
148
  with gr.Tab("LBW Review"):
 
151
  review_seconds = gr.Number(
152
  value=8, label="Seconds to review", minimum=2, maximum=20
153
  )
154
+
155
  decision_output = gr.Textbox(label="Decision", lines=1)
156
+ ball_speed_output = gr.Textbox(label="Ball speed (km/h)", lines=1, interactive=False)
157
+ impact_frame_output = gr.Textbox(label="Impact frame index", lines=1, interactive=False)
158
+ annotated_video_output = gr.Video(label="Annotated replay video")
159
+ trajectory_plot_output = gr.Image(label="3D Trajectory plot")
 
 
 
 
 
 
 
 
160
 
161
  def on_analyse(_):
162
  video_path = out_video_path.value
 
195
  if __name__ == "__main__":
196
  demo = build_interface()
197
  demo.launch()
198
+