black279 commited on
Commit
4f6ed2e
Β·
verified Β·
1 Parent(s): cddb6cd

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +188 -0
  2. best.pt +3 -0
  3. requirements.txt +8 -0
app.py ADDED
@@ -0,0 +1,188 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import mediapipe as mp
3
+ import numpy as np
4
+ import time
5
+ import gradio as gr
6
+ from ultralytics import YOLO
7
+ from PIL import Image
8
+
9
+ # ---------------- CONFIG ---------------- #
10
+ CONF_THRESHOLD = 0.5
11
+ COOLDOWN_TIME = 3 # seconds between alerts
12
+ MODEL_PATH = "best.pt" # Place your model in the same directory
13
+ FRAME_WIDTH = 640
14
+ FRAME_HEIGHT = 480
15
+ # ---------------------------------------- #
16
+
17
+ # ---------------- MediaPipe Setup ---------------- #
18
+ mp_pose = mp.solutions.pose
19
+ mp_drawing = mp.solutions.drawing_utils
20
+
21
+ # ---------------- Load YOLO Model ---------------- #
22
+ try:
23
+ model = YOLO(MODEL_PATH)
24
+ except:
25
+ print("Warning: Model not found. Using dummy detection.")
26
+ model = None
27
+
28
+ # ---------------- Global State ---------------- #
29
+ class DetectionState:
30
+ def __init__(self):
31
+ self.last_alert_time = 0
32
+ self.state = 'no_hold'
33
+ self.alert_count = 0
34
+ self.pose = mp_pose.Pose(
35
+ min_detection_confidence=0.5,
36
+ min_tracking_confidence=0.5
37
+ )
38
+
39
+ state_obj = DetectionState()
40
+
41
+ # ---------------- Utility Functions ---------------- #
42
+ def distance(a, b):
43
+ return np.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)
44
+
45
+ # ---------------- Littering Detection ---------------- #
46
+ def detect_littering(frame, pose_results):
47
+ feedback = "SAFE"
48
+ current_time = time.time()
49
+
50
+ # 1️⃣ Get Right Hand Position from MediaPipe
51
+ hand = None
52
+ if pose_results.pose_landmarks:
53
+ landmarks = pose_results.pose_landmarks.landmark
54
+ wrist = landmarks[mp_pose.PoseLandmark.RIGHT_WRIST.value]
55
+ hand = (wrist.x, wrist.y)
56
+
57
+ # 2️⃣ Run YOLO Detection
58
+ trash_positions = []
59
+ if model is not None:
60
+ results = model.predict(frame, conf=CONF_THRESHOLD, verbose=False)
61
+
62
+ for result in results:
63
+ boxes = result.boxes.xyxy.cpu().numpy()
64
+ confs = result.boxes.conf.cpu().numpy()
65
+ for (x1, y1, x2, y2), conf in zip(boxes, confs):
66
+ cx, cy = (x1+x2)/2/frame.shape[1], (y1+y2)/2/frame.shape[0]
67
+ trash_positions.append((cx, cy))
68
+ cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0,255,0), 2)
69
+ cv2.putText(frame, f"Trash {conf:.2f}", (int(x1), int(y1)-5),
70
+ cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0,255,0), 2)
71
+
72
+ # 3️⃣ State Machine
73
+ if hand and trash_positions:
74
+ dists = [distance(hand, t) for t in trash_positions]
75
+ min_dist = min(dists)
76
+
77
+ if state_obj.state == 'no_hold' and min_dist < 0.1:
78
+ state_obj.state = 'holding'
79
+ feedback = "HOLDING TRASH"
80
+
81
+ elif state_obj.state == 'holding':
82
+ feedback = "HOLDING TRASH"
83
+ if min_dist > 0.25:
84
+ state_obj.state = 'throwing'
85
+ feedback = "THROWING TRASH"
86
+
87
+ elif state_obj.state == 'throwing':
88
+ if min_dist > 0.25 and (current_time - state_obj.last_alert_time > COOLDOWN_TIME):
89
+ feedback = "⚠️ LITTERING DETECTED!"
90
+ state_obj.alert_count += 1
91
+ state_obj.last_alert_time = current_time
92
+ state_obj.state = 'no_hold'
93
+
94
+ # Draw MediaPipe Pose
95
+ if pose_results.pose_landmarks:
96
+ mp_drawing.draw_landmarks(frame, pose_results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
97
+
98
+ return frame, feedback
99
+
100
+ # ---------------- Gradio Processing Function ---------------- #
101
+ def process_frame(frame):
102
+ """Process a single frame from webcam"""
103
+ if frame is None:
104
+ return None, "No frame", 0
105
+
106
+ # Resize frame
107
+ frame = cv2.resize(frame, (FRAME_WIDTH, FRAME_HEIGHT))
108
+
109
+ # Process with MediaPipe
110
+ pose_results = state_obj.pose.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
111
+
112
+ # Detect littering
113
+ output, feedback = detect_littering(frame, pose_results)
114
+
115
+ # Add UI Overlay
116
+ cv2.rectangle(output, (0,0), (250,70), (50,50,50), -1)
117
+ cv2.putText(output, f'ALERTS: {state_obj.alert_count}', (10,40),
118
+ cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)
119
+
120
+ color = (0,0,255) if "⚠️" in feedback else (0,150,0)
121
+ cv2.rectangle(output, (250,0), (FRAME_WIDTH,70), color, -1)
122
+ cv2.putText(output, feedback, (260,45),
123
+ cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255,255,255), 2)
124
+
125
+ return output, feedback, state_obj.alert_count
126
+
127
+ def reset_alerts():
128
+ """Reset the alert counter"""
129
+ state_obj.alert_count = 0
130
+ state_obj.state = 'no_hold'
131
+ return 0
132
+
133
+ # ---------------- Gradio Interface ---------------- #
134
+ with gr.Blocks(title="Smart Garbage Patrol") as demo:
135
+ gr.Markdown("""
136
+ # πŸ—‘οΈ Smart Garbage Patrol - Littering Detection System
137
+
138
+ This system uses AI to detect littering behavior in real-time:
139
+ - **MediaPipe** tracks hand movements
140
+ - **YOLOv8** detects trash objects
141
+ - **State Machine** identifies throwing behavior
142
+
143
+ **How it works:**
144
+ 1. Hold trash near your hand β†’ System detects "HOLDING TRASH"
145
+ 2. Move hand away quickly β†’ System detects "THROWING TRASH"
146
+ 3. If trash is released β†’ "⚠️ LITTERING DETECTED!"
147
+ """)
148
+
149
+ with gr.Row():
150
+ with gr.Column():
151
+ webcam = gr.Image(sources=["webcam"], streaming=True, type="numpy")
152
+ reset_btn = gr.Button("πŸ”„ Reset Alert Count", variant="secondary")
153
+
154
+ with gr.Column():
155
+ output_frame = gr.Image(label="Detection Output")
156
+ status_text = gr.Textbox(label="Current Status", interactive=False)
157
+ alert_counter = gr.Number(label="Total Alerts", value=0, interactive=False)
158
+
159
+ # Process webcam stream
160
+ webcam.stream(
161
+ fn=process_frame,
162
+ inputs=[webcam],
163
+ outputs=[output_frame, status_text, alert_counter],
164
+ show_progress=False
165
+ )
166
+
167
+ # Reset button
168
+ reset_btn.click(
169
+ fn=reset_alerts,
170
+ outputs=[alert_counter]
171
+ )
172
+
173
+ gr.Markdown("""
174
+ ### πŸ“ Notes:
175
+ - Place your trained YOLOv8 model as `best.pt` in the app directory
176
+ - The system needs webcam access to function
177
+ - Alert cooldown: 3 seconds between detections
178
+ - Press **Reset** to clear the alert counter
179
+
180
+ ### πŸš€ Deployment on Hugging Face Spaces:
181
+ 1. Create a new Space with **Gradio SDK**
182
+ 2. Upload this script as `app.py`
183
+ 3. Upload your model file as `best.pt`
184
+ 4. Add `requirements.txt` with dependencies
185
+ """)
186
+
187
+ if __name__ == "__main__":
188
+ demo.launch()
best.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ecd2ba9445075544e88722a077558cbc31de5e5ed947e9a26029e50c5ee6bead
3
+ size 5456360
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ gradio==4.44.0
2
+ opencv-python-headless==4.10.0.84
3
+ mediapipe==0.10.14
4
+ numpy==1.26.4
5
+ ultralytics==8.2.103
6
+ pillow==10.4.0
7
+ torch==2.3.1
8
+ torchvision==0.18.1