Views
No views yet
| Property | Value |
|---|---|
| Category | Object Detection + Optical Character Recognition (GstAnalytics) |
| Source Framework | PyTorch (Ultralytics YOLOv8), PaddlePaddle (PP-OCRv4) |
| Supported Precisions | FP32 |
| Inference Engine | OpenVINO |
| Hardware | CPU, GPU, NPU |
yolov8_license_plate_detector, a YOLOv8 model fine-tuned to localize license plates as oriented bounding boxes.ch_PP-OCRv4_rec_infer, the PaddleOCR PP-OCRv4 multilingual text recognizer that converts each cropped plate into a text string.Note: Plate detector accuracy depends on the regional distribution of training data. The bundled detector was trained primarily on European and US plates. For other regions, fine-tune the YOLOv8 detector on a representative dataset.
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.
sys.path by default, so export
PYTHONPATH as well:1source /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:-}1chmod +x export_and_quantize.sh
2./export_and_quantize.shParkingVideo.mp4) from the Intel Edge AI Resources project into the current directory.license-plate-reader archive from the Intel Edge AI Resources project and extracts it under ./models/yolov8_license_plate_detector/license-plate-reader/.
The archive bundles both the YOLOv8 plate detector (models/yolov8n/yolov8n_retrained.xml, FP32) and the converted PaddleOCR recognizer (models/ch_PP-OCRv4_rec_infer/ch_PP-OCRv4_rec_infer.xml, FP32), so no separate OCR download step is required../models/yolov8_license_plate_detector/license-plate-reader/models/ch_PP-OCRv4_rec_infer/ch_PP-OCRv4_rec_infer.xmlNote: PaddleOCR PP-OCRv4 is a CTC sequence model. DLStreamer 2026.0+ auto-derives the CTC decoder for the bundledch_PP-OCRv4_rec_inferIR and exposes the decoded plate string as aGstAnalytics.ClsMtdentry (withCONTAINrelation to the detection) -- no externalmodel-procis required for this sample. For other PaddleOCR variants or non-Latin character sets, supply a custommodel-proc(see DLStreamer model_proc reference) with the matching character dictionary.
license_plate_recognition.sh
sample: decodebin3 ! queue ! gvadetect ! queue ! videoconvert ! gvaclassify ! queue ! gvawatermark ! ....
The gvadetect element runs the license plate detector;
gvaclassify then runs the PaddleOCR recognizer on each detected plate region.
A buffer probe reads the GstAnalytics classification metadata
attached to each detection to extract the recognized plate text.
The input is ParkingVideo.mp4, the short parking-lot clip downloaded by
export_and_quantize.sh into the current directory.
The annotated stream is muxed into output_dlstreamer.mp4 with H.264 (OpenH264).1import os
2
3import gi
4
5gi.require_version("Gst", "1.0")
6gi.require_version("GstAnalytics", "1.0")
7gi.require_version("DLStreamerWatermarkMeta", "1.0")
8from gi.repository import Gst, GLib, GstAnalytics, DLStreamerWatermarkMeta
9
10Gst.init([])
11
12MODELS_DIR = os.path.abspath("./models/yolov8_license_plate_detector")
13DETECTOR_XML = (
14 f"{MODELS_DIR}/license-plate-reader/models/"
15 "yolov8n/yolov8n_retrained.xml"
16)
17OCR_XML = (
18 f"{MODELS_DIR}/license-plate-reader/models/"
19 "ch_PP-OCRv4_rec_infer/ch_PP-OCRv4_rec_infer.xml"
20)
21INPUT_VIDEO = "ParkingVideo.mp4"
22DEVICE = "GPU"
23
24pipeline_str = (
25 f"filesrc location={INPUT_VIDEO} ! decodebin3 ! "
26 f"videoconvert ! queue ! "
27 f"gvadetect model={DETECTOR_XML} device={DEVICE} ! queue ! "
28 f"videoconvert ! "
29 f"gvaclassify model={OCR_XML} device={DEVICE} ! queue ! "
30 f"identity name=probe ! "
31 f"gvawatermark displ-cfg=show-labels=false ! videoconvert ! video/x-raw,format=I420 ! "
32 f"openh264enc ! h264parse ! "
33 f"mp4mux ! filesink location=output_dlstreamer.mp4"
34)
35
36pipeline = Gst.parse_launch(pipeline_str)
37
38
39def on_buffer(pad, info):
40 buf = info.get_buffer()
41 new_buf = buf.copy_deep()
42 rmeta = GstAnalytics.buffer_get_analytics_relation_meta(new_buf)
43 if not rmeta:
44 info.set_buffer(new_buf)
45 return Gst.PadProbeReturn.OK
46 for od in rmeta.iter_on_type(GstAnalytics.ODMtd):
47 _, x, y, w, h, _ = od.get_location()
48 # OCR result is attached as ClsMtd with CONTAIN relation
49 text = ""
50 for cls in od.iter_direct_related(
51 GstAnalytics.RelTypes.CONTAIN, GstAnalytics.ClsMtd
52 ):
53 if cls.get_length() > 0:
54 q = cls.get_quark(0)
55 text = GLib.quark_to_string(q) if q else ""
56 break
57 if text:
58 DLStreamerWatermarkMeta.text_meta_add(
59 new_buf, x=int(x), y=max(0, int(y) - 10),
60 text=text, font_scale=0.6, font_type=0,
61 r=0, g=255, b=0, thickness=1, draw_bg=True)
62 print(f"Plate: {text} bbox=({x},{y})", flush=True)
63 info.set_buffer(new_buf)
64 return Gst.PadProbeReturn.OK
65
66
67probe = pipeline.get_by_name("probe")
68probe.get_static_pad("src").add_probe(
69 Gst.PadProbeType.BUFFER, on_buffer
70)
71
72pipeline.set_state(Gst.State.PLAYING)
73bus = pipeline.get_bus()
74bus.timed_pop_filtered(
75 Gst.CLOCK_TIME_NONE,
76 Gst.MessageType.EOS | Gst.MessageType.ERROR,
77)
78pipeline.set_state(Gst.State.NULL)DEVICE = "GPU" to DEVICE = "CPU".
For NPU, change DEVICE = "GPU" to DEVICE = "NPU" and use
batch-size=1 and nireq=4 for best utilization.export_and_quantize.sh already downloaded ParkingVideo.mp4 into the
current directory, so the sample is ready to run.
Execute the DLStreamer sample above.
The annotated video is saved to output_dlstreamer.mp4 with green bounding boxes drawn
by gvawatermark around every detected plate.
The buffer probe prints one line per detected plate per frame.1Plate: 9MRM624 bbox=(979,458)
2filesink with fakesink in pipeline_str and pipe the console output to a file.Known warning: Theopenh264encelement prints[OpenH264] this = 0x..., Error:CWelsH264SVCEncoder::EncodeFrame(), cmInitParaError.on the first frame. This is a benign initialization message — the output video is encoded correctly. The warning comes from the OpenH264 library's internal logging and does not indicate a real error.
