Views
No views yet
| Property | Value |
|---|---|
| Category | Object Detection + Multi-Object Tracking |
| Base Model | YOLO26 (Ultralytics) + DLStreamer gvatrack (Kalman filter tracker) |
| Source Framework | PyTorch (Ultralytics) |
| Supported Precisions | FP32, FP16, INT8 (mixed-precision) |
| Inference Engine | OpenVINO |
| Hardware | CPU, GPU, NPU |
| Detected Class(es) | Configurable (default: all 80 COCO classes) |
gvadetect + gvatrack element with tracking-type=short-term-imageless.track_id that persists across frames as long as the object remains visible.
Outputs include per-object trajectories suitable for path analysis, dwell-time computation, and zone-based event triggers.yolo26n, yolo26s, yolo26m, yolo26l, yolo26x.
Smaller variants (yolo26n, yolo26s) are recommended for high-FPS edge deployment.
The default tracker is short-term-imageless (Kalman filter-based, no image data required).
DLStreamer also supports tracking-type=deep-sort for more robust re-identification using a feature extraction model (e.g., mars-small128).ffmpeg (sudo apt install ffmpeg) -- used by both samples to encode output video1python3 -m venv .venv --system-site-packages
2source .venv/bin/activateNote: The--system-site-packagesflag is required so the virtual environment can access the system-installed OpenVINO and DLStreamer Python packages.
1chmod +x export_and_quantize.sh
2./export_and_quantize.sh1./export_and_quantize.sh yolo26n FP32 # full-precision
2./export_and_quantize.sh yolo26n INT8 # quantized
3./export_and_quantize.sh yolo26s # larger variant, default FP16yolo26n with any variant (yolo26s, yolo26m, yolo26l, yolo26x).
The second argument selects the precision (FP32, FP16, INT8); the default is FP16.openvino, ultralytics; adds nncf for INT8).test_video.mp4) and a sample test image (test.jpg).yolo26n_openvino_model/ -- FP32 or FP16 OpenVINO IR model directory.yolo26n_tracking_int8.xml / yolo26n_tracking_int8.bin -- INT8 quantized model (only when INT8 is selected).| Precision | CPU | GPU | NPU |
|---|---|---|---|
| FP32 | Yes | Yes | No |
| FP16 | Yes | Yes | Yes |
| INT8 | Yes | Yes | Yes |
Note: The INT8 calibration uses frames from the bundled sample video. For production accuracy, replace it with a representative set of frames from the target deployment site.
gvadetect on
test_video.mp4, attaches persistent track IDs with gvatrack
(short-term-imageless tracker), and overlays bounding boxes with
gvawatermark. Frames are pulled from an appsink, per-track trajectory
polylines are drawn with OpenCV, and the result is muxed to output_dlstreamer.mp4
(H.264 via ffmpeg).Notes on running this sample:
Use the FP16 IR (yolo26n_openvino_model/yolo26n.xml). Class names are read automatically from the model's embeddedmetadata.yamlby DLStreamer 2026.0+ -- no externallabels-fileis required. ExportPYTHONPATHso the DLStreamer Python module is importable:bash1source /opt/intel/openvino_2026/setupvars.sh 2source /opt/intel/dlstreamer/scripts/setup_dls_env.sh 3export PYTHONPATH=/opt/intel/dlstreamer/python:\ 4/opt/intel/dlstreamer/gstreamer/lib/python3/dist-packages:${PYTHONPATH:-}
1import subprocess
2from collections import defaultdict
3
4import numpy as np
5import gi
6
7gi.require_version("Gst", "1.0")
8gi.require_version("GstAnalytics", "1.0")
9from gi.repository import Gst, GLib, GstAnalytics
10
11Gst.init([])
12
13# Import cv2 after Gst.init to avoid GStreamer re-initialization conflicts.
14import cv2
15
16# For CPU: change device=GPU to device=CPU.
17# For NPU: change device=GPU to device=NPU (batch-size=1, nireq=4 recommended).
18pipeline_str = (
19 "filesrc location=test_video.mp4 ! decodebin3 ! "
20 "videoconvert ! "
21 "gvadetect model=yolo26n_openvino_model/yolo26n.xml "
22 "device=GPU "
23 "threshold=0.4 ! queue ! "
24 "gvatrack tracking-type=short-term-imageless ! queue ! "
25 "gvawatermark ! appsink name=sink emit-signals=false sync=false"
26)
27pipeline = Gst.parse_launch(pipeline_str)
28appsink = pipeline.get_by_name("sink")
29
30# Distinct colors for trajectory lines (one per track ID).
31COLORS = [
32 (255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 0),
33 (255, 0, 255), (0, 255, 255), (128, 0, 255), (255, 128, 0),
34]
35track_history: dict[int, list[tuple[int, int]]] = defaultdict(list)
36
37pipeline.set_state(Gst.State.PLAYING)
38
39proc = None
40
41while True:
42 sample = appsink.emit("pull-sample")
43 if sample is None:
44 break
45
46 buf = sample.get_buffer()
47 caps = sample.get_caps()
48 struct = caps.get_structure(0)
49 width = struct.get_value("width")
50 height = struct.get_value("height")
51
52 # Start ffmpeg encoder on the first frame.
53 if proc is None:
54 ok, fps_num, fps_den = struct.get_fraction("framerate")
55 fps = fps_num / fps_den if ok and fps_den > 0 else 30.0
56 proc = subprocess.Popen(
57 ["ffmpeg", "-y", "-f", "rawvideo", "-pix_fmt", "bgr24",
58 "-s", f"{width}x{height}", "-r", str(fps),
59 "-i", "pipe:0", "-c:v", "libx264", "-pix_fmt", "yuv420p",
60 "-movflags", "+faststart", "output_dlstreamer.mp4"],
61 stdin=subprocess.PIPE, stderr=subprocess.DEVNULL,
62 )
63
64 # Read detection / tracking metadata via GstAnalytics.
65 rmeta = GstAnalytics.buffer_get_analytics_relation_meta(buf)
66 regions_data = []
67 if rmeta is not None:
68 od_entries = []
69 trk_map = {} # metadata_id -> tracking_id
70 idx = 1
71 while True:
72 ok_od, od = rmeta.get_od_mtd(idx)
73 ok_trk, trk = rmeta.get_tracking_mtd(idx)
74 if not ok_od and not ok_trk:
75 break
76 if ok_od:
77 label = GLib.quark_to_string(od.get_obj_type())
78 _, x, y, w, h, conf = od.get_location()
79 od_entries.append((idx, label, int(x + w / 2), int(y + h / 2)))
80 if ok_trk:
81 ok2, tid, _, _, _ = trk.get_info()
82 if ok2:
83 trk_map[idx] = tid
84 idx += 1
85 for od_id, label, cx, cy in od_entries:
86 tid = 0
87 for trk_meta_id, tracking_id in trk_map.items():
88 if rmeta.get_relation(od_id, trk_meta_id) != GstAnalytics.RelTypes.NONE:
89 tid = tracking_id
90 break
91 regions_data.append((tid, label, cx, cy))
92
93 # Map buffer read-only and copy pixels to a writable numpy array.
94 success, map_info = buf.map(Gst.MapFlags.READ)
95 if not success:
96 continue
97 arr = np.ndarray((height, width, 3), dtype=np.uint8,
98 buffer=map_info.data).copy()
99 buf.unmap(map_info)
100
101 # Draw per-track trajectory polylines on the frame copy.
102 for tid, label, cx, cy in regions_data:
103 track = track_history[tid]
104 track.append((cx, cy))
105 if len(track) > 30:
106 track.pop(0)
107 color = COLORS[tid % len(COLORS)]
108 pts = np.array(track, dtype=np.int32).reshape((-1, 1, 2))
109 cv2.polylines(arr, [pts], False, color, 2)
110 print(f" Track {tid}: {label} center=({cx},{cy})", flush=True)
111
112 proc.stdin.write(arr.tobytes())
113
114pipeline.set_state(Gst.State.NULL)
115if proc:
116 proc.stdin.close()
117 proc.wait()
118print("Wrote output_dlstreamer.mp4", flush=True)
device=GPU -- default in the sample code.device=CPU -- change device=GPU to device=CPU.device=NPU -- change device=GPU to device=NPU; use batch-size=1 and nireq=4 for best NPU utilization.