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/subscribeund 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.
| Adresse | Bedeutung |
|---|---|
|
Prüft alle |
|
Entfernt die Quelle, die |
| Adresse | Typ | Beim Start | Bedeutung |
|---|---|---|---|
|
bool |
|
|
|
string |
|
Der Stream-Ordner der Quelle, der das |
|
string |
|
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 - |
|
uint32 |
|
Wie viele Bilder auf die Inferenz warten dürfen, 1 bis 64. Siehe Die Warteschlangengröße. |
|
bool |
|
|
|
string |
leer |
Die Quelle, die |
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.
| Adresse | Typ | Bedeutung |
|---|---|---|
|
bool |
|
|
flatbuffer |
Das Ergebnis jedes inferierten Bildes, im selben Format wie |
|
uint64 |
Zähler des laufenden oder letzten Streams, siehe Die Statistik lesen. |
| Adresse | Typ | Bedeutung |
|---|---|---|
|
wie die Eingaben |
Was das Modul gerade anwendet, wie im Abschnitt |
|
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 |
|---|---|
|
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 ( |
|
Wann das Bild eingetroffen ist, in Mikrosekunden seit der Epoche. |
|
Wann die Inferenz auf dem Bild gestartet wurde, in Mikrosekunden seit der Epoche. Die Differenz zu
|
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:
-
Der Schritt der Kamera, wie der Cam Driver ihn erzeugt hat:
producerist die Adresse der Kamera,hdvisionsystems/lumiscan-cam-driver/<camera name>,run, wann ihr Stream gestartet wurde,sequencedie Nummer des Bildes in diesem Lauf,external_iddie eigene Bildnummer der Kamera,settings_hashdie Einstellungen der Kamera undtagdas Tag des Cam Driver für die Kamera, standardmäßig ihre Modul-ID, zum Beispielcamera1. -
Der Schritt des Moduls:
producerist 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);sequencedie Nummer des Ergebnisses im Lauf;settings_hashdie Einstellungen des Moduls, siehe Der Einstellungs-Hash;elapsed_usdie Mikrosekunden vom Eintreffen des Bildes bis zur Veröffentlichung des Ergebnisses;time_us, wann es veröffentlicht wurde;tagdas 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
streamundexternalImagePath, 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
simulateResultstattdessen 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:
-
Schreiben Sie die Eingaben, die sich ändern, auf
control/subscribe/input/…- für eine andere Kameracontrol/subscribe/input/address; für eine andere Markierung der Ergebnissecontrol/subscribe/input/tag; zum Starten oder Stoppencontrol/subscribe/input/enable. -
Schreiben Sie
trueaufcontrol/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 |
|---|---|---|
|
|
Erledigt. |
|
|
|
|
|
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. |
|
|
Die Einstellungen wurden auf |
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
-
Stellen Sie sicher, dass der Stream des Cam Driver läuft: Sein
control/publish/output/stream/activeisttrue. -
Abonnieren Sie
control/subscribe/output/stream/result. -
Schreiben Sie
trueaufcontrol/subscribe/input/enable- und die Adresse der Quelle, falls das Modul noch keine hat - undtrueaufcontrol/subscribe/execute. Warten Sie, biscontrol/subscribe/output/stream/activetrueist. Ab dann treffen die Ergebnisse ein. -
Zum Stoppen schreiben Sie
falseaufcontrol/subscribe/input/enableundtrueaufcontrol/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/readyistfalse, solange der Stream läuft. -
Ein Request auf
control/inference/requestwird mit Status100002(StreamActive) beantwortet. Er hinterlässt keinen Fehler, und kein Reset ist nötig. -
control/inference/executeantwortet mitDL_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 |
|---|---|
|
Millisekunden seit dem Start des Streams. Teilen Sie einen Zähler dadurch, um eine Rate zu erhalten. |
|
Bilder, die das Abonnement geliefert hat. |
|
Inferierte Bilder, jedes mit einem auf |
|
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. |
|
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. |
|
Bilder, die verloren gingen, bevor sie eintrafen, ermittelt aus Lücken in der |
|
Mikrosekunden, die alle Inferenzen gedauert haben. Teilen Sie durch |