SkalskiP commited on
Commit
3338cd9
·
1 Parent(s): 57181ef

add Trackers Playground demo with tracking UI, class filtering, and video examples

Browse files
Files changed (3) hide show
  1. README.md +7 -9
  2. app.py +420 -0
  3. requirements.txt +2 -0
README.md CHANGED
@@ -1,14 +1,12 @@
1
  ---
2
- title: Trackers
3
- emoji: 🏃
4
- colorFrom: yellow
5
- colorTo: yellow
6
  sdk: gradio
7
- sdk_version: 6.5.1
8
  app_file: app.py
9
- pinned: false
10
  license: apache-2.0
11
- short_description: Detect objects with RF-DETR and track them with Trackers.
12
  ---
13
-
14
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Roboflow Trackers
3
+ emoji: 🔥
4
+ colorFrom: purple
5
+ colorTo: green
6
  sdk: gradio
7
+ sdk_version: 6.3.0
8
  app_file: app.py
9
+ suggested_hardware: l4x1
10
  license: apache-2.0
11
+ python_version: '3.11'
12
  ---
 
 
app.py ADDED
@@ -0,0 +1,420 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Gradio app for the trackers library — run object tracking on uploaded videos."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import subprocess
6
+ import tempfile
7
+ from pathlib import Path
8
+
9
+ import cv2
10
+ import gradio as gr
11
+
12
+ MAX_DURATION_SECONDS = 30
13
+
14
+ MODELS = [
15
+ "rfdetr-nano",
16
+ "rfdetr-small",
17
+ "rfdetr-medium",
18
+ "rfdetr-large",
19
+ "rfdetr-seg-nano",
20
+ "rfdetr-seg-small",
21
+ "rfdetr-seg-medium",
22
+ "rfdetr-seg-large",
23
+ ]
24
+
25
+ TRACKERS = ["bytetrack", "sort"]
26
+
27
+ COCO_CLASSES = [
28
+ "person",
29
+ "bicycle",
30
+ "car",
31
+ "motorcycle",
32
+ "airplane",
33
+ "bus",
34
+ "truck",
35
+ "cat",
36
+ "dog",
37
+ "sports ball",
38
+ ]
39
+
40
+ VIDEO_EXAMPLES = [
41
+ [
42
+ "https://storage.googleapis.com/com-roboflow-marketing/supervision/video-examples/bikes-1280x720-1.mp4",
43
+ "rfdetr-small",
44
+ "bytetrack",
45
+ 0.2,
46
+ 30,
47
+ 0.3,
48
+ 3,
49
+ 0.1,
50
+ 0.6,
51
+ [],
52
+ True,
53
+ True,
54
+ False,
55
+ False,
56
+ True,
57
+ False,
58
+ ],
59
+ [
60
+ "https://storage.googleapis.com/com-roboflow-marketing/supervision/video-examples/bikes-1280x720-2.mp4",
61
+ "rfdetr-seg-small",
62
+ "sort",
63
+ 0.2,
64
+ 30,
65
+ 0.3,
66
+ 3,
67
+ 0.3,
68
+ 0.6,
69
+ [],
70
+ True,
71
+ True,
72
+ False,
73
+ False,
74
+ True,
75
+ True,
76
+ ],
77
+ [
78
+ "https://storage.googleapis.com/com-roboflow-marketing/supervision/video-examples/cars-1280x720-1.mp4",
79
+ "rfdetr-small",
80
+ "bytetrack",
81
+ 0.2,
82
+ 30,
83
+ 0.3,
84
+ 3,
85
+ 0.1,
86
+ 0.6,
87
+ ["car"],
88
+ True,
89
+ True,
90
+ False,
91
+ True,
92
+ False,
93
+ False,
94
+ ],
95
+ [
96
+ "https://storage.googleapis.com/com-roboflow-marketing/supervision/video-examples/jets-1280x720-1.mp4",
97
+ "rfdetr-small",
98
+ "bytetrack",
99
+ 0.2,
100
+ 30,
101
+ 0.3,
102
+ 3,
103
+ 0.1,
104
+ 0.6,
105
+ [],
106
+ True,
107
+ True,
108
+ False,
109
+ False,
110
+ False,
111
+ False,
112
+ ],
113
+ [
114
+ "https://storage.googleapis.com/com-roboflow-marketing/supervision/video-examples/jets-1280x720-2.mp4",
115
+ "rfdetr-seg-small",
116
+ "bytetrack",
117
+ 0.2,
118
+ 30,
119
+ 0.3,
120
+ 3,
121
+ 0.1,
122
+ 0.6,
123
+ [],
124
+ True,
125
+ True,
126
+ False,
127
+ False,
128
+ True,
129
+ False,
130
+ ],
131
+ [
132
+ "https://storage.googleapis.com/com-roboflow-marketing/supervision/video-examples/vehicles-1280x720.mp4",
133
+ "rfdetr-small",
134
+ "bytetrack",
135
+ 0.2,
136
+ 30,
137
+ 0.3,
138
+ 3,
139
+ 0.1,
140
+ 0.6,
141
+ [],
142
+ True,
143
+ True,
144
+ True,
145
+ False,
146
+ True,
147
+ False,
148
+ ],
149
+ ]
150
+
151
+
152
+ def _get_video_duration(path: str) -> float:
153
+ """Return video duration in seconds using OpenCV."""
154
+ cap = cv2.VideoCapture(path)
155
+ if not cap.isOpened():
156
+ raise gr.Error("Could not open the uploaded video.")
157
+ fps = cap.get(cv2.CAP_PROP_FPS)
158
+ frame_count = cap.get(cv2.CAP_PROP_FRAME_COUNT)
159
+ cap.release()
160
+ if fps <= 0:
161
+ raise gr.Error("Could not determine video frame rate.")
162
+ return frame_count / fps
163
+
164
+
165
+ def track(
166
+ video_path: str,
167
+ model: str,
168
+ tracker: str,
169
+ confidence: float,
170
+ lost_track_buffer: int,
171
+ track_activation_threshold: float,
172
+ minimum_consecutive_frames: int,
173
+ minimum_iou_threshold: float,
174
+ high_conf_det_threshold: float,
175
+ classes: list[str] | None = None,
176
+ show_boxes: bool = True,
177
+ show_ids: bool = True,
178
+ show_labels: bool = False,
179
+ show_confidence: bool = False,
180
+ show_trajectories: bool = False,
181
+ show_masks: bool = False,
182
+ ) -> str:
183
+ """Run tracking on the uploaded video and return the output path."""
184
+ if video_path is None:
185
+ raise gr.Error("Please upload a video.")
186
+
187
+ duration = _get_video_duration(video_path)
188
+ if duration > MAX_DURATION_SECONDS:
189
+ raise gr.Error(
190
+ f"Video is {duration:.1f}s long. "
191
+ f"Maximum allowed duration is {MAX_DURATION_SECONDS}s."
192
+ )
193
+
194
+ tmp_dir = tempfile.mkdtemp()
195
+ output_path = str(Path(tmp_dir) / "output.mp4")
196
+
197
+ cmd = [
198
+ "trackers",
199
+ "track",
200
+ "--source",
201
+ video_path,
202
+ "--output",
203
+ output_path,
204
+ "--overwrite",
205
+ "--model",
206
+ model,
207
+ "--tracker",
208
+ tracker,
209
+ "--model.confidence",
210
+ str(confidence),
211
+ "--tracker.lost_track_buffer",
212
+ str(lost_track_buffer),
213
+ "--tracker.track_activation_threshold",
214
+ str(track_activation_threshold),
215
+ "--tracker.minimum_consecutive_frames",
216
+ str(minimum_consecutive_frames),
217
+ "--tracker.minimum_iou_threshold",
218
+ str(minimum_iou_threshold),
219
+ ]
220
+
221
+ # ByteTrack extra param
222
+ if tracker == "bytetrack":
223
+ cmd += ["--tracker.high_conf_det_threshold", str(high_conf_det_threshold)]
224
+
225
+ if classes:
226
+ cmd += ["--classes", ",".join(classes)]
227
+
228
+ if show_boxes:
229
+ cmd += ["--show-boxes"]
230
+ else:
231
+ cmd += ["--no-boxes"]
232
+ if show_ids:
233
+ cmd += ["--show-ids"]
234
+ if show_labels:
235
+ cmd += ["--show-labels"]
236
+ if show_confidence:
237
+ cmd += ["--show-confidence"]
238
+ if show_trajectories:
239
+ cmd += ["--show-trajectories"]
240
+ if show_masks:
241
+ cmd += ["--show-masks"]
242
+
243
+ result = subprocess.run(cmd, capture_output=True, text=True) # noqa: S603
244
+ if result.returncode != 0:
245
+ raise gr.Error(f"Tracking failed:\n{result.stderr[-500:]}")
246
+
247
+ return output_path
248
+
249
+
250
+ with gr.Blocks(title="Trackers Playground 🔥") as demo:
251
+ gr.Markdown(
252
+ "# Trackers Playground 🔥\n\n"
253
+ "Upload a video, detect COCO objects with "
254
+ "[RF-DETR](https://github.com/roboflow-ai/rf-detr) and track them with "
255
+ "[Trackers](https://github.com/roboflow/trackers)."
256
+ )
257
+
258
+ with gr.Row():
259
+ input_video = gr.Video(label="Input Video")
260
+ output_video = gr.Video(label="Tracked Video")
261
+
262
+ track_btn = gr.Button(value="Track", variant="primary")
263
+
264
+ with gr.Row():
265
+ model_dropdown = gr.Dropdown(
266
+ choices=MODELS,
267
+ value="rfdetr-small",
268
+ label="Detection Model",
269
+ )
270
+ tracker_dropdown = gr.Dropdown(
271
+ choices=TRACKERS,
272
+ value="bytetrack",
273
+ label="Tracker",
274
+ )
275
+
276
+ with gr.Accordion("Configuration", open=False):
277
+ with gr.Row():
278
+ with gr.Column():
279
+ gr.Markdown("### Model")
280
+ confidence_slider = gr.Slider(
281
+ minimum=0.0,
282
+ maximum=1.0,
283
+ value=0.2,
284
+ step=0.05,
285
+ label="Detection Confidence",
286
+ info="Minimum score for a detection to be kept.",
287
+ )
288
+ class_filter = gr.CheckboxGroup(
289
+ choices=COCO_CLASSES,
290
+ value=[],
291
+ label="Filter Classes",
292
+ info="Only track selected classes. None selected means all.",
293
+ )
294
+
295
+ with gr.Column():
296
+ gr.Markdown("### Tracker")
297
+ lost_track_buffer_slider = gr.Slider(
298
+ minimum=1,
299
+ maximum=120,
300
+ value=30,
301
+ step=1,
302
+ label="Lost Track Buffer",
303
+ info="Frames to keep a lost track before removing it.",
304
+ )
305
+ track_activation_slider = gr.Slider(
306
+ minimum=0.0,
307
+ maximum=1.0,
308
+ value=0.3,
309
+ step=0.05,
310
+ label="Track Activation Threshold",
311
+ info="Minimum score for a track to be activated.",
312
+ )
313
+ min_consecutive_slider = gr.Slider(
314
+ minimum=1,
315
+ maximum=10,
316
+ value=2,
317
+ step=1,
318
+ label="Minimum Consecutive Frames",
319
+ info="Detections needed before a track is confirmed.",
320
+ )
321
+ min_iou_slider = gr.Slider(
322
+ minimum=0.0,
323
+ maximum=1.0,
324
+ value=0.1,
325
+ step=0.05,
326
+ label="Minimum IoU Threshold",
327
+ info="Overlap required to match a detection to a track.",
328
+ )
329
+ high_conf_slider = gr.Slider(
330
+ minimum=0.0,
331
+ maximum=1.0,
332
+ value=0.6,
333
+ step=0.05,
334
+ label="High Confidence Detection Threshold",
335
+ info="Detections above this are matched first (ByteTrack only).",
336
+ )
337
+
338
+ with gr.Column():
339
+ gr.Markdown("### Visualization")
340
+ show_boxes_checkbox = gr.Checkbox(
341
+ value=True,
342
+ label="Show Boxes",
343
+ info="Draw bounding boxes around detections.",
344
+ )
345
+ show_ids_checkbox = gr.Checkbox(
346
+ value=True,
347
+ label="Show IDs",
348
+ info="Display track ID for each object.",
349
+ )
350
+ show_labels_checkbox = gr.Checkbox(
351
+ value=False,
352
+ label="Show Labels",
353
+ info="Display class name for each detection.",
354
+ )
355
+ show_confidence_checkbox = gr.Checkbox(
356
+ value=False,
357
+ label="Show Confidence",
358
+ info="Display detection confidence score.",
359
+ )
360
+ show_trajectories_checkbox = gr.Checkbox(
361
+ value=False,
362
+ label="Show Trajectories",
363
+ info="Draw motion path for each tracked object.",
364
+ )
365
+ show_masks_checkbox = gr.Checkbox(
366
+ value=False,
367
+ label="Show Masks",
368
+ info="Draw segmentation masks (seg models only).",
369
+ )
370
+
371
+ gr.Examples(
372
+ examples=VIDEO_EXAMPLES,
373
+ fn=track,
374
+ cache_examples=True,
375
+ inputs=[
376
+ input_video,
377
+ model_dropdown,
378
+ tracker_dropdown,
379
+ confidence_slider,
380
+ lost_track_buffer_slider,
381
+ track_activation_slider,
382
+ min_consecutive_slider,
383
+ min_iou_slider,
384
+ high_conf_slider,
385
+ class_filter,
386
+ show_boxes_checkbox,
387
+ show_ids_checkbox,
388
+ show_labels_checkbox,
389
+ show_confidence_checkbox,
390
+ show_trajectories_checkbox,
391
+ show_masks_checkbox,
392
+ ],
393
+ outputs=output_video,
394
+ )
395
+
396
+ track_btn.click(
397
+ fn=track,
398
+ inputs=[
399
+ input_video,
400
+ model_dropdown,
401
+ tracker_dropdown,
402
+ confidence_slider,
403
+ lost_track_buffer_slider,
404
+ track_activation_slider,
405
+ min_consecutive_slider,
406
+ min_iou_slider,
407
+ high_conf_slider,
408
+ class_filter,
409
+ show_boxes_checkbox,
410
+ show_ids_checkbox,
411
+ show_labels_checkbox,
412
+ show_confidence_checkbox,
413
+ show_trajectories_checkbox,
414
+ show_masks_checkbox,
415
+ ],
416
+ outputs=output_video,
417
+ )
418
+
419
+ if __name__ == "__main__":
420
+ demo.launch()
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ gradio>=6.3.0,<6.4.0
2
+ trackers[detection]@git+https://github.com/roboflow/trackers.git