dschandra's picture
Rename main.py to app.py
dcae6b4 verified
import cv2
import numpy as np
import gradio as gr
import tempfile
from pathlib import Path
from cvzone.ColorModule import ColorFinder
from batsman import batsman_detect
from ball_detect import ball_detect
# ---------------------------------------------------
# Static detection parameters (tune these if needed)
# ---------------------------------------------------
mycolorFinder = ColorFinder(False)
# HSV range for ball – tune for your footage
hsvVals = {
"hmin": 10,
"smin": 44,
"vmin": 192,
"hmax": 125,
"smax": 114,
"vmax": 255,
}
# RGB range & Canny thresholds for batsman – replace with tuned values
tuned_rgb_lower = np.array([112, 0, 181])
tuned_rgb_upper = np.array([255, 255, 255])
tuned_canny_threshold1 = 100
tuned_canny_threshold2 = 200
# ---------------------------------------------------
# Helper to classify each frame event
# ---------------------------------------------------
def ball_pitch_pad(x, x_prev, prev_x_diff, y, y_prev, prev_y_diff, batLeg):
"""Return 'Pad', 'Pitch' or 'Motion' based on ball & batsman coords."""
if x_prev == 0 and y_prev == 0:
return "Motion", 0, 0
if abs(x - x_prev) > 3 * abs(prev_x_diff) and abs(prev_x_diff) > 0:
if y < batLeg:
return "Pad", x - x_prev, y - y_prev
if y - y_prev < 0 and prev_y_diff > 0:
if y < batLeg:
return "Pad", x - x_prev, y - y_prev
else:
return "Pitch", x - x_prev, y - y_prev
return "Motion", x - x_prev, y - y_prev
# ---------------------------------------------------
# Main analysis routine wrapped for Gradio
# ---------------------------------------------------
def detect_lbw(video):
"""Run the LBW detector on an uploaded video, return annotated clip + verdict."""
# Accept both dict (gradio 4.x) or str
video_path = video if isinstance(video, (str, Path)) else video.get("name")
cap = cv2.VideoCapture(str(video_path))
if not cap.isOpened():
raise ValueError("Unable to open uploaded video.")
fps = cap.get(cv2.CAP_PROP_FPS) or 25
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
# Prepare temporary output file for annotated video
tmpfile = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
out_path = tmpfile.name
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
writer = cv2.VideoWriter(out_path, fourcc, fps, (width, height))
# Tracking variables
x = y = batLeg = 0
x_prev = y_prev = 0
prev_x_diff = prev_y_diff = 0
lbw_detected = False
while True:
x_prev, y_prev = x, y
success, img = cap.read()
if not success:
break
overlay = img.copy()
# 1️⃣ Ball detection
_, x, y = ball_detect(img, mycolorFinder, hsvVals)
if x and y:
cv2.circle(overlay, (x, y), 8, (255, 0, 0), -1)
# 2️⃣ Batsman detection
batsmanContours = batsman_detect(
img,
tuned_rgb_lower,
tuned_rgb_upper,
tuned_canny_threshold1,
tuned_canny_threshold2,
)
# Compute batsman's leg (lowest y among contours above the ball)
current_batLeg = float("inf")
for cnt in batsmanContours:
if cv2.contourArea(cnt) > 5000 and y != 0 and min(cnt[:, :, 1]) < y:
leg_candidate = max(cnt[:, :, 1])
current_batLeg = min(current_batLeg, leg_candidate)
cv2.drawContours(overlay, cnt, -1, (0, 255, 0), 3)
batLeg = current_batLeg if current_batLeg != float("inf") else batLeg
# 3️⃣ Classify the motion event for this frame
motion_type, prev_x_diff, prev_y_diff = ball_pitch_pad(
x, x_prev, prev_x_diff, y, y_prev, prev_y_diff, batLeg
)
if motion_type == "Pad":
lbw_detected = True
cv2.putText(
overlay,
"PAD CONTACT",
(50, 80),
cv2.FONT_HERSHEY_SIMPLEX,
1.6,
(0, 0, 255),
4,
cv2.LINE_AA,
)
elif motion_type == "Pitch":
cv2.putText(
overlay,
"Bounced",
(50, 80),
cv2.FONT_HERSHEY_SIMPLEX,
1.6,
(0, 255, 255),
4,
cv2.LINE_AA,
)
writer.write(overlay)
cap.release()
writer.release()
verdict = "✅ Potential LBW Detected!" if lbw_detected else "❌ No LBW Detected."
return out_path, verdict
# ---------------------------------------------------
# Gradio interface
# ---------------------------------------------------
demo = gr.Interface(
fn=detect_lbw,
inputs=gr.Video(label="Upload cricket clip (side-on view)"),
outputs=[
gr.Video(label="Annotated Review"),
gr.Textbox(label="Decision"),
],
title="Automated LBW Detector",
description=(
"Upload a short video of the delivery. The system analyses the ball & batsman "
"interaction frame-by-frame, overlays detections, and flags potential LBW instances."
),
)
if __name__ == "__main__":
demo.launch()