Spaces:
Paused
Paused
added storage option
Browse files- .gitignore +3 -1
- app.py +74 -20
.gitignore
CHANGED
@@ -7,4 +7,6 @@ flagged/
|
|
7 |
.DS_Store
|
8 |
gradio_cached_examples/
|
9 |
venv/
|
10 |
-
__pycache__
|
|
|
|
|
|
7 |
.DS_Store
|
8 |
gradio_cached_examples/
|
9 |
venv/
|
10 |
+
__pycache__
|
11 |
+
*.db
|
12 |
+
*.sqlite3
|
app.py
CHANGED
@@ -6,10 +6,27 @@ import random
|
|
6 |
from ultralytics import YOLO
|
7 |
import numpy as np
|
8 |
from collections import defaultdict
|
|
|
|
|
9 |
|
10 |
# Import the supervision library
|
11 |
import supervision as sv
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
# --- File Downloading ---
|
14 |
# File URLs for sample images and video
|
15 |
file_urls = [
|
@@ -84,27 +101,17 @@ def show_preds_image(image_path):
|
|
84 |
|
85 |
# --- Video Processing Function (with Supervision) ---
|
86 |
def process_video_with_two_side_bins(video_path):
|
87 |
-
|
88 |
-
if video_path is None:
|
89 |
-
return
|
90 |
-
|
91 |
generator = sv.get_video_frames_generator(video_path)
|
92 |
|
93 |
try:
|
94 |
first_frame = next(generator)
|
95 |
except StopIteration:
|
96 |
-
print("No frames found in the provided video input.")
|
97 |
-
# Option 1: Return or yield a blank frame or error image
|
98 |
-
# For example, yield a blank black image of fixed size:
|
99 |
blank_frame = np.zeros((480, 640, 3), dtype=np.uint8)
|
100 |
yield cv2.cvtColor(blank_frame, cv2.COLOR_BGR2RGB)
|
101 |
return
|
102 |
|
103 |
-
first_frame = next(generator)
|
104 |
frame_height, frame_width, _ = first_frame.shape
|
105 |
|
106 |
-
# Define two bins: recyle and trash sides
|
107 |
-
|
108 |
bins = [
|
109 |
{
|
110 |
"name": "Recycle Bin",
|
@@ -130,7 +137,7 @@ def process_video_with_two_side_bins(video_path):
|
|
130 |
|
131 |
box_annotator = sv.BoxAnnotator(thickness=2)
|
132 |
label_annotator = sv.LabelAnnotator(
|
133 |
-
text_scale=1.2,
|
134 |
text_thickness=3,
|
135 |
text_position=sv.Position.TOP_LEFT,
|
136 |
)
|
@@ -140,14 +147,30 @@ def process_video_with_two_side_bins(video_path):
|
|
140 |
items_in_bins = {bin_["name"]: set() for bin_ in bins}
|
141 |
class_counts_per_bin = {bin_["name"]: defaultdict(int) for bin_ in bins}
|
142 |
|
143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
144 |
results = model(frame, verbose=False)[0]
|
145 |
detections = sv.Detections.from_ultralytics(results)
|
146 |
tracked_detections = tracker.update_with_detections(detections)
|
147 |
|
148 |
annotated_frame = frame.copy()
|
149 |
|
150 |
-
# Draw bins and
|
151 |
for bin_ in bins:
|
152 |
x1, y1, x2, y2 = bin_["coords"]
|
153 |
color = bin_["color"]
|
@@ -157,7 +180,7 @@ def process_video_with_two_side_bins(video_path):
|
|
157 |
bin_["name"],
|
158 |
(x1 + 5, y1 - 15),
|
159 |
cv2.FONT_HERSHEY_SIMPLEX,
|
160 |
-
1.5,
|
161 |
color,
|
162 |
3,
|
163 |
cv2.LINE_AA,
|
@@ -167,6 +190,10 @@ def process_video_with_two_side_bins(video_path):
|
|
167 |
yield cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB)
|
168 |
continue
|
169 |
|
|
|
|
|
|
|
|
|
170 |
for box, track_id, class_id in zip(
|
171 |
tracked_detections.xyxy,
|
172 |
tracked_detections.tracker_id,
|
@@ -175,14 +202,32 @@ def process_video_with_two_side_bins(video_path):
|
|
175 |
x1, y1, x2, y2 = map(int, box)
|
176 |
cx = (x1 + x2) // 2
|
177 |
cy = (y1 + y2) // 2
|
|
|
178 |
|
179 |
for bin_ in bins:
|
180 |
bx1, by1, bx2, by2 = bin_["coords"]
|
|
|
|
|
181 |
if (bx1 <= cx <= bx2) and (by1 <= cy <= by2):
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
186 |
|
187 |
labels = [
|
188 |
f"#{tid} {class_names[cid]}"
|
@@ -196,7 +241,7 @@ def process_video_with_two_side_bins(video_path):
|
|
196 |
scene=annotated_frame, detections=tracked_detections, labels=labels
|
197 |
)
|
198 |
|
199 |
-
#
|
200 |
y_pos = 50
|
201 |
for bin_name, class_count_dict in class_counts_per_bin.items():
|
202 |
text = (
|
@@ -208,7 +253,7 @@ def process_video_with_two_side_bins(video_path):
|
|
208 |
text,
|
209 |
(30, y_pos),
|
210 |
cv2.FONT_HERSHEY_SIMPLEX,
|
211 |
-
1.1,
|
212 |
(255, 255, 255),
|
213 |
3,
|
214 |
cv2.LINE_AA,
|
@@ -217,6 +262,15 @@ def process_video_with_two_side_bins(video_path):
|
|
217 |
|
218 |
yield cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB)
|
219 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
220 |
|
221 |
|
222 |
# --- Gradio Interface Setup ---
|
|
|
6 |
from ultralytics import YOLO
|
7 |
import numpy as np
|
8 |
from collections import defaultdict
|
9 |
+
import sqlite3
|
10 |
+
import time
|
11 |
|
12 |
# Import the supervision library
|
13 |
import supervision as sv
|
14 |
|
15 |
+
|
16 |
+
# --- Initialize SQLite DB for logging ---
|
17 |
+
conn = sqlite3.connect("detection_log.db", check_same_thread=False)
|
18 |
+
cursor = conn.cursor()
|
19 |
+
cursor.execute('''
|
20 |
+
CREATE TABLE IF NOT EXISTS detections (
|
21 |
+
timestamp REAL,
|
22 |
+
frame_number INTEGER,
|
23 |
+
bin_name TEXT,
|
24 |
+
class_name TEXT,
|
25 |
+
count INTEGER
|
26 |
+
)
|
27 |
+
''')
|
28 |
+
conn.commit()
|
29 |
+
|
30 |
# --- File Downloading ---
|
31 |
# File URLs for sample images and video
|
32 |
file_urls = [
|
|
|
101 |
|
102 |
# --- Video Processing Function (with Supervision) ---
|
103 |
def process_video_with_two_side_bins(video_path):
|
|
|
|
|
|
|
|
|
104 |
generator = sv.get_video_frames_generator(video_path)
|
105 |
|
106 |
try:
|
107 |
first_frame = next(generator)
|
108 |
except StopIteration:
|
|
|
|
|
|
|
109 |
blank_frame = np.zeros((480, 640, 3), dtype=np.uint8)
|
110 |
yield cv2.cvtColor(blank_frame, cv2.COLOR_BGR2RGB)
|
111 |
return
|
112 |
|
|
|
113 |
frame_height, frame_width, _ = first_frame.shape
|
114 |
|
|
|
|
|
115 |
bins = [
|
116 |
{
|
117 |
"name": "Recycle Bin",
|
|
|
137 |
|
138 |
box_annotator = sv.BoxAnnotator(thickness=2)
|
139 |
label_annotator = sv.LabelAnnotator(
|
140 |
+
text_scale=1.2,
|
141 |
text_thickness=3,
|
142 |
text_position=sv.Position.TOP_LEFT,
|
143 |
)
|
|
|
147 |
items_in_bins = {bin_["name"]: set() for bin_ in bins}
|
148 |
class_counts_per_bin = {bin_["name"]: defaultdict(int) for bin_ in bins}
|
149 |
|
150 |
+
frame_number = 0
|
151 |
+
BATCH_SIZE = 10
|
152 |
+
LOGGED_OBJECT_TTL_SECONDS = 300 # 5 minutes
|
153 |
+
insert_buffer = []
|
154 |
+
logged_objects = {}
|
155 |
+
|
156 |
+
for frame in generator:
|
157 |
+
frame_number += 1
|
158 |
+
current_time = time.time()
|
159 |
+
|
160 |
+
# Prune old logged objects every BATCH_SIZE frames
|
161 |
+
if frame_number % BATCH_SIZE == 0:
|
162 |
+
keys_to_remove = [key for key, ts in logged_objects.items()
|
163 |
+
if current_time - ts > LOGGED_OBJECT_TTL_SECONDS]
|
164 |
+
for key in keys_to_remove:
|
165 |
+
del logged_objects[key]
|
166 |
+
|
167 |
results = model(frame, verbose=False)[0]
|
168 |
detections = sv.Detections.from_ultralytics(results)
|
169 |
tracked_detections = tracker.update_with_detections(detections)
|
170 |
|
171 |
annotated_frame = frame.copy()
|
172 |
|
173 |
+
# Draw bins and labels
|
174 |
for bin_ in bins:
|
175 |
x1, y1, x2, y2 = bin_["coords"]
|
176 |
color = bin_["color"]
|
|
|
180 |
bin_["name"],
|
181 |
(x1 + 5, y1 - 15),
|
182 |
cv2.FONT_HERSHEY_SIMPLEX,
|
183 |
+
1.5,
|
184 |
color,
|
185 |
3,
|
186 |
cv2.LINE_AA,
|
|
|
190 |
yield cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB)
|
191 |
continue
|
192 |
|
193 |
+
# Clear counts for this frame
|
194 |
+
for bin_name in class_counts_per_bin:
|
195 |
+
class_counts_per_bin[bin_name].clear()
|
196 |
+
|
197 |
for box, track_id, class_id in zip(
|
198 |
tracked_detections.xyxy,
|
199 |
tracked_detections.tracker_id,
|
|
|
202 |
x1, y1, x2, y2 = map(int, box)
|
203 |
cx = (x1 + x2) // 2
|
204 |
cy = (y1 + y2) // 2
|
205 |
+
class_name = class_names[class_id]
|
206 |
|
207 |
for bin_ in bins:
|
208 |
bx1, by1, bx2, by2 = bin_["coords"]
|
209 |
+
bin_name = bin_["name"]
|
210 |
+
|
211 |
if (bx1 <= cx <= bx2) and (by1 <= cy <= by2):
|
212 |
+
key = (track_id, bin_name, class_name)
|
213 |
+
|
214 |
+
if track_id not in items_in_bins[bin_name]:
|
215 |
+
items_in_bins[bin_name].add(track_id)
|
216 |
+
class_counts_per_bin[bin_name][class_name] += 1
|
217 |
+
|
218 |
+
if key not in logged_objects:
|
219 |
+
timestamp = time.time()
|
220 |
+
insert_buffer.append((timestamp, frame_number, bin_name, class_name, 1))
|
221 |
+
logged_objects[key] = current_time
|
222 |
+
|
223 |
+
# Batch insert every BATCH_SIZE frames
|
224 |
+
if frame_number % BATCH_SIZE == 0 and insert_buffer:
|
225 |
+
cursor.executemany('''
|
226 |
+
INSERT INTO detections (timestamp, frame_number, bin_name, class_name, count)
|
227 |
+
VALUES (?, ?, ?, ?, ?)
|
228 |
+
''', insert_buffer)
|
229 |
+
conn.commit()
|
230 |
+
insert_buffer.clear()
|
231 |
|
232 |
labels = [
|
233 |
f"#{tid} {class_names[cid]}"
|
|
|
241 |
scene=annotated_frame, detections=tracked_detections, labels=labels
|
242 |
)
|
243 |
|
244 |
+
# Display counts per bin
|
245 |
y_pos = 50
|
246 |
for bin_name, class_count_dict in class_counts_per_bin.items():
|
247 |
text = (
|
|
|
253 |
text,
|
254 |
(30, y_pos),
|
255 |
cv2.FONT_HERSHEY_SIMPLEX,
|
256 |
+
1.1,
|
257 |
(255, 255, 255),
|
258 |
3,
|
259 |
cv2.LINE_AA,
|
|
|
262 |
|
263 |
yield cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB)
|
264 |
|
265 |
+
# Insert any remaining buffered data at end
|
266 |
+
if insert_buffer:
|
267 |
+
cursor.executemany('''
|
268 |
+
INSERT INTO detections (timestamp, frame_number, bin_name, class_name, count)
|
269 |
+
VALUES (?, ?, ?, ?, ?)
|
270 |
+
''', insert_buffer)
|
271 |
+
conn.commit()
|
272 |
+
insert_buffer.clear()
|
273 |
+
|
274 |
|
275 |
|
276 |
# --- Gradio Interface Setup ---
|