Nodeflux Central
License Plate Recognition (LPR)

API Reference — License Plate Recognition

Endpoint REST API untuk membuat pipeline License Plate Recognition pada stream Visionaire4, event streaming hasil OCR via WebSocket, dan struktur event JSON.

Endpoint pipeline (/pipeline/...) memanggil Visionaire4 API — basis URL dikonfigurasi melalui variabel VISIONAIRE_API_URL (default: http://localhost:4004). Autentikasi mengikuti konfigurasi deployment Visionaire4 Anda.


Manajemen Pipeline

Endpoint untuk membuat, memperbarui, membaca, dan menghapus pipeline LPR. Setiap pipeline diidentifikasi oleh kombinasi node_num + stream_id + analytic_id; segmen terakhir path menentukan varian (NFV4-LPR2, NFV4-LPRS, NFV4-LPR3, NFV4-LPR3S).

POST
/pipeline/{node_num}/{stream_id}/NFV4-LPR2

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X POST "http://localhost:4004/pipeline/0/stream_001/NFV4-LPR2" \  -H "Content-Type: application/json" \  -d '{    "plate_confidence_threshold": 0.6,    "vehicle_confidence_threshold": 0.6,    "similarity_score_threshold": 0.7,    "min_group_member": 2,    "plate_cache_lifetime": 10,    "areas": [      {        "name": "Gate A",        "roi_type": "whitelist",        "points": [          {            "x": 0.1,            "y": 0.3          },          {            "x": 0.9,            "y": 0.3          },          {            "x": 0.9,            "y": 0.9          },          {            "x": 0.1,            "y": 0.9          }        ]      }    ]  }'
{  "code": 200,  "message": "pipeline successfully created",  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR2"}
{  "code": 400,  "message": "Pipeline already exists"}
{  "code": 404,  "message": "Stream not found"}
PUT
/pipeline/{node_num}/{stream_id}/NFV4-LPR2

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X PUT "http://localhost:4004/pipeline/0/stream_001/NFV4-LPR2" \  -H "Content-Type: application/json" \  -d '{    "plate_confidence_threshold": 0.7,    "similarity_score_threshold": 0.8  }'
{  "code": 200,  "message": "pipeline successfully updated",  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR2"}
{  "code": 400,  "message": "Pipeline already exists"}
{  "code": 404,  "message": "Stream not found"}
GET
/pipeline/{node_num}/{stream_id}/NFV4-LPR2

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Response Body

application/json

application/json

curl -X GET "http://localhost:4004/pipeline/0/stream_001/NFV4-LPR2"
{  "code": 200,  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR2",  "config": {},  "message": "configuration has been successfully retrieved from the runtime pipeline"}
{  "code": 400,  "message": "analytic_id: NFV4-LPR2 is not exists given stream_id: stream_001"}
DELETE
/pipeline/{node_num}/{stream_id}/NFV4-LPR2

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Response Body

application/json

application/json

curl -X DELETE "http://localhost:4004/pipeline/0/stream_001/NFV4-LPR2"
{  "code": 200,  "message": "pipeline successfully deleted",  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR2"}
{  "code": 404,  "message": "Stream not found"}
POST
/pipeline/{node_num}/{stream_id}/NFV4-LPRS

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X POST "http://localhost:4004/pipeline/0/stream_001/NFV4-LPRS" \  -H "Content-Type: application/json" \  -d '{    "plate_confidence_threshold": 0.6,    "vehicle_confidence_threshold": 0.6,    "areas": [      {        "name": "Checkpoint",        "roi_type": "whitelist",        "points": [          {            "x": 0,            "y": 0.2          },          {            "x": 1,            "y": 0.2          },          {            "x": 1,            "y": 1          },          {            "x": 0,            "y": 1          }        ]      }    ]  }'
{  "code": 200,  "message": "pipeline successfully created",  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPRS"}
{  "code": 400,  "message": "Pipeline already exists"}
{  "code": 400,  "message": "Pipeline already exists"}
PUT
/pipeline/{node_num}/{stream_id}/NFV4-LPRS

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X PUT "http://localhost:4004/pipeline/0/stream_001/NFV4-LPRS" \  -H "Content-Type: application/json" \  -d '{    "plate_confidence_threshold": 0.7  }'
{  "code": 200,  "message": "pipeline successfully updated",  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPRS"}
{  "code": 400,  "message": "Pipeline already exists"}
{  "code": 400,  "message": "Pipeline already exists"}
GET
/pipeline/{node_num}/{stream_id}/NFV4-LPRS

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Response Body

application/json

application/json

curl -X GET "http://localhost:4004/pipeline/0/stream_001/NFV4-LPRS"
{  "code": 200,  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR2",  "config": {},  "message": "configuration has been successfully retrieved from the runtime pipeline"}
{  "code": 400,  "message": "Pipeline already exists"}
DELETE
/pipeline/{node_num}/{stream_id}/NFV4-LPRS

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Response Body

application/json

application/json

curl -X DELETE "http://localhost:4004/pipeline/0/stream_001/NFV4-LPRS"
{  "code": 200,  "message": "pipeline successfully deleted",  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPRS"}
{  "code": 400,  "message": "Pipeline already exists"}
POST
/pipeline/{node_num}/{stream_id}/NFV4-LPR3

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X POST "http://localhost:4004/pipeline/0/stream_001/NFV4-LPR3" \  -H "Content-Type: application/json" \  -d '{    "plate_confidence_threshold": 0.7,    "vehicle_confidence_threshold": 0.6,    "plate_recognition_fps": 6,    "plate_cache_lifetime": 3,    "areas": [      {        "name": "Toll Gate 1",        "points": [          {            "x": 0,            "y": 0          },          {            "x": 0.25,            "y": 0          },          {            "x": 0.25,            "y": 1          },          {            "x": 0,            "y": 1          }        ]      }    ]  }'
{  "code": 200,  "message": "pipeline successfully created",  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR3"}
{  "code": 400,  "message": "Pipeline already exists"}
{  "code": 400,  "message": "Pipeline already exists"}
PUT
/pipeline/{node_num}/{stream_id}/NFV4-LPR3

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X PUT "http://localhost:4004/pipeline/0/stream_001/NFV4-LPR3" \  -H "Content-Type: application/json" \  -d '{    "plate_recognition_fps": 8  }'
{  "code": 200,  "message": "pipeline successfully updated",  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR3"}
{  "code": 400,  "message": "Pipeline already exists"}
{  "code": 400,  "message": "Pipeline already exists"}
GET
/pipeline/{node_num}/{stream_id}/NFV4-LPR3

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Response Body

application/json

application/json

curl -X GET "http://localhost:4004/pipeline/0/stream_001/NFV4-LPR3"
{  "code": 200,  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR2",  "config": {},  "message": "configuration has been successfully retrieved from the runtime pipeline"}
{  "code": 400,  "message": "Pipeline already exists"}
DELETE
/pipeline/{node_num}/{stream_id}/NFV4-LPR3

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Response Body

application/json

application/json

curl -X DELETE "http://localhost:4004/pipeline/0/stream_001/NFV4-LPR3"
{  "code": 200,  "message": "pipeline successfully deleted",  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR3"}
{  "code": 400,  "message": "Pipeline already exists"}
POST
/pipeline/{node_num}/{stream_id}/NFV4-LPR3S

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X POST "http://localhost:4004/pipeline/0/stream_001/NFV4-LPR3S" \  -H "Content-Type: application/json" \  -d '{    "plate_confidence_threshold": 0.7,    "vehicle_confidence_threshold": 0.6,    "plate_recognition_fps": 6,    "areas": [      {        "name": "Toll Gate 2",        "points": [          {            "x": 0.25,            "y": 0          },          {            "x": 0.5,            "y": 0          },          {            "x": 0.5,            "y": 1          },          {            "x": 0.25,            "y": 1          }        ]      }    ]  }'
{  "code": 200,  "message": "pipeline successfully created",  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR3S"}
{  "code": 400,  "message": "Pipeline already exists"}
{  "code": 400,  "message": "Pipeline already exists"}
PUT
/pipeline/{node_num}/{stream_id}/NFV4-LPR3S

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

curl -X PUT "http://localhost:4004/pipeline/0/stream_001/NFV4-LPR3S" \  -H "Content-Type: application/json" \  -d '{    "plate_recognition_fps": 8  }'
{  "code": 200,  "message": "pipeline successfully updated",  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR3S"}
{  "code": 400,  "message": "Pipeline already exists"}
{  "code": 400,  "message": "Pipeline already exists"}
GET
/pipeline/{node_num}/{stream_id}/NFV4-LPR3S

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Response Body

application/json

application/json

curl -X GET "http://localhost:4004/pipeline/0/stream_001/NFV4-LPR3S"
{  "code": 200,  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR2",  "config": {},  "message": "configuration has been successfully retrieved from the runtime pipeline"}
{  "code": 400,  "message": "Pipeline already exists"}
DELETE
/pipeline/{node_num}/{stream_id}/NFV4-LPR3S

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Path Parameters

node_num*integer

Nomor node Visionaire. Gunakan 0 untuk deployment single-node.

stream_id*string

ID unik stream video yang akan diproses pipeline ini.

Response Body

application/json

application/json

curl -X DELETE "http://localhost:4004/pipeline/0/stream_001/NFV4-LPR3S"
{  "code": 200,  "message": "pipeline successfully deleted",  "node_num": 0,  "stream_id": "stream_001",  "analytic_id": "NFV4-LPR3S"}
{  "code": 400,  "message": "Pipeline already exists"}

Respons POST untuk kombinasi node_num + stream_id + analytic_id yang sudah ada adalah HTTP 400 (bukan 409) dengan pesan error dari server. Endpoint GET mengembalikan bentuk config yang berbeda tergantung varian — untuk NFV4-LPR2/NFV4-LPRS, config berisi daftar parameter default lengkap beserta areas aktif; untuk NFV4-LPR3/NFV4-LPR3S, config hanya berisi body konfigurasi terakhir yang tersimpan di database (server tidak memasukkan kedua varian ini ke daftar verbose-config).


Event Streaming (WebSocket)

Visionaire4 mengirim setiap event hasil deteksi/OCR melalui WebSocket. Untuk berlangganan event dari pipeline LPR pada stream tertentu, buka koneksi ke:

ws://<host>:4004/event_channel/{node_num}/{stream_id}/{analytic_id}

Ganti {analytic_id} dengan varian yang dipakai (NFV4-LPR2, NFV4-LPRS, NFV4-LPR3, atau NFV4-LPR3S) — harus sama dengan analytic_id pipeline yang dibuat.

Setelah koneksi terbuka, server langsung mendorong (push) setiap event ke client tanpa handshake atau pesan subscribe. Tutup koneksi untuk berhenti menerima event.

Parameter Path

ParameterTipeDeskripsi
node_numintegerNomor node tempat stream berjalan (0 = master)
stream_idstringID stream yang akan dipantau

Query Parameter (Opsional)

ParameterTipeDeskripsi
logicstringFilter event berdasarkan nama logic rule yang aktif pada pipeline. Tanpa parameter ini, semua event dari analitik akan dikirim.

Contoh Koneksi

const ws = new WebSocket(
  'ws://localhost:4004/event_channel/0/<stream_id>/NFV4-LPR2'
);

ws.onmessage = (msg) => {
  const event = JSON.parse(msg.data);
  console.log(event.primary_text, event.pipeline_data);
};

ws.onerror = (err) => console.error('WebSocket error', err);
ws.onclose = () => console.log('Disconnected');
import asyncio
import json
import websockets

async def listen():
    url = "ws://localhost:4004/event_channel/0/<stream_id>/NFV4-LPR2"
    async with websockets.connect(url) as ws:
        async for msg in ws:
            event = json.loads(msg)
            print(event["primary_text"], event["pipeline_data"])

asyncio.run(listen())

Endpoint Channel Lainnya

Untuk mendengarkan event yang lebih luas (lintas analitik atau lintas stream), gunakan endpoint berikut yang dijelaskan pada Developer Guide:

EndpointCakupan
WS /event_channel/Semua event dari seluruh node
WS /event_channel/{node_num}/Semua event dari satu node
WS /event_channel/{node_num}/{stream_id}Semua event dari satu stream (semua analitik)

Live View (MJPEG)

GET /mjpeg/{node_num}/{stream_id}/{analytic_id} menghasilkan MJPEG stream dengan overlay pipeline (bounding box kendaraan/plat, garis ROI) — berguna untuk memverifikasi konfigurasi areas secara visual. Tanpa {analytic_id} (GET /mjpeg/{node_num}/{stream_id}), endpoint ini menampilkan stream mentah tanpa overlay analitik apa pun.

Query Parameter

ParameterTipeDefaultDeskripsi
fpsinteger0Frame per detik output MJPEG. 0 = tidak dibatasi.
heightinteger320Tinggi output dalam piksel.
jqinteger60Kualitas JPEG (0–100).
curl "http://localhost:4004/mjpeg/0/gate_entry_001/NFV4-LPR2?fps=10&height=480&jq=70"

GET /visual/{node_num}/{stream_id}/{analytic_id} bukan endpoint MJPEG — ia mengembalikan halaman HTML viewer, bukan gambar/stream langsung. Untuk mengambil MJPEG secara terprogram, gunakan /mjpeg/... di atas. Path /pipeline/{node_num}/{stream_id}/{analytic_id}/mjpeg, /pipeline/.../config, dan /pipeline/.../snapshot yang muncul di dokumentasi versi lama tidak ada — endpoint MJPEG selalu berada di bawah prefix /mjpeg/..., terpisah dari /pipeline/....


Struktur Event

Pipeline memancarkan satu event setiap kali kendaraan dengan plat selesai diproses dan lolos semua filter (atau, jika enable_dump_non_plate aktif, saat kendaraan tanpa plat terdeteksi keluar dari frame). Event dikirim melalui event channel WebSocket dan disimpan ke database node kecuali --db-disable-event-store aktif.

Semua modul analitik Visionaire memakai envelope yang sama; bagian yang spesifik LPR ada di pipeline_data.

{
  "timestamp": 1705314600,
  "node_num": 0,
  "stream_id": "gate_entry_001",
  "stream_name": "Gerbang Utama",
  "stream_address": "rtsp://10.7.2.50:554/stream",
  "stream_longitude": 106.823649,
  "stream_latitude": -6.261376,
  "analytic_id": "NFV4-LPR2",
  "primary_text": "car|Gate A",
  "secondary_text": "B1234ABC",
  "pipeline_data": {
    "event_id": "1705314600-1a2b3c4d",
    "confidence": 0.95,
    "label": "car",
    "area_name": "Gate A",
    "plate_number": "B1234ABC",
    "plate_type": "plate",
    "bounding_box": { "left": 812.0, "top": 611.0, "width": 96.0, "height": 34.0 },
    "direction": "down",
    "attributes": {
      "vehicle": { "label": "car", "confidence": 0.92 },
      "plate": { "label": "plate", "confidence": 0.88 },
      "character": { "label": "B1234ABC", "confidence": 0.95 }
    }
  },
  "image_jpeg": "<base64 JPEG>"
}

Field Envelope

FieldTipeDeskripsi
timestampintWaktu event dalam epoch detik (UTC).
node_numintNomor node tempat pipeline berjalan.
stream_idstringIdentifier stream sumber.
stream_namestringNama stream.
stream_addressstringURL sumber video stream.
stream_longitude, stream_latitudefloatPosisi kamera.
analytic_idstringVarian pipeline yang memancarkan event — NFV4-LPR2, NFV4-LPRS, NFV4-LPR3, atau NFV4-LPR3S.
primary_textstringLabel kendaraan (mis. car), ditambah suffix |<area_name> jika mode whitelist dan area bukan default.
secondary_textstringNomor plat hasil OCR (ditambah , <plate_type> jika bukan plate).
pipeline_dataobjectDetail deteksi — lihat tabel berikutnya.
image_jpegstring (base64)Crop JPEG kendaraan/plat hasil deteksi.

Envelope tidak memiliki field event_id di level atas maupun timestamp_ms — keduanya sering diasumsikan ada tapi tidak pernah dikirim. ID unik event ada di pipeline_data.event_id.

Field pipeline_data

FieldTipeDeskripsi
event_idstringID unik event berformat <timestamp>-<hash8>.
confidencefloatConfidence hasil OCR karakter plat (0.0–1.0).
labelstringJenis kendaraan — car, bus, truck, motorcycle (dan bicycle pada NFV4-LPR3/NFV4-LPR3S).
area_namestringNama area ROI tempat kendaraan terdeteksi, atau default pada mode blacklist / saat areas tidak dikonfigurasi.
plate_numberstringHasil OCR nomor plat. Kosong jika event berasal dari enable_dump_non_plate tanpa plat terdeteksi.
plate_typestringNFV4-LPR2/NFV4-LPR3: selalu plate. NFV4-LPRS/NFV4-LPR3S: salah satu dari private, public, government, embassy, new_vehicle, police, tni_1-AU, tni_2-AD, tni_3-AL, kemenhan, mabes_tni.
bounding_boxobjectPosisi plat (bukan kendaraan) dalam koordinat pixel pada frame asli — {left, top, width, height}. Untuk event dari enable_dump_non_plate tanpa plat, field ini berisi bounding box kendaraan.
directionstringNFV4-LPR2/NFV4-LPRS: up, down, atau none, dihitung dari pergerakan vertikal plat antar sampel. NFV4-LPR3/NFV4-LPR3S: selalu unknown. Lihat Varian & Cara Kerja.
attributes.vehicleobject{label, confidence} hasil deteksi kendaraan.
attributes.plateobject{label, confidence} hasil deteksi plat — label sama dengan plate_type.
attributes.characterobject{label, confidence} hasil OCR karakter — label sama dengan plate_number.

bounding_box berisi koordinat pixel absolut relatif terhadap dimensi frame asli, bukan koordinat dinormalisasi [0,1] seperti areas.points pada request body. Jangan menyamakan sistem koordinat keduanya.

On this page