Inferenz auf einem Bild-Stream (experimentell)

Die Inferenz auf einem Bild-Stream ist experimentell (ab v2.2.0). Ihre Knoten können sich noch ändern. Verwenden Sie sie zur Evaluierung, und prüfen Sie sie mit Ihrem Netz und Ihrer Kamera, bevor Sie sich darauf verlassen.

Das allgemeine Konzept der Streams - Produzenten und Konsumenten, der Ergebnis-Envelope und seine Lineage - ist in Streams beschrieben. Diese Seite beschreibt den Stream von AI Object Matching. Er funktioniert auf dem ctrlX Data Layer und auf LumiScan Keryx gleich.

Auf Anfrage inferiert ein Modul ein Bild pro Request: Ihr Programm schreibt das Bild, oder der Cam Driver nimmt eines auf, und fordert dann die Inferenz an. Mit einem Bild-Stream veröffentlicht der Cam Driver jedes Bild, das er aufnimmt, auf control/publish/output/stream/frame, mit seiner Größe, seinem Pixelformat und seiner Lineage (siehe das Handbuch des Cam Driver, Bilder streamen). Ein Modul abonniert den Stream einer Kamera - seine Quelle -, inferiert die Bilder, sobald sie eintreffen, und veröffentlicht ein Ergebnis pro inferiertem Bild. Jedes Ergebnis trägt die Lineage seines Bildes - welche Kamera es aufgenommen hat, in welchem Lauf ihres Streams, als welches Bild des Laufs - ergänzt um den eigenen Schritt des Moduls, siehe Die Lineage eines Ergebnisses.

Standardmäßig fällt das Modul nie hinter die Kamera zurück. Treffen Bilder schneller ein, als das Netz inferiert, inferiert es jeweils das neueste Bild, sobald die vorherige Inferenz abgeschlossen ist. Die Bilder dazwischen zählen als übersprungen. Wie viele Bilder warten dürfen, legt die Warteschlangengröße fest, siehe Die Warteschlangengröße.

Ein Modul hat eine Quelle. Um die Bilder von zwei Kameras zu inferieren, verwenden Sie zwei Module.

Auf beiden Data Layern erreicht jedes Bild das Modul, in der richtigen Reihenfolge. Unterwegs verlorene Bilder werden in statistics/lost-frames gezählt: Jedes Bild trägt seine Nummer im Stream seiner Kamera.

Einrichtung

Jedes Modul hat die unten aufgeführten Stream-Knoten, ob es bereits eine Quelle hat oder nicht: Um sie zu verwenden, ist kein Neustart nötig. Entweder

  • setzen Sie in der Konfigurationsdatei des Moduls den Abschnitt stream, zum Beispiel

    "stream": {
        "enable": true,
        "address": "hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream"
    }

    Siehe Konfigurationsdatei eines Moduls. Eine geänderte Datei wirkt beim nächsten Start oder Reset; oder

  • Sie schreiben zur Laufzeit die Eingaben von control/subscribe und rufen es auf, siehe Abonnieren zur Laufzeit.

Der Bild-Stream wird mit dem Netz, den Klassenfiltern und der Neuzuordnung des Moduls inferiert. Für ein anderes Netz oder andere Einstellungen verwenden Sie ein anderes Modul.

In den Einstellungen gespeichert

Stream-Modus und Quelle sind Einstellungen des Moduls, im Abschnitt stream seiner Konfigurationsdatei. Ohne diesen Abschnitt, oder ohne enable darin, ist das Modul nicht im Stream-Modus. Der Stream-Modus benötigt eine Quelle: Eine Modulkonfigurationsdatei, in der enable auf true gesetzt ist und keine address steht, ist ungültig, und das Modul wird nicht geladen. Ebenso wenig ein Modul mit einem Schritt in stream.onEntry: Der Abschnitt enthält die Schritte des Streams jeder LumiScan-Anwendung, und AI Object Matching hat noch keine.

control/subscribe/execute und control/unsubscribe/execute speichern enable, address, tag, queueSize und keepLatestOutput, bevor sie sie anwenden. Nach einem Neustart abonniert das Modul dieselbe Quelle und startet, wenn stream.enable true ist, seinen Stream sofort - niemand muss die Methode erneut aufrufen. Das Speichern ändert nur diese Werte: Der Rest der Datei bleibt, wie er war, Kommentare eingeschlossen.

Adressen

Alle Adressen unten beginnen mit hdvisionsystems/lumiscan-ai-object-matching/<network name>/. Der Stream folgt dem Aufbau einer Execute-Methode: control/subscribe besitzt seine Eingaben und Ausgaben.

