vagheshpatel commited on
Commit
7c6dbfb
·
verified ·
1 Parent(s): 77b927f

Sync object-counting from metro-analytics-catalog

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ expected_output_dlstreamer.gif filter=lfs diff=lfs merge=lfs -text
37
+ expected_output_openvino.jpg filter=lfs diff=lfs merge=lfs -text
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 ADDED
@@ -0,0 +1,334 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ license_link: LICENSE
4
+ library_name: openvino
5
+ pipeline_tag: object-detection
6
+ tags:
7
+ - openvino
8
+ - intel
9
+ - yolo
10
+ - yolo26
11
+ - object-counting
12
+ - coco
13
+ - edge-ai
14
+ - metro
15
+ - dlstreamer
16
+ language:
17
+ - en
18
+ ---
19
+
20
+ # Object Counting
21
+
22
+ | Property | Value |
23
+ |---|---|
24
+ | **Category** | Object Detection + Counting (80-class COCO) |
25
+ | **Base Model** | [YOLO26](https://docs.ultralytics.com/models/yolo26/) (Ultralytics) |
26
+ | **Source Framework** | PyTorch (Ultralytics) |
27
+ | **Supported Precisions** | FP32, FP16, INT8 (mixed-precision) |
28
+ | **Inference Engine** | OpenVINO |
29
+ | **Hardware** | CPU, GPU, NPU |
30
+ | **Detected Class(es)** | All 80 COCO classes (counted per class) |
31
+
32
+ ---
33
+
34
+ ## Overview
35
+
36
+ Object Counting is a Metro Analytics use case that detects objects and reports
37
+ how many of each class are present in an image or per video frame.
38
+ It is built on [YOLO26](https://docs.ultralytics.com/models/yolo26/), a
39
+ state-of-the-art real-time object detector, quantized to INT8 for efficient
40
+ inference on Intel hardware.
41
+ Counting is implemented as a thin aggregation layer on top of the strongest
42
+ general-purpose detector, which keeps it accurate and reusable across classes.
43
+ The DLStreamer sample below demonstrates this on a traffic scene sample video,
44
+ counting **person**, **bicycle**, and **car** detections per frame.
45
+
46
+ Typical Metro deployments include:
47
+
48
+ - **Occupancy Counting** -- count people on a platform or in a waiting area.
49
+ - **Vehicle Counting** -- count cars, buses, and trucks at an intersection.
50
+ - **Inventory Counting** -- count bags, bottles, or other items in a zone.
51
+ - **Throughput Metrics** -- aggregate per-frame counts into time series.
52
+
53
+ Available variants: `yolo26n`, `yolo26s`, `yolo26m`, `yolo26l`, `yolo26x`.
54
+ Smaller variants (`yolo26n`, `yolo26s`) are recommended for high-FPS edge deployment; larger variants improve recall for small or distant objects.
55
+
56
+ For line-crossing counts (directional entry/exit), see the
57
+ [vehicle-entry-exit-logging](../vehicle-entry-exit-logging/) use case.
58
+
59
+ ---
60
+
61
+ ## Prerequisites
62
+
63
+ - Python 3.11+
64
+ - [Install OpenVINO](https://docs.openvino.ai/2026/get-started/install-openvino.html) (latest version)
65
+ - [Install Intel DLStreamer](https://docs.openedgeplatform.intel.com/2026.0/edge-ai-libraries/dlstreamer/get_started/install/install_guide_ubuntu.html) (latest version)
66
+
67
+ Create and activate a Python virtual environment before running the scripts:
68
+
69
+ ```bash
70
+ python3 -m venv .venv --system-site-packages
71
+ source .venv/bin/activate
72
+ ```
73
+
74
+ > **Note:** The `--system-site-packages` flag is required so the virtual
75
+ > environment can access the system-installed OpenVINO and DLStreamer Python
76
+ > packages.
77
+
78
+ ---
79
+
80
+ ## Getting Started
81
+
82
+ ### Download and Quantize Model
83
+
84
+ Run the provided script to download, export to OpenVINO IR, and optionally quantize:
85
+
86
+ ```bash
87
+ chmod +x export_and_quantize.sh
88
+ ./export_and_quantize.sh
89
+ ```
90
+
91
+ This exports the default **yolo26n** model in **FP16** precision.
92
+
93
+ #### Optional: Select a Different Variant or Precision
94
+
95
+ ```bash
96
+ ./export_and_quantize.sh yolo26n FP32 # full-precision
97
+ ./export_and_quantize.sh yolo26n INT8 # quantized
98
+ ./export_and_quantize.sh yolo26s # larger variant, default FP16
99
+ ```
100
+
101
+ Replace `yolo26n` with any variant (`yolo26s`, `yolo26m`, `yolo26l`, `yolo26x`).
102
+ The second argument selects the precision (`FP32`, `FP16`, `INT8`); the default is **FP16**.
103
+
104
+ The script performs the following steps:
105
+
106
+ 1. Installs dependencies (`openvino`, `ultralytics`; adds `nncf` for INT8).
107
+ 2. Downloads a sample test image (`test.jpg`) and a sample test video
108
+ (`test_video.mp4`, the
109
+ [`person-bicycle-car-detection.mp4`](https://github.com/intel-iot-devkit/sample-videos/blob/master/person-bicycle-car-detection.mp4)
110
+ street scene from Intel IoT DevKit's sample-videos repository).
111
+ 3. Downloads the PyTorch weights and exports to OpenVINO IR.
112
+ 4. *(INT8 only)* Quantizes the model using NNCF post-training quantization.
113
+
114
+ Output files:
115
+
116
+ - `yolo26n_openvino_model/` -- FP32 or FP16 OpenVINO IR model directory.
117
+ - `yolo26n_objcount_int8.xml` / `yolo26n_objcount_int8.bin` -- INT8 quantized model *(only when `INT8` is selected)*.
118
+
119
+ #### Precision / Device Compatibility
120
+
121
+ | Precision | CPU | GPU | NPU |
122
+ |---|---|---|---|
123
+ | FP32 | Yes | Yes | No |
124
+ | FP16 | Yes | Yes | Yes |
125
+ | INT8 | Yes | Yes | Yes |
126
+
127
+ > **Note:** The INT8 calibration uses the bundled sample image.
128
+ > For production accuracy, replace it with a representative set of frames from
129
+ > the target deployment site.
130
+
131
+ ### OpenVINO Sample
132
+
133
+ The sample below runs YOLO26 inference, then aggregates detections into a
134
+ per-class count and a total count for a single image.
135
+ YOLO26 is end-to-end (NMS-free), so no manual non-maximum suppression is needed.
136
+ Change the `device` string to run on CPU, GPU, or NPU.
137
+
138
+ ```python
139
+ from collections import Counter
140
+
141
+ import cv2
142
+ import numpy as np
143
+ import openvino as ov
144
+
145
+ CONF_THRESHOLD = 0.4
146
+ INPUT_SIZE = 640
147
+
148
+ core = ov.Core()
149
+ model = core.read_model("yolo26n_openvino_model/yolo26n.xml")
150
+
151
+ # YOLO26 embeds the 80 COCO class names in rt_info -- read them instead of
152
+ # hardcoding the list. Ultralytics separates multi-word names with
153
+ # underscores (e.g. "traffic_light"), so restore spaces for display.
154
+ COCO_NAMES = [
155
+ name.replace("_", " ")
156
+ for name in model.get_rt_info()["model_info"]["labels"].value.split()
157
+ ]
158
+
159
+ # Change device to "GPU" or "NPU" to run on integrated GPU or NPU.
160
+ compiled = core.compile_model(model, "CPU")
161
+
162
+ image = cv2.imread("test.jpg")
163
+ h0, w0 = image.shape[:2]
164
+
165
+ blob = cv2.resize(image, (INPUT_SIZE, INPUT_SIZE))
166
+ blob = cv2.cvtColor(blob, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0
167
+ blob = blob.transpose(2, 0, 1)[np.newaxis, ...] # NCHW
168
+
169
+ # YOLO26 end-to-end output: [1, 300, 6] = [x1, y1, x2, y2, confidence, class_id]
170
+ output = compiled([blob])[compiled.output(0)][0]
171
+ dets = output[output[:, 4] >= CONF_THRESHOLD]
172
+
173
+ sx, sy = w0 / INPUT_SIZE, h0 / INPUT_SIZE
174
+ counts = Counter(COCO_NAMES[int(d[5])] for d in dets)
175
+
176
+ print(f"Total objects: {len(dets)}")
177
+ print("Object counts:")
178
+ for name, n in sorted(counts.items(), key=lambda kv: (-kv[1], kv[0])):
179
+ print(f" {name}: {n}")
180
+
181
+ colors = np.random.RandomState(42).randint(0, 255, (80, 3)).tolist()
182
+ for det in dets:
183
+ x1, y1, x2, y2 = (int(det[0] * sx), int(det[1] * sy),
184
+ int(det[2] * sx), int(det[3] * sy))
185
+ cid = int(det[5])
186
+ cv2.rectangle(image, (x1, y1), (x2, y2), colors[cid], 2)
187
+ cv2.putText(image, COCO_NAMES[cid], (x1, y1 - 5),
188
+ cv2.FONT_HERSHEY_SIMPLEX, 0.6, colors[cid], 2)
189
+
190
+ summary = ", ".join(f"{n} {name}" for name, n in counts.items())
191
+ cv2.putText(image, summary[:60], (10, 30),
192
+ cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
193
+ cv2.imwrite("output_openvino.jpg", image)
194
+ ```
195
+
196
+ **Device targets:**
197
+
198
+ - `"CPU"` -- default, works on all Intel platforms.
199
+ - `"GPU"` -- Intel integrated or discrete GPU.
200
+ - `"NPU"` -- Intel NPU (validate with `benchmark_app -d NPU`).
201
+
202
+ ### Try It on a Sample Image
203
+
204
+ The `export_and_quantize.sh` script downloads `test.jpg` automatically.
205
+ Re-run the OpenVINO sample above.
206
+ The script reads `test.jpg`, prints the per-class counts to the console, and writes the annotated frame to `output_openvino.jpg`.
207
+
208
+ Expected console output (representative):
209
+
210
+ ```text
211
+ Total objects: 5
212
+ Object counts:
213
+ person: 4
214
+ bus: 1
215
+ ```
216
+
217
+ #### Expected Output
218
+
219
+ ![OpenVINO expected output](expected_output_openvino.jpg)
220
+
221
+ ### DLStreamer Sample
222
+
223
+ The pipeline below runs the FP16 YOLO26 detector on the sample video via
224
+ `gvadetect`, overlays bounding boxes with `gvawatermark`, saves the annotated
225
+ result to `output_dlstreamer.mp4`, and prints the per-frame **person**,
226
+ **bicycle**, and **car** counts by reading the `GstAnalytics` detection
227
+ metadata. The sample video
228
+ ([`person-bicycle-car-detection.mp4`](https://github.com/intel-iot-devkit/sample-videos/blob/master/person-bicycle-car-detection.mp4))
229
+ is a street scene containing pedestrians, a cyclist, and cars, matching the
230
+ three classes counted below.
231
+
232
+ > **Notes on running this sample:**
233
+ >
234
+ > - Use the FP16 IR (`yolo26n_openvino_model/yolo26n.xml`). Class names are
235
+ > read automatically from the model's embedded `metadata.yaml` by
236
+ > DLStreamer 2026.0+ -- no external `labels-file` is required.
237
+ > - Export `PYTHONPATH` so the DLStreamer Python module is importable:
238
+ >
239
+ > ```bash
240
+ > source /opt/intel/openvino_2026/setupvars.sh
241
+ > source /opt/intel/dlstreamer/scripts/setup_dls_env.sh
242
+ > export PYTHONPATH=/opt/intel/dlstreamer/python:\
243
+ > /opt/intel/dlstreamer/gstreamer/lib/python3/dist-packages:${PYTHONPATH:-}
244
+ > ```
245
+
246
+ ```python
247
+ from collections import Counter
248
+
249
+ import gi
250
+
251
+ gi.require_version("Gst", "1.0")
252
+ gi.require_version("GstAnalytics", "1.0")
253
+ from gi.repository import Gst, GLib, GstAnalytics
254
+
255
+ Gst.init([])
256
+
257
+ INPUT_VIDEO = "test_video.mp4"
258
+
259
+ # Only these classes are counted; the sample video contains pedestrians,
260
+ # a cyclist, and cars.
261
+ CLASSES_OF_INTEREST = {"person", "bicycle", "car"}
262
+
263
+ # For CPU: change device=GPU to device=CPU.
264
+ # For NPU: change device=GPU to device=NPU (batch-size=1, nireq=4 recommended).
265
+ pipeline_str = (
266
+ f"filesrc location={INPUT_VIDEO} ! decodebin3 ! "
267
+ "videoconvert ! "
268
+ "gvadetect model=yolo26n_openvino_model/yolo26n.xml "
269
+ "device=GPU "
270
+ "threshold=0.4 ! queue ! "
271
+ "gvawatermark ! videoconvert ! video/x-raw,format=I420 ! "
272
+ "openh264enc ! h264parse ! "
273
+ "mp4mux ! filesink name=sink location=output_dlstreamer.mp4"
274
+ )
275
+ pipeline = Gst.parse_launch(pipeline_str)
276
+
277
+
278
+ def on_buffer(pad, info):
279
+ buf = info.get_buffer()
280
+ rmeta = GstAnalytics.buffer_get_analytics_relation_meta(buf)
281
+ if rmeta is None:
282
+ return Gst.PadProbeReturn.OK
283
+ counts = Counter()
284
+ idx = 1
285
+ while True:
286
+ ok, od = rmeta.get_od_mtd(idx)
287
+ if not ok:
288
+ break
289
+ label = GLib.quark_to_string(od.get_obj_type())
290
+ if label in CLASSES_OF_INTEREST:
291
+ counts[label] += 1
292
+ idx += 1
293
+ if counts:
294
+ summary = ", ".join(f"{n} {name}" for name, n in counts.items())
295
+ print(f"Object counts: {summary}", flush=True)
296
+ return Gst.PadProbeReturn.OK
297
+
298
+
299
+ sink = pipeline.get_by_name("sink")
300
+ sink.get_static_pad("sink").add_probe(Gst.PadProbeType.BUFFER, on_buffer)
301
+
302
+ pipeline.set_state(Gst.State.PLAYING)
303
+ bus = pipeline.get_bus()
304
+ bus.timed_pop_filtered(
305
+ Gst.CLOCK_TIME_NONE,
306
+ Gst.MessageType.EOS | Gst.MessageType.ERROR,
307
+ )
308
+ pipeline.set_state(Gst.State.NULL)
309
+ ```
310
+
311
+ **Device targets:**
312
+
313
+ - `device=GPU` -- default in the sample code.
314
+ - `device=CPU` -- change `device=GPU` to `device=CPU`.
315
+ - `device=NPU` -- change `device=GPU` to `device=NPU`; use `batch-size=1` and `nireq=4` for best NPU utilization.
316
+
317
+ #### Expected Output
318
+
319
+ ![DLStreamer expected output](expected_output_dlstreamer.gif)
320
+
321
+ ---
322
+
323
+ ## License
324
+
325
+ Licensed under the MIT License. See [LICENSE](LICENSE) for details.
326
+
327
+ ## References
328
+
329
+ - [YOLO26 Documentation](https://docs.ultralytics.com/models/yolo26/)
330
+ - [Ultralytics Object Counting Guide](https://docs.ultralytics.com/guides/object-counting/)
331
+ - [Intel DLStreamer gvadetect](https://docs.openedgeplatform.intel.com/2026.0/edge-ai-libraries/dlstreamer/elements/gvadetect.html)
332
+ - [OpenVINO Documentation](https://docs.openvino.ai/)
333
+ - [NNCF Post-Training Quantization](https://docs.openvino.ai/latest/nncf_ptq_introduction.html)
334
+ - [Intel DLStreamer](https://docs.openedgeplatform.intel.com/2026.0/edge-ai-libraries/dlstreamer/index.html)
expected_output_dlstreamer.gif ADDED

Git LFS Details

  • SHA256: 6795b0e1bc2a09b062b8e62e71ce7e156e702e5d74f6a9614274b82d49abe724
  • Pointer size: 132 Bytes
  • Size of remote file: 3.47 MB
expected_output_openvino.jpg ADDED

Git LFS Details

  • SHA256: ec33ccba8e7fe8b950f8e9f377b7db3b57ec24649cb97c2994a0cf70e506e1d7
  • Pointer size: 131 Bytes
  • Size of remote file: 348 kB
export_and_quantize.sh ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+ # SPDX-License-Identifier: MIT
3
+ # Copyright (C) Intel Corporation
4
+ #
5
+ # Export a YOLO26 detector to OpenVINO IR for the object-counting use case.
6
+ # Usage: ./export_and_quantize.sh [MODEL_VARIANT] [PRECISION]
7
+ # Example: ./export_and_quantize.sh yolo26n FP16
8
+ #
9
+ # Supported precisions:
10
+ # FP32 -- Full-precision floating-point weights
11
+ # FP16 -- Half-precision floating-point weights (default)
12
+ # INT8 -- Quantized 8-bit integer weights (requires NNCF)
13
+ #
14
+ # Precision / device compatibility:
15
+ # | Precision | CPU | GPU | NPU |
16
+ # |-----------|-----|-----|-----|
17
+ # | FP32 | Yes | Yes | No |
18
+ # | FP16 | Yes | Yes | Yes |
19
+ # | INT8 | Yes | Yes | Yes |
20
+
21
+ set -euo pipefail
22
+
23
+ MODEL_NAME="${1:-yolo26n}"
24
+ PRECISION="${2:-FP16}"
25
+ PRECISION="$(echo "${PRECISION}" | tr '[:lower:]' '[:upper:]')"
26
+
27
+ if [[ "${PRECISION}" != "FP32" && "${PRECISION}" != "FP16" && "${PRECISION}" != "INT8" ]]; then
28
+ echo "ERROR: unsupported precision '${PRECISION}'. Choose FP32, FP16, or INT8." >&2
29
+ exit 1
30
+ fi
31
+
32
+ echo "--- Installing dependencies ---"
33
+ if [[ "${PRECISION}" == "INT8" ]]; then
34
+ pip install -qU openvino nncf ultralytics
35
+ else
36
+ pip install -qU openvino ultralytics
37
+ fi
38
+
39
+ # Ask for approval before downloading models and sample files
40
+ echo ""
41
+ echo "This script will download:"
42
+ echo " - Model weights and/or sample files"
43
+ echo ""
44
+ read -p "Continue with downloads? (yes/no): " APPROVAL
45
+ if [[ "${APPROVAL}" != "yes" ]]; then
46
+ echo "Download cancelled by user."
47
+ exit 0
48
+ fi
49
+ echo ""
50
+ echo "--- Downloading sample test image ---"
51
+ if [[ ! -f test.jpg ]]; then
52
+ wget -q -O test.jpg https://ultralytics.com/images/bus.jpg
53
+ echo "Downloaded: test.jpg"
54
+ else
55
+ echo "Already present: test.jpg"
56
+ fi
57
+ echo ""
58
+ echo "--- Downloading sample test video ---"
59
+ if [[ ! -f test_video.mp4 ]]; then
60
+ wget -q -O test_video.mp4 \
61
+ "https://raw.githubusercontent.com/intel-iot-devkit/sample-videos/master/person-bicycle-car-detection.mp4"
62
+ echo "Downloaded: test_video.mp4"
63
+ else
64
+ echo "Already present: test_video.mp4"
65
+ fi
66
+
67
+ if [[ "${PRECISION}" == "FP32" ]]; then
68
+ HALF_FLAG="False"
69
+ EXPORT_LABEL="FP32"
70
+ else
71
+ HALF_FLAG="True"
72
+ EXPORT_LABEL="FP16"
73
+ fi
74
+
75
+ echo "--- Exporting ${MODEL_NAME} to OpenVINO IR (${EXPORT_LABEL}) ---"
76
+ python3 -c "
77
+ from ultralytics import YOLO
78
+
79
+ model = YOLO('${MODEL_NAME}.pt')
80
+ model.export(format='openvino', half=${HALF_FLAG}, dynamic=False, imgsz=640)
81
+ print('Export complete: ${MODEL_NAME}_openvino_model/')
82
+ "
83
+
84
+ if [[ "${PRECISION}" == "INT8" ]]; then
85
+ echo "--- Quantizing to INT8 with NNCF ---"
86
+ python3 -c "
87
+ import nncf
88
+ import openvino as ov
89
+ import numpy as np
90
+ import cv2
91
+
92
+ core = ov.Core()
93
+ model = core.read_model('${MODEL_NAME}_openvino_model/${MODEL_NAME}.xml')
94
+
95
+ # Use the downloaded test image for calibration instead of random noise.
96
+ img = cv2.imread('test.jpg')
97
+ img = cv2.resize(img, (640, 640))
98
+ img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0
99
+ img = img.transpose(2, 0, 1)[np.newaxis, ...] # NCHW
100
+
101
+ def transform_fn(data_item):
102
+ return img
103
+
104
+ calibration_dataset = nncf.Dataset(list(range(300)), transform_fn)
105
+
106
+ quantized = nncf.quantize(
107
+ model,
108
+ calibration_dataset,
109
+ preset=nncf.QuantizationPreset.MIXED,
110
+ subset_size=300,
111
+ )
112
+
113
+ ov.save_model(quantized, '${MODEL_NAME}_objcount_int8.xml')
114
+ print('Quantization complete: ${MODEL_NAME}_objcount_int8.xml')
115
+ "
116
+ fi
117
+ echo "--- Done ---"