vagheshpatel commited on
Commit
67d76c6
·
verified ·
1 Parent(s): 10c09b1

Sync loitering-detection from metro-analytics-catalog

Browse files
Files changed (3) hide show
  1. LICENSE +21 -45
  2. README.md +99 -40
  3. expected_output_dlstreamer.gif +2 -2
LICENSE CHANGED
@@ -1,45 +1,21 @@
1
- This directory contains two categories of content under different licenses.
2
-
3
-
4
- Scripts and Documentation
5
- -------------------------
6
-
7
- The scripts (export_and_quantize.sh) and documentation (README.md) in this
8
- directory are original works by Intel Corporation, licensed under the
9
- MIT License.
10
-
11
- Copyright (C) Intel Corporation
12
-
13
- Permission is hereby granted, free of charge, to any person obtaining a copy
14
- of this software and associated documentation files (the "Software"), to deal
15
- in the Software without restriction, including without limitation the rights
16
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17
- copies of the Software, and to permit persons to whom the Software is
18
- furnished to do so, subject to the following conditions:
19
-
20
- The above copyright notice and this permission notice shall be included in
21
- all copies or substantial portions of the Software.
22
-
23
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
- THE SOFTWARE.
30
-
31
-
32
- YOLO26 Model
33
- ------------
34
-
35
- The YOLO26 model weights and the Ultralytics framework are developed by
36
- Ultralytics and licensed under the GNU Affero General Public License v3.0
37
- (AGPL-3.0).
38
-
39
- Source: https://github.com/ultralytics/ultralytics
40
- License: https://github.com/ultralytics/ultralytics/blob/main/LICENSE
41
- Docs: https://docs.ultralytics.com/models/yolo26/
42
-
43
- Users must comply with the AGPL-3.0 license terms when using, modifying,
44
- or distributing the YOLO26 model weights or Ultralytics software.
45
- For commercial licensing options, see https://www.ultralytics.com/license.
 
1
+ MIT License
2
+
3
+ Copyright (c) Intel Corporation.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -1,5 +1,5 @@
1
  ---
2
- license: other
3
  license_link: LICENSE
4
  library_name: openvino
5
  pipeline_tag: object-detection
@@ -11,6 +11,8 @@ tags:
11
  - loitering-detection
12
  - zone-analytics
13
  - tracking
 
 
14
  - edge-ai
15
  - metro
16
  - dlstreamer
@@ -24,7 +26,7 @@ language:
24
 
25
  | Property | Value |
26
  |---|---|
27
- | **Category** | Object Detection + Tracking + Zone Analytics |
28
  | **Source Framework** | PyTorch (Ultralytics) |
29
  | **Supported Precisions** | FP32, FP16, INT8 (mixed-precision) |
30
  | **Inference Engine** | OpenVINO |
@@ -37,7 +39,8 @@ language:
37
 
38
  Loitering Detection is a Metro Analytics use case that flags people who remain inside a configurable region of interest for longer than a dwell-time threshold.