Tabelle 1. Methoden
Adresse Bedeutung

control/subscribe/execute

Prüft alle control/subscribe/input/…​ gemeinsam, speichert sie in der Konfigurationsdatei des Moduls und wendet sie dann an: Der Stream folgt in seinem nächsten Zyklus, ohne Neustart. Siehe Abonnieren zur Laufzeit.

control/unsubscribe/execute

Entfernt die Quelle, die control/unsubscribe/input/address nennt, was auch den Stream-Modus beendet, und speichert das. Das Tag bleibt.

Tabelle 2. Eingaben
Adresse Typ Beim Start Bedeutung

control/subscribe/input/enable

bool

stream.enable, oder false

true inferiert die Bilder der Quelle; false stoppt es.

control/subscribe/input/address

string

stream.address, oder leer

Der Stream-Ordner der Quelle, der das frame der Kamera enthält, zum Beispiel hdvisionsystems/lumiscan-cam-driver/camera1/control/publish/output/stream.

control/subscribe/input/tag

string

stream.tag, oder leer

Das Tag, das das Modul auf seine Ergebnisse setzt: Der Schritt des Moduls in der Lineage jedes Ergebnisses trägt es, sodass jeder, der ein Ergebnis weiter unten in der Kette liest, sieht, welches Modul es erzeugt hat. Leer: die Modul-ID, das letzte Segment der Adresse des Moduls - example für hdvisionsystems/lumiscan-ai-object-matching/example. Ein neues Tag markiert das nächste Ergebnis; die Quelle bleibt abonniert.

control/subscribe/input/queue-size

uint32

stream.queueSize, oder 1

Wie viele Bilder auf die Inferenz warten dürfen, 1 bis 64. Siehe Die Warteschlangengröße.

control/subscribe/input/keep-latest-output

bool

stream.keepLatestOutput, oder false

true schreibt jedes Stream-Ergebnis zusätzlich in die normale Ausgabe. Siehe Neuestes Ergebnis behalten.

control/unsubscribe/input/address

string

leer

Die Quelle, die control/unsubscribe/execute entfernt: die Adresse auf setting/stream/address.

Das Schreiben einer Eingabe ändert für sich allein nichts: Erst control/subscribe/execute wendet die Eingaben an. Sie beginnen mit dem, was das Modul anwendet, und ein Reset setzt sie wieder auf die Werte der Datei, sodass ein Client eine Eingabe ändern und die Methode aufrufen kann.

Was die Quelle enthalten muss: Lesen Sie hdvisionsystems/lumiscan-ai-object-matching/system/meta/subscription-schema (string, schreibgeschützt), für jedes Modul dasselbe. Es ist ein JSON Schema (draft-04) des frame-Knotens der Quelle, eines stream_image mit seiner lineage und seinem image, in seiner JSON-Form. Der Knoten ist experimentell.

Tabelle 3. Ausgaben
Adresse Typ Bedeutung

control/subscribe/output/stream/active

bool

true, solange das Modul seinen Bild-Stream inferiert.

control/subscribe/output/stream/result

flatbuffer stream_detections

Das Ergebnis jedes inferierten Bildes, im selben Format wie output/result, und seine Lineage. Abonnieren Sie ihn, um jedes Ergebnis zu erhalten. Siehe Das Ergebnis eines gestreamten Bildes.

control/subscribe/output/stream/statistics/…​

uint64

Zähler des laufenden oder letzten Streams, siehe Die Statistik lesen.

Tabelle 4. Einstellung
Adresse Typ Bedeutung

setting/stream/enable, setting/stream/address, setting/stream/tag, setting/stream/queue-size, setting/stream/keep-latest-output

wie die Eingaben

Was das Modul gerade anwendet, wie im Abschnitt stream gespeichert. Ein Client findet hier die Bilder der Quelle: LumiScan Cockpit verwendet setting/stream/address, um die Ergebnisse auf den Livebildern einzuzeichnen.

setting/settings-hash

string

Der Hash der Einstellungen, mit denen die Ergebnisse erzeugt werden, als 16 Hexadezimalziffern. Siehe Der Einstellungs-Hash.

Solange keep-latest-output nicht gesetzt ist, werden die Ergebnisse des Streams nur auf control/subscribe/output/stream/result veröffentlicht, und output/result, output/package-identifier, output/timestamp und output/image behalten das Ergebnis der letzten Inferenz auf Anfrage.

Das Ergebnis eines gestreamten Bildes

