Ich habe ein Video von einer stationären Kamera. Sowohl die Auflösung als auch die FPS sind recht hoch. Die Daten, die ich erhalte, sind im Bayer- Format und verwenden 10 Bit pro Pixel. Da es auf meiner Plattform keinen 10-Bit-Datentyp gibt, werden die Originaldaten mithilfe von 16-Bit-Wörtern im Speicher gespeichert. Ich möchte eine verlustfreie Komprimierung der Daten implementieren, bevor sie über ein Netzwerk übertragen werden.
- Die Kamera bewegt sich nicht, sodass große Teile aufeinanderfolgender Bilder nahezu identisch sind - aber aufgrund des unvermeidlichen Rauschens immer noch nicht vollständig (Rauschunterdrückung ist keine Option, da sie verlustfrei sein soll und nicht einmal das Rauschen "verlieren" sollte ).
- Aufgrund der hohen FPS ändern sich selbst die Teile, die sich ändern, zwischen zwei aufeinanderfolgenden Bildern nicht wesentlich.
- Es sieht jedoch so aus, als ob die Kamera auch ein wenig wackelt. Sehr wenig, aber auch die stationären Objekte sind im Bildraum nicht ganz so.
- Die Komprimierung muss im laufenden Betrieb erfolgen, daher kann ich nicht viele Frames erfassen und alle zusammen komprimieren, aber ich kann 1 Frame zurückblicken und als Referenz verwenden.
Auf der Grundlage des oben Gesagten war mein erster Gedanke, die Daten bitweise zu packen, damit diese 6 redundanten Bits nicht für jedes Wort verschwendet werden. Ich dachte jedoch, dass bei Verwendung einer Entropiecodierung (z. B. Huffman usw.) diese Redundanz automatisch berücksichtigt wird, sodass kein zusätzliches Packen erforderlich ist. Also habe ich folgendes gemacht:
- Nahm binäre Differenz zwischen zwei aufeinanderfolgenden Bildern. Der ursprüngliche Datenbereich lag zwischen 0 und 1023 (z. B. 10 Bit ohne Vorzeichen). Differenzdaten werden signiert und der Bereich steigt auf -1023 ~ 1023, aber die Datenvariation (oder was ist der richtige mathematische Ausdruck) wird viel geringer als in den Originaldaten, in der Tat sind die meisten Werte nicht überraschend nahe Null .
- Angewandte Reiskodierung zum Unterschied. Soweit ich weiß, scheint dies eine gute Wahl für Datensätze mit meist kleinen numerischen Werten zu sein.
Dadurch kann ich die Größe von 1280 x 720 Frames um etwa 60% reduzieren, und mein Testsystem (Linux in VirtualBox auf einem einzelnen Kern) kann ~ 40 solcher Komprimierungen pro Sekunde durchführen (ohne viel Optimierung). Nicht so toll, aber vernünftig, denke ich (oder?).
Gibt es bessere Wege? Häufig gemachte Fehler? Irgendwelche allgemeinen Schritte, die ich verpasst habe? Frames mit höherer Auflösung können später verwendet werden. Sollte ich bei größeren Frames mit besseren Komprimierungsraten rechnen?
UPD .:
- Ich habe diese Bibliothek für die Rice-Codierung verwendet. Die Bibliothek ist sehr langsam (der Autor selbst beschreibt sie eher als etwas zum Lernen als für den wirklichen Gebrauch), zum Beispiel liest und schreibt sie Bits nacheinander in Schleifen, was die Leistung beeinträchtigt. Anfangs gab es mir nur ~ 20 FPS, nach einer sehr einfachen Optimierung wurden es 40 FPS (wie oben berichtet), später optimierte ich es noch weiter, es wurde 80. Das ist auf einem einzelnen i7-Kern ohne Vektorisierung.
- Was die Vektorisierung betrifft, konnte ich mir leider keine Möglichkeit vorstellen, Reiscode zu vektorisieren (ich weiß nicht einmal, ob dies überhaupt möglich ist - ich konnte keine Daten zu Reiscode finden, was ich über Huffman-Code finden könnte, legt dies nahe Es ist sequentiell und kann nicht effizient vektorisiert werden (dies kann sowohl für Reiscode als auch für andere Codes variabler Länge gelten).
- Ich habe auch einen ganz anderen Ansatz ausprobiert: Teilen Sie die Daten in kleine Teile (z. B. 64 Pixel pro Stück) und verwenden Sie die einfache Nullunterdrückung. Wir finden die größte Zahl in einem Block, schreiben die Anzahl der Bits, die erforderlich sind, um ihn am Anfang des Blocks darzustellen (in meinem Fall wurden dafür 4 zusätzliche Bits benötigt), und reduzieren dann alle Zahlen im Block auf die gleiche Anzahl von Bits. Ich habe erwartet, dass die Komprimierungsrate schlecht ist, aber wenn die Teile klein sind, haben viele von ihnen keine Rauschspitzen, daher kann ihre binäre Differenz auf etwa 4 bis 6 Bits pro Wert reduziert werden, und das war in der Tat nur so Etwa 5% schlechter als der von Rice Code, aber ungefähr doppelt so schnell (zB 160 FPS für meinen Fall). Ich habe versucht, es zu vektorisieren, aber ich habe ein bisschen an der Vektorisierung gesaugt, deshalb konnte ich vielleicht nur etwa das 1,8-fache der weiteren Beschleunigung erreichen.
Da negative Zahlen keine führenden Nullen haben, habe ich die Zick-Zack-Codierung nach der binären Differenz und vor der Unterdrückung von Reis / Null angewendet .