39
  It is built on [YOLO26](https://docs.ultralytics.com/models/yolo26/) for person detection, paired with a multi-object tracker that assigns persistent IDs across frames.
40
- A polygon zone defines the area to monitor; for each tracked person whose bounding-box anchor falls inside the zone, the application accumulates dwell time and raises a loitering event when the threshold is exceeded.
 
41
 
42
  Typical Metro deployments include:
43
 
@@ -117,17 +120,30 @@ Output files:
117
  > For production accuracy, replace it with a representative set of frames from
118
  > the target deployment site.
119
 
120
- ### Defining the Region of Interest
121
 
122
- The zone is a rectangular ROI expressed as `x_min,y_min,x_max,y_max` in the
123
- original input frame coordinates (not the 640x640 model input).
124
- DLStreamer's `gvaattachroi` element attaches the ROI to every buffer, and
125
- `gvadetect inference-region=1` (`roi-list`) restricts inference to that ROI
126
- only -- no Python polygon math required.
127
  A typical surveillance-zone configuration on a 1280x720 source might be:
128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  ```text
130
- roi=0,200,300,400 # ROI for gvaattachroi (x_min,y_min,x_max,y_max)
131
  LOITERING_SECONDS = 5.0 # dwell threshold, in seconds (demo value)
132
  ```
133
 
@@ -136,8 +152,13 @@ LOITERING_SECONDS = 5.0 # dwell threshold, in seconds (demo value)
136
  > increase this to 10--30 seconds depending on the site's operational
137
  > requirements.
138
 
139
- Per-person dwell time is measured at the bottom-center of the bounding box
140
- (the foot anchor), which most closely approximates the person's ground position.
 
 
 
 
 
141
 
142
  ### DLStreamer Sample
143
 
@@ -153,60 +174,89 @@ Run loitering detection:
153
 
154
  ```python
155
  from collections import defaultdict
156
- import ctypes
 
157
  import gi
158
  gi.require_version("Gst", "1.0")
159
- from gi.repository import Gst
160
- from gstgva import Tensor, VideoFrame
 
 
161
 
162
- Gst.init(None)
163
 
164
- libgst = ctypes.CDLL("libgstreamer-1.0.so.0")
165
- libgst.gst_structure_new_empty.argtypes = [ctypes.c_char_p]
166
- libgst.gst_structure_new_empty.restype = ctypes.c_void_p
 
167
 
168
  MODEL = "yolo26n_openvino_model/yolo26n.xml"
169
  VIDEO = "VIRAT_S_000101.mp4"
170
- ROI = "0,200,300,400"
 
 
 
 
 
171
  LOITERING_SECONDS = 5.0
172
 
173
  pipeline = Gst.parse_launch(
174
  f"filesrc location={VIDEO} ! decodebin3 ! videoconvert ! "
175
- f"gvaattachroi roi={ROI} ! "
176
- f"gvadetect inference-region=1 model={MODEL} device=GPU threshold=0.5 ! queue ! "
177
  f"gvatrack tracking-type=short-term-imageless ! queue ! "
178
- f"gvafpscounter ! identity name=probe ! gvawatermark ! videoconvert ! video/x-raw,format=I420 ! "
 
 
179
  f"openh264enc ! h264parse ! mp4mux ! filesink location=output_dlstreamer.mp4"
180
  )
181
 
 
 
 
182
  dwell = defaultdict(float)
183
  last_seen = {}
184
  flagged = set()
185
 
186
  def on_buffer(pad, info):
187
  buf = info.get_buffer()
188
- frame = VideoFrame(buf, caps=pad.get_current_caps())
189
  now = buf.pts / Gst.SECOND if buf.pts != Gst.CLOCK_TIME_NONE else 0.0
190
-
191
- for region in frame.regions():
192
- if region.label() != "person":
 
 
 
 
 
193
  continue
194
- oid = region.object_id()
195
- if oid <= 0:
 
 
 
 
 
 
 
196
  continue
197
 
198
- dwell[oid] += now - last_seen.get(oid, now)
199
- last_seen[oid] = now
 
 
 
200
 
201
- # Show dwell time on the bounding box (rendered by gvawatermark)
202
- t = Tensor(libgst.gst_structure_new_empty(b"dwell"))
203
- t.set_label(f" {dwell[oid]:.1f}s")
204
- region.add_tensor(t)
 
 
205
 
206
- if dwell[oid] >= LOITERING_SECONDS and oid not in flagged:
207
- flagged.add(oid)
208
- rect = region.rect()
209
- print(f"LOITERING id={oid} dwell={dwell[oid]:.1f}s pos=({int(rect.x + rect.w/2)},{int(rect.y + rect.h)})")
210
 
211
  return Gst.PadProbeReturn.OK
212
 
@@ -224,7 +274,8 @@ LOITERING id=27 dwell=5.0s pos=(122,337)
224
  ...
225
  ```
226
 
227
- The annotated video is saved to `output.mp4`.
 
228
 
229
  #### Expected Output
230
 
@@ -248,6 +299,14 @@ Licensed under the MIT License. See [LICENSE](LICENSE) for details.
248
  - [YOLO26 Documentation](https://docs.ultralytics.com/models/yolo26/)
249
  - [OpenVINO YOLO26 Notebook](https://github.com/openvinotoolkit/openvino_notebooks/blob/latest/notebooks/yolov26-optimization/yolov26-object-detection.ipynb)
250
  - [Intel DLStreamer Object Tracking](https://docs.openedgeplatform.intel.com/2026.0/edge-ai-libraries/dlstreamer/elements/gvatrack.html)
 
251
  - [OpenVINO Documentation](https://docs.openvino.ai/)
252
  - [NNCF Post-Training Quantization](https://docs.openvino.ai/latest/nncf_ptq_introduction.html)
253
  - [COCO Dataset](https://cocodataset.org/)
 
 
 
 
 
 
 
 
1
  ---
2
+ license: mit
3
  license_link: LICENSE
4
  library_name: openvino
5
  pipeline_tag: object-detection
 
11
  - loitering-detection
12
  - zone-analytics
13
  - tracking
14
+ - gstanalytics
15
+ - gvaanalytics
16
  - edge-ai
17
  - metro
18
  - dlstreamer
 
26
 
27
  | Property | Value |
28
  |---|---|
29
+ | **Category** | Object Detection + Tracking + Zone Analytics (GstAnalytics) |
30
  | **Source Framework** | PyTorch (Ultralytics) |
31
  | **Supported Precisions** | FP32, FP16, INT8 (mixed-precision) |
32
  | **Inference Engine** | OpenVINO |
 
39
 
40
  Loitering Detection is a Metro Analytics use case that flags people who remain inside a configurable region of interest for longer than a dwell-time threshold.
41
  It is built on [YOLO26](https://docs.ultralytics.com/models/yolo26/) for person detection, paired with a multi-object tracker that assigns persistent IDs across frames.
42
+ DLStreamer's `gvaanalytics` element defines the monitoring zone and automatically attaches `GstAnalyticsZoneMtd` metadata to every tracked person whose center falls inside the polygon.
43
+ A Python probe reads this GstAnalytics metadata to accumulate per-person dwell time and raises a loitering event when the threshold is exceeded.
44
 
45
  Typical Metro deployments include:
46
 
 
120
  > For production accuracy, replace it with a representative set of frames from
121
  > the target deployment site.
122
 
123
+ ### Defining the Monitoring Zone
124
 
125
+ The zone is a polygon defined in JSON and passed to DLStreamer's
126
+ `gvaanalytics` element, which automatically detects when tracked objects
127
+ are inside the zone using GstAnalytics metadata -- no Python polygon math
128
+ required.
 
129
  A typical surveillance-zone configuration on a 1280x720 source might be:
130
 
131
+ ```json
132
+ [
133
+ {
134
+ "id": "loiter_zone",
135
+ "type": "polygon",
136
+ "points": [
137
+ {"x": 0, "y": 200},
138
+ {"x": 300, "y": 200},
139
+ {"x": 300, "y": 400},
140
+ {"x": 0, "y": 400}
141
+ ]
142
+ }
143
+ ]
144
+ ```
145
+
146
  ```text
 
147
  LOITERING_SECONDS = 5.0 # dwell threshold, in seconds (demo value)
148
  ```
149
 
 
152
  > increase this to 10--30 seconds depending on the site's operational
153
  > requirements.
154
 
155
+ The `gvaanalytics` element attaches `GstAnalyticsZoneMtd` to each detection
156
+ whose center falls inside the polygon. The Python probe checks for this
157
+ metadata to accumulate per-person dwell time.
158
+
159
+ > **Note:** The zone polygon supports arbitrary shapes (not just rectangles).
160
+ > Use `draw-zones=true` (the default) so that `gvawatermark` renders the zone
161
+ > boundary on the output video.
162
 
163
  ### DLStreamer Sample
164
 
 
174
 
175
  ```python
176
  from collections import defaultdict
177
+ import json
178
+ import sys
179
  import gi
180
  gi.require_version("Gst", "1.0")
181
+ gi.require_version("GstAnalytics", "1.0")
182
+ gi.require_version("DLStreamerMeta", "1.0")
183
+ gi.require_version("DLStreamerWatermarkMeta", "1.0")
184
+ from gi.repository import Gst, GLib, GstAnalytics, DLStreamerMeta, DLStreamerWatermarkMeta
185
 
186
+ Gst.init([])
187
 
188
+ # Register DLStreamerMeta types so GstAnalytics iteration can handle them
189
+ _ov = sys.modules["gi.overrides.GstAnalytics"]
190
+ _ov.__mtd_types__[DLStreamerMeta.ZoneMtd.get_mtd_type()] = DLStreamerMeta.relation_meta_get_zone_mtd
191
+ _ov.__mtd_types__[DLStreamerMeta.TripwireMtd.get_mtd_type()] = DLStreamerMeta.relation_meta_get_tripwire_mtd
192
 
193
  MODEL = "yolo26n_openvino_model/yolo26n.xml"
194
  VIDEO = "VIRAT_S_000101.mp4"
195
+ ZONE_JSON = json.dumps([{
196
+ "id": "loiter_zone",
197
+ "type": "polygon",
198
+ "points": [{"x": 0, "y": 200}, {"x": 300, "y": 200},
199
+ {"x": 300, "y": 400}, {"x": 0, "y": 400}]
200
+ }])
201
  LOITERING_SECONDS = 5.0
202
 
203
  pipeline = Gst.parse_launch(
204
  f"filesrc location={VIDEO} ! decodebin3 ! videoconvert ! "
205
+ f"gvadetect model={MODEL} device=GPU threshold=0.5 ! queue ! "
 
206
  f"gvatrack tracking-type=short-term-imageless ! queue ! "
207
+ f"gvaanalytics name=analytics draw-zones=true ! "
208
+ f"gvafpscounter ! identity name=probe ! gvawatermark name=watermark ! "
209
+ f"videoconvert ! video/x-raw,format=I420 ! "
210
  f"openh264enc ! h264parse ! mp4mux ! filesink location=output_dlstreamer.mp4"
211
  )
212
 
213
+ pipeline.get_by_name("analytics").set_property("zones", ZONE_JSON)
214
+ pipeline.get_by_name("watermark").set_property("displ-cfg", "hide-roi=person")
215
+
216
  dwell = defaultdict(float)
217
  last_seen = {}
218
  flagged = set()
219
 
220
  def on_buffer(pad, info):
221
  buf = info.get_buffer()
 
222
  now = buf.pts / Gst.SECOND if buf.pts != Gst.CLOCK_TIME_NONE else 0.0
223
+ rmeta = GstAnalytics.buffer_get_analytics_relation_meta(buf)
224
+ if not rmeta:
225
+ return Gst.PadProbeReturn.OK
226
+
227
+ # Iterate only over object-detection entries
228
+ for od in rmeta.iter_on_type(GstAnalytics.ODMtd):
229
+ label = GLib.quark_to_string(od.get_obj_type())
230
+ if label != "person":
231
  continue
232
+
233
+ # Find tracking ID via direct relation
234
+ track_id = None
235
+ for trk in od.iter_direct_related(GstAnalytics.RelTypes.RELATE_TO, GstAnalytics.TrackingMtd):
236
+ success, tracking_id, *_ = trk.get_info()
237
+ if success:
238
+ track_id = tracking_id
239
+ break
240
+ if track_id is None:
241
  continue
242
 
243
+ # Check if gvaanalytics placed this detection inside the zone
244
+ in_zone = False
245
+ for zone in od.iter_direct_related(GstAnalytics.RelTypes.RELATE_TO, DLStreamerMeta.ZoneMtd):
246
+ in_zone = True
247
+ break
248
 
249
+ if not in_zone:
250
+ continue
251
+
252
+ # Accumulate dwell time for persons inside the zone
253
+ dwell[track_id] += now - last_seen.get(track_id, now)
254
+ last_seen[track_id] = now
255
 
256
+ if dwell[track_id] >= LOITERING_SECONDS and track_id not in flagged:
257
+ flagged.add(track_id)
258
+ _, x, y, w, h, _ = od.get_location()
259
+ print(f"LOITERING id={track_id} dwell={dwell[track_id]:.1f}s pos=({int(x + w/2)},{int(y + h)})")
260
 
261
  return Gst.PadProbeReturn.OK
262
 
 
274
  ...
275
  ```
276
 
277
+ The annotated video is saved to `output_dlstreamer.mp4`.
278
+ The `gvaanalytics` element also draws the zone polygon on each frame via `gvawatermark`.
279
 
280
  #### Expected Output
281
 
 
299
  - [YOLO26 Documentation](https://docs.ultralytics.com/models/yolo26/)
300
  - [OpenVINO YOLO26 Notebook](https://github.com/openvinotoolkit/openvino_notebooks/blob/latest/notebooks/yolov26-optimization/yolov26-object-detection.ipynb)
301
  - [Intel DLStreamer Object Tracking](https://docs.openedgeplatform.intel.com/2026.0/edge-ai-libraries/dlstreamer/elements/gvatrack.html)
302
+ - [Intel DLStreamer gvaanalytics](https://github.com/dlstreamer/dlstreamer/blob/main/src/monolithic/gst/elements/gvaanalytics/README.md)
303
  - [OpenVINO Documentation](https://docs.openvino.ai/)
304
  - [NNCF Post-Training Quantization](https://docs.openvino.ai/latest/nncf_ptq_introduction.html)
305
  - [COCO Dataset](https://cocodataset.org/)
306
+ Company logo
307
+ Browse warning
308
+ When posting information to this site please be careful not to post personal or Intel Confidential/ Intel Top Secret information.
309
+
310
+
311
+
312
+ For More Information about Generative AI Guidelines at Intel please visit https://goto/generativeaiguidelines
expected_output_dlstreamer.gif CHANGED

Git LFS Details

  • SHA256: c6573ac55eac081f030322da4b70745da96eb49d61c07d57477cfc658ce13e1c
  • Pointer size: 132 Bytes
  • Size of remote file: 1.51 MB

Git LFS Details

  • SHA256: f67822dbe072e8ebc62dac9fa7bccd950ac83e2002e60ed25424aa569b6e2a63
  • Pointer size: 131 Bytes
  • Size of remote file: 896 kB