control/subscribe/output/stream/result enthält eine FlatBuffers-Tabelle vom Typ stream_detections, auf dem Data Layer registriert als types/hdvisionsystems/lumiscan-ai-object-matching/stream_detections. Ihr kompiliertes Schema wird als bfbs/stream_detections.bfbs installiert. Sie hat zwei Felder: result, dieselbe Tabelle wie output/result (object_detection), und lineage, siehe Die Lineage eines Ergebnisses.

Drei Felder von result beschreiben das Bild:

Feld Bedeutung

image_id

Die Nummer des Bildes seit dem Start des Streams: 1, 2, 3 und so weiter. Eine Lücke bedeutet, dass die Bilder dazwischen übersprungen wurden oder fehlgeschlagen sind. Eine 64-Bit-Zahl (ulong). In Versionen vor Oktober 2026 war es ein 16-Bit-short, das nach 32767 Bildern in negative Zahlen überlief.

timestamp

Wann das Bild eingetroffen ist, in Mikrosekunden seit der Epoche.

requested_timestamp

Wann die Inferenz auf dem Bild gestartet wurde, in Mikrosekunden seit der Epoche. Die Differenz zu timestamp ist die Zeit, die das Bild gewartet hat.

Die Klassenfilter in input/class-filters und die Neuzuordnung der Klassenindizes des Moduls gelten wie bei der Inferenz auf Anfrage. Eine Klasse, die die Netzbeschreibung nicht benennt, wird mit ihrem Index veröffentlicht.

Neuestes Ergebnis behalten

Mit gesetztem keep-latest-output wird jedes Stream-Ergebnis zusätzlich in die normale Ausgabe des Moduls geschrieben, so wie eine Inferenz auf Anfrage es schreibt: output/result, output/timestamp und output/package-identifier, weitergezählt ab den Inferenzen auf Anfrage. Ein Client, der die normale Ausgabe liest - zum Beispiel ein SPS-Programm, das für die Inferenz auf Anfrage geschrieben wurde -, sieht dort dann das neueste Stream-Ergebnis. Das Ausgabebild (output/image) wird nicht gezeichnet.

Es kostet eine Kopie jedes Ergebnisses und ist deshalb standardmäßig ausgeschaltet. Das Stream-Ergebnis auf control/subscribe/output/stream/result wird zuerst veröffentlicht.

Die Lineage eines Ergebnisses

lineage.steps listet auf, woher das Ergebnis stammt, der Ursprung zuerst:

  1. Der Schritt der Kamera, wie der Cam Driver ihn erzeugt hat: producer ist die Adresse der Kamera, hdvisionsystems/lumiscan-cam-driver/<camera name>, run, wann ihr Stream gestartet wurde, sequence die Nummer des Bildes in diesem Lauf, external_id die eigene Bildnummer der Kamera, settings_hash die Einstellungen der Kamera und tag das Tag des Cam Driver für die Kamera, standardmäßig ihre Modul-ID, zum Beispiel camera1.

  2. Der Schritt des Moduls: producer ist die Adresse des Moduls, hdvisionsystems/lumiscan-ai-object-matching/<network name>; run, wann der Stream des Moduls gestartet wurde (jeder Start ist ein neuer Lauf); sequence die Nummer des Ergebnisses im Lauf; settings_hash die Einstellungen des Moduls, siehe Der Einstellungs-Hash; elapsed_us die Mikrosekunden vom Eintreffen des Bildes bis zur Veröffentlichung des Ergebnisses; time_us, wann es veröffentlicht wurde; tag das Tag des Moduls, control/subscribe/input/tag, oder die Modul-ID, wenn es leer ist.

Ein Ergebnis benennt sein Bild also genau: die Kamera über producer, das Bild über run und sequence. Eine Quelle, die während des laufenden Streams geändert wird, behält den Lauf des Moduls: Die Ergebnisse der neuen Kamera werden weitergezählt, und der producer ihres ersten Schritts benennt sie. Zwei Ergebnisse desselben Kamerabildes, vor und nach einer Änderung der Einstellungen, unterscheiden sich im settings_hash des Modulschritts.

Ein Bild ohne Lineage - veröffentlicht von etwas anderem als dem Cam Driver - ergibt ein Ergebnis mit dem Schritt des Moduls allein. Ein Wert auf dem frame-Knoten des Streams, der kein stream_image ist, wird ignoriert und einmalig protokolliert.

Der Einstellungs-Hash

setting/settings-hash und der settings_hash des Modulschritts in jedem Ergebnis bezeichnen, womit die Ergebnisse erzeugt werden. Der Hash ändert sich, wenn sich eines davon ändert:

  • die Einstellungen der Modulkonfigurationsdatei, mit denen das Modul gestartet wurde - außer dem Abschnitt stream und externalImagePath, die die Bilder auswählen und nicht, was daraus gemacht wird;

  • die Netzbeschreibung und die Netzdatei, die sie benennt, nach ihrem Inhalt - ein neues Netz unter dem alten Dateinamen ist ein neuer Hash; mit simulateResult stattdessen der Inhalt dieser Datei;

  • input/class-filters;

  • die Version der Anwendung.

