Spaces:
Sleeping
Sleeping
File size: 5,445 Bytes
2649d00 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
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() |