Views
No views yet
| Property | Value |
|---|---|
| Category | Object Detection + Tracking + Zone Analytics (GstAnalytics) |
| Base Model | YOLO26 |
| Source Framework | PyTorch (Ultralytics) |
| Supported Precisions | FP32, FP16, INT8 (mixed-precision) |
| Inference Engine | OpenVINO |
| Hardware | CPU, GPU, NPU |
| Detected Class | person (COCO class 0) |
gvaanalytics element defines the protected zone and automatically attaches GstAnalyticsZoneMtd metadata to every tracked person whose center falls inside the polygon.
A Python probe reads this GstAnalytics metadata and raises an intrusion event the moment a tracked person first crosses into the restricted zone.
The model is a quantized (INT8) state-of-the-art detector; smaller variants run at high FPS on edge hardware.yolo26n, yolo26s, yolo26m, yolo26l, yolo26x.
Smaller variants (yolo26n, yolo26s) are recommended for high-FPS edge deployment.1python3 -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).VIRAT_S_000101.mp4) from the Intel Metro AI Suite project into the current directory.yolo26n_openvino_model/ -- FP32 or FP16 OpenVINO IR model directory.yolo26n_intrusion_int8.xml / yolo26n_intrusion_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.
gvaanalytics element, which automatically detects when tracked objects
are inside the zone using GstAnalytics metadata -- no Python polygon math
required.
A typical restricted-zone configuration on a 1280x720 source might be:1[
2 {
3 "id": "restricted_zone",
4 "type": "polygon",
5 "points": [
6 {"x": 0, "y": 200},
7 {"x": 300, "y": 200},
8 {"x": 300, "y": 400},
9 {"x": 0, "y": 400}
10 ]
11 }
12]gvaanalytics element attaches GstAnalyticsZoneMtd to each detection
whose center falls inside the polygon.
The Python probe checks for this metadata and raises an intrusion event the
first time each tracked person enters the zone.Note: The zone polygon supports arbitrary shapes (not just rectangles). Usedraw-zones=true(the default) so thatgvawatermarkrenders the zone boundary on the output video.
1source /opt/intel/openvino_2026/setupvars.sh
2source /opt/intel/dlstreamer/scripts/setup_dls_env.sh
3export PYTHONPATH=/opt/intel/dlstreamer/python:/opt/intel/dlstreamer/gstreamer/lib/python3/dist-packages:${PYTHONPATH:-}1import json
2import sys
3import gi
4gi.require_version("Gst", "1.0")
5gi.require_version("GstAnalytics", "1.0")
6gi.require_version("DLStreamerMeta", "1.0")
7gi.require_version("DLStreamerWatermarkMeta", "1.0")
8from gi.repository import Gst, GLib, GstAnalytics, DLStreamerMeta, DLStreamerWatermarkMeta
9
10Gst.init([])
11
12# Register DLStreamerMeta types so GstAnalytics iteration can handle them
13_ov = sys.modules["gi.overrides.GstAnalytics"]
14_ov.__mtd_types__[DLStreamerMeta.ZoneMtd.get_mtd_type()] = DLStreamerMeta.relation_meta_get_zone_mtd
15_ov.__mtd_types__[DLStreamerMeta.TripwireMtd.get_mtd_type()] = DLStreamerMeta.relation_meta_get_tripwire_mtd
16
17MODEL = "yolo26n_openvino_model/yolo26n.xml"
18VIDEO = "VIRAT_S_000101.mp4"
19ZONE_JSON = json.dumps([{
20 "id": "restricted_zone",
21 "type": "polygon",
22 "points": [{"x": 0, "y": 200}, {"x": 300, "y": 200},
23 {"x": 300, "y": 400}, {"x": 0, "y": 400}]
24}])
25
26pipeline = Gst.parse_launch(
27 f"filesrc location={VIDEO} ! decodebin3 ! videoconvert ! "
28 f"gvadetect model={MODEL} device=GPU threshold=0.5 ! queue ! "
29 f"gvatrack tracking-type=short-term-imageless ! queue ! "
30 f"gvaanalytics name=analytics draw-zones=true ! "
31 f"gvafpscounter ! identity name=probe ! gvawatermark name=watermark ! "
32 f"videoconvert ! video/x-raw,format=I420 ! "
33 f"openh264enc ! h264parse ! mp4mux ! filesink location=output_dlstreamer.mp4"
34)
35
36pipeline.get_by_name("analytics").set_property("zones", ZONE_JSON)
37pipeline.get_by_name("watermark").set_property("displ-cfg", "hide-roi=person")
38
39# Track IDs that have already triggered an intrusion event, so each intruder
40# is reported only once.
41flagged = set()
42
43def on_buffer(pad, info):
44 buf = info.get_buffer()
45 now = buf.pts / Gst.SECOND if buf.pts != Gst.CLOCK_TIME_NONE else 0.0
46 rmeta = GstAnalytics.buffer_get_analytics_relation_meta(buf)
47 if not rmeta:
48 return Gst.PadProbeReturn.OK
49
50 # Iterate only over object-detection entries
51 for od in rmeta.iter_on_type(GstAnalytics.ODMtd):
52 label = GLib.quark_to_string(od.get_obj_type())
53 if label != "person":
54 continue
55
56 # Find tracking ID via direct relation
57 track_id = None
58 for trk in od.iter_direct_related(GstAnalytics.RelTypes.RELATE_TO, GstAnalytics.TrackingMtd):
59 success, tracking_id, *_ = trk.get_info()
60 if success:
61 track_id = tracking_id
62 break
63 if track_id is None:
64 continue
65
66 # Check if gvaanalytics placed this detection inside the restricted zone
67 in_zone = False
68 for zone in od.iter_direct_related(GstAnalytics.RelTypes.RELATE_TO, DLStreamerMeta.ZoneMtd):
69 in_zone = True
70 break
71
72 if not in_zone:
73 continue
74
75 # Raise an intrusion event the first time each person enters the zone
76 if track_id not in flagged:
77 flagged.add(track_id)
78 _, x, y, w, h, _ = od.get_location()
79 print(f"INTRUSION id={track_id} t={now:.1f}s entered restricted zone at ({int(x + w/2)},{int(y + h)})")
80
81 return Gst.PadProbeReturn.OK
82
83pipeline.get_by_name("probe").get_static_pad("src").add_probe(Gst.PadProbeType.BUFFER, on_buffer)
84pipeline.set_state(Gst.State.PLAYING)
85pipeline.get_bus().timed_pop_filtered(Gst.CLOCK_TIME_NONE, Gst.MessageType.EOS | Gst.MessageType.ERROR)
86pipeline.set_state(Gst.State.NULL)1INTRUSION id=26 t=3.2s entered restricted zone at (147,341)
2INTRUSION id=27 t=4.6s entered restricted zone at (122,337)
3...output_dlstreamer.mp4.
The gvaanalytics element also draws the zone polygon on each frame via gvawatermark.
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.