Ein Reset liest die Netzbeschreibung und die Netzdatei erneut. Wenn ein Hash zum ersten Mal auftritt, schreibt das Modul die Einstellungen, für die er steht, nach settings-history/<network name>-<hash>.json im Konfigurationsordner der Anwendung, sodass ein in einem Ergebnis gefundener Hash später nachgeschlagen werden kann.

Ein Ergebnis trägt nur den Hash. Ein anderer Hash besagt, dass sich etwas geändert hat, womit die Ergebnisse erzeugt werden, nicht was. Um das herauszufinden, vergleichen Sie die beiden Dateien in settings-history, die die Hashes benennen, von Hand. Dasselbe gilt für den Hash der Kamera im Kameraschritt; was er abbildet, steht im Handbuch des Cam Driver, Bilder streamen.

Abonnieren zur Laufzeit

Eine SPS oder ein anderer Client ändert Quelle und Stream-Modus, während die Anwendung läuft, mit oder ohne laufenden Stream:

  1. Schreiben Sie die Eingaben, die sich ändern, auf control/subscribe/input/…​ - für eine andere Kamera control/subscribe/input/address; für eine andere Markierung der Ergebnisse control/subscribe/input/tag; zum Starten oder Stoppen control/subscribe/input/enable.

  2. Schreiben Sie true auf control/subscribe/execute.

Die Methode prüft alle Eingaben gemeinsam, speichert sie im Abschnitt stream und wendet sie dann an: setting/stream/…​ zeigt sie sofort, und ein laufender Stream folgt in seinem nächsten Zyklus. Eine andere Adresse ersetzt die Quelle - ein vorheriges Unsubscribe ist nicht nötig -, und die Bilder, die die alte Kamera noch wartend hatte, zählen als übersprungen. Tag, Warteschlangengröße und keep-latest-output wirken ohne erneutes Abonnieren: Ein neues Tag markiert das nächste Ergebnis.

Um die Quelle zu entfernen, schreiben Sie ihre Adresse auf control/unsubscribe/input/address und true auf control/unsubscribe/execute. Das beendet auch den Stream-Modus und speichert enable als false ohne Adresse. Das Tag bleibt: Es markiert die Ergebnisse des Moduls, nicht die Quelle. control/subscribe/input/…​ werden ebenfalls darauf gesetzt, sodass ein späteres control/subscribe/execute, das eine andere Eingabe ändert, die Quelle nicht zurückbringt. Ein / am Anfang oder Ende einer Adresse spielt keine Rolle.

Die Methoden antworten:

ctrlX Data Layer LumiScan Keryx Wann

DL_OK

Ok

Erledigt.

DL_INVALID_VALUE

Rejected

control/subscribe: enable ist true und die Adresse ist leer, oder die Warteschlangengröße liegt nicht zwischen 1 und 64. control/unsubscribe: Die Adresse ist nicht die Quelle, oder es gibt keine Quelle. Nichts hat sich geändert.

DL_CREATION_FAILED

CreationFailed

Die Konfigurationsdatei des Moduls konnte nicht geschrieben werden. Nichts hat sich geändert: Der Stream bleibt, wie er war. Die Antwort und das Log nennen den Grund.

DL_RESOURCE_UNAVAILABLE

ResourceUnavailable

Die Einstellungen wurden auf system/settings bearbeitet, und die Anwendung wartet auf einen Neustart.

Ein Reset (control/reset) liest den Abschnitt stream der Modulkonfigurationsdatei erneut, wendet ihn an und setzt die Eingaben darauf: Ein laufender Stream folgt. Eine von Hand bearbeitete Datei wirkt also mit einem Reset.

Kann das Abonnement nicht eingerichtet werden, zum Beispiel weil die Kamera noch nicht läuft, versucht es das Modul alle 5 Sekunden erneut, solange der Stream läuft, und protokolliert den ersten Fehlschlag.

Die Warteschlangengröße

control/subscribe/input/queue-size, gespeichert als stream.queueSize, legt fest, wie viele Bilder auf die Inferenz warten dürfen: 1 bis 64, standardmäßig 1. Ein Bild, das eintrifft, wenn so viele warten, verdrängt das älteste davon, was in statistics/skipped-frames gezählt wird.

Warteschlangengröße Wirkung

1 (Standard)

