Schnelle, verlustfreie Komprimierung eines Videostreams


14

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 .


Sie könnten einen Standard-Codec wie h264 verwenden, der einen 10-Bit-Modus unterstützt. "Das Setzen von -crf oder -qp auf 0 zwingt x264 im verlustfreien Modus, die voreingestellten Einstellungen wirken sich dann nur auf das Verhältnis von Geschwindigkeit zu Größe aus." (Aber ich weiß nicht, ob es Echtzeit-Leistung verwalten wird)
CodesInChaos

@CodesInChaos, würde es viel für nur zwei Frames tun?
Headcrab

Vielleicht noch wichtiger: Können Standard-Codecs sogar Bayer-Bilder codieren? Wenn ich mich nicht irre, beinhaltet die Konvertierung von Bayer in RGB eine Interpolation und ist daher irreversibel.
Headcrab

Antworten:


4

Sie haben eine zeitliche Vorhersage, aber keine räumliche. Für eine bessere Komprimierung zu Lasten der Geschwindigkeit sollten Sie in der Lage sein, die Pixel oberhalb und links des aktuellen Pixels im aktuellen Frame als Prädiktoren sowie die Pixel an derselben Position im vorherigen Frame zu verwenden. Der Grund, warum nur nach oben und links geschaut wird, ist der gleiche wie der Grund, warum nur der vorherige Frame angeschaut wird. Sie möchten sich nur auf Daten verlassen, die Sie bereits dekodiert haben, und begrenzen, wie viel davon Sie aufbewahren müssen.

Reiscodes sind wahrscheinlich ein guter Kompromiss zwischen Effizienz und Geschwindigkeit, aber ein statischer Huffman-Code (von Ihnen für ein Beispiel von Videodaten vorberechnet) ist möglicherweise effizienter und ebenso schnell.

Was der Geschwindigkeit, stellen Sie sicher , dass Ihr Code wird immer vektorisiert - entweder durch den richtigen Compiler - Flags und Codemuster mit dem Compiler Auto-vectorize zu ermöglichen, oder von Hand zu schreiben , den Code zu verwenden Vektor - Spezifika oder Montag.

Ist es schließlich möglich, auf 8 Bit pro Pixel abzusinken? Das würde natürlich den Bereich "verlustfrei" verlassen, aber nicht nur die Größe Ihrer komprimierten Ausgabe verringern, sondern mit vektorisiertem Code möglicherweise auch Ihren Durchsatz auf das Zweifache steigern.


Ich denke, die 10bpp auf 8 zu reduzieren ist nicht möglich, aber es könnte möglich sein, die Deltas in weniger Bits zu speichern, ähnlich wie UTF-8 1 oder manchmal 2 Bytes zum Speichern eines Zeichens verwendet. Wenn die Deltas die ganze Zeit beinahe 0 sind, ist es ziemlich selten, dass sich alle 10 Bits ändern. Daher lohnt es sich, 1 oder 2 Bytes zu bestimmen, um sie zu speichern.
gbjbaanb

@ Gbjbaanb das ist, was die Reis-Codierung erreicht. Die meisten Deltas sind klein und verwenden daher nur wenige Bits.
Hobbs

@hobbs, meinst du mit "räumlicher Vorhersage" so etwas wie das Ersetzen eines Pixelwerts x5durch den Unterschied (x5 - x4)?
Headcrab

@Headcrab - ein Ansatz, den ich zuvor gesehen habe, besteht darin, den Medianwert des vorherigen Pixels und der Pixel über und links im aktuellen Frame zu verwenden.
Jules

@Jules Wenn ein Pixel durch einen Medianwert der umgebenden Pixel ersetzt wird, kann der ursprüngliche Wert wiederhergestellt werden?
Headcrab

0

Am besten eignen sich wahrscheinlich vorhandene Implementierungen für Komprimierung und Dekomprimierung. Ihre vorhandene Implementierung scheint dem HuffYUV- Codec zu ähneln. Es lohnt sich also zu prüfen, ob sie für Sie gut genug funktioniert.


libx264 "voreingestellte ultraschnelle" hat mir historisch gesehen recht gute Dienste
geleistet

@rogerdpack - Es ist erwähnenswert, dass die Einstellung von libx264 für verlustfreie Codierung zu einer Ausgabe führt, die nicht H.264-kompatibel ist und auf einigen Playern nicht funktioniert. Aber es könnte zumindest für die Anwendung des OP nützlich sein.
Jules

Interessant, hast du irgendwelche Links dazu? Fehlerbericht? Beachten Sie auch, dass ein mit HuffyYUV codiertes Video wahrscheinlich auch nicht "uni player friendly" ist, würde ich mir vorstellen :)
Rogerdpack
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.