Das Modul inferiert das neueste Bild. Es fällt nie zurück; ist das Netz langsamer als die Kamera, überspringt es Bilder.

Mehr als 1

Kurze Bildschübe werden vollständig inferiert, und weniger Bilder werden übersprungen. Ist das Netz länger langsamer als die Kamera, fällt das Modul zurück: Es inferiert Bilder, die bis zu so viele Inferenzen alt sind. Jedes wartende Bild hält ein ganzes Bild im Speicher.

Eine geänderte Warteschlangengröße gilt für das nächste eintreffende Bild, ohne Neustart des Streams.

Einen Stream ausführen

  1. Stellen Sie sicher, dass der Stream des Cam Driver läuft: Sein control/publish/output/stream/active ist true.

  2. Abonnieren Sie control/subscribe/output/stream/result.

  3. Schreiben Sie true auf control/subscribe/input/enable - und die Adresse der Quelle, falls das Modul noch keine hat - und true auf control/subscribe/execute. Warten Sie, bis control/subscribe/output/stream/active true ist. Ab dann treffen die Ergebnisse ein.

  4. Zum Stoppen schreiben Sie false auf control/subscribe/input/enable und true auf control/subscribe/execute.

Beides wird gespeichert: Das Modul startet wieder so, wie es verlassen wurde. Der Stream kann vor dem Stream des Cam Driver gestartet werden; Ergebnisse treffen ein, sobald Bilder eintreffen.

Inferenz auf Anfrage, während der Stream läuft

Beide verwenden dasselbe Netz, deshalb laufen sie nie gleichzeitig:

  • control/inference/ready ist false, solange der Stream läuft.

  • Ein Request auf control/inference/request wird mit Status 100002 (StreamActive) beantwortet. Er hinterlässt keinen Fehler, und kein Reset ist nötig.

  • control/inference/execute antwortet mit DL_INVALID_OPERATION_MODE (LumiScan Keryx: InvalidOperationMode). Wiederholen Sie es nicht in einer Schleife: Stoppen Sie zuerst den Stream.

  • Reset, list, load, save, save-result-image und remove funktionieren weiterhin. Ein Reset lädt das Netz neu, und der Stream läuft damit weiter.

Gemessene Raten

Gemessen mit einer simulierten Kamera (1440 x 1080, Mono8), einem Detektionsnetz mit einer Eingabe von 640 x 480 auf einer NVIDIA GeForce RTX 2060 SUPER mit dem CUDA-Provider, unter Linux. Die Zahlen zeigen nur die Größenordnung.

  • ctrlX Data Layer: Der Data Layer machte bei den Zahlen keinen Unterschied.

  • LumiScan Keryx auf einem PC (Windows): Auf derselben GPU dauerte eine Inferenz etwa 53 ms, und 18,4 von 30 Bildern pro Sekunde wurden inferiert; die Tabelle zeigt den Lauf unter Linux.

Kamera Empfangen Inferiert Übersprungen Inferenzzeit

10 Bilder/s

10 /s

10 /s

0

etwa 49 ms

30 Bilder/s

30 /s

19,4 /s

10,7 /s

etwa 51 ms

Kein Bild ging verloren oder schlug fehl.

Die Statistik lesen

Die Zähler stehen unter control/subscribe/output/stream/statistics/. Sie beginnen bei jedem Start des Streams bei null und werden, solange er läuft, etwa viermal pro Sekunde aktualisiert.

Zähler Bedeutung

elapsed-ms

Millisekunden seit dem Start des Streams. Teilen Sie einen Zähler dadurch, um eine Rate zu erhalten.

received-frames

Bilder, die das Abonnement geliefert hat.

inferred-frames

Inferierte Bilder, jedes mit einem auf control/subscribe/output/stream/result veröffentlichten Ergebnis.

skipped-frames

Nie inferierte Bilder: von neueren aus der Warteschlange verdrängt, während Inferenzen liefen (siehe Die Warteschlangengröße), oder wartend, als die Quelle ersetzt wurde.

failed-frames

Bilder, die nicht dekodiert oder inferiert werden konnten, zum Beispiel weil ihre Pixel nicht die Größe und das Pixelformat ausfüllen, die sie tragen. Das Log nennt den Grund.

lost-frames

Bilder, die verloren gingen, bevor sie eintrafen, ermittelt aus Lücken in der sequence der Kamera innerhalb eines Laufs ihres Streams. Ein neuer Lauf des Kamera-Streams oder eine neue Quelle beginnt die Zählung von vorn.

inference-us

Mikrosekunden, die alle Inferenzen gedauert haben. Teilen Sie durch inferred-frames für den Mittelwert.