ビデオストリームの高速でロスレスな圧縮


14

静止カメラからのビデオがあります。解像度とFPSはどちらも非常に高いです。私が取得するデータはバイエル形式で、ピクセルあたり10ビットを使用します。プラットフォームには10ビットデータ型がないため、元のデータは16ビットワードを使用してメモリに保存されます。ネットワークを介してデータを送信する前に、何らかの種類のデータのロスレス圧縮を実装したいと思います。

  • カメラは動かないので、連続するフレームの大部分はほぼ同一ですが、避けられないノイズのために完全ではありません(ノイズがなくてもノイズを「失う」べきではないため、ノイズ除去はオプションではありません)。
  • FPSが高いため、変化する部分でさえ、2つの連続するフレーム間であまり変化しません。
  • ただし、カメラも少し揺れているようです。非常にわずかですが、それでも、静止したオブジェクトでさえ、画像空間では完全にはそうではありません。
  • 圧縮はオンザフライで実行する必要があるため、多くのフレームを収集してそれらをまとめて圧縮することはできませんが、1フレーム後ろを見て参照として使用できます。

上記に基づいて、私が最初に考えたのは、データをビットパックすることで、これらの6つの冗長ビットがすべての単語で無駄にならないようにしました。ただし、エントロピーコーディング(ハフマンなど)を使用すると、その冗長性が自動的に考慮されるため、追加のパッキングは必要ないと考えました。だから私は次のことをしました:

  • 2つの連続するフレーム間でバイナリの差分を取りました。元のデータ範囲は0〜1023(たとえば、符号なし10ビット)でした。差分データは符号付きになり、範囲は-1023〜1023に増加しますが、データの変動(または正しい数学用語)は元のデータよりもはるかに小さくなります。実際、ほとんどの値は驚くことではありませんが、ゼロに近いです。 。
  • 違いにライスコーディングを適用しました。私が理解していることから、ほとんど数値が小さいデータセットには良い選択のように見えます。

これにより、1280x720フレームのサイズが約60%削減され、テストシステム(シングルコアのVirtualBoxのLinux)は、1秒あたり約40の圧縮を(最適化なしで)実行できます。それほど素晴らしいわけではありませんが、合理的だと思います(またはそうでしょうか?)。

より良い方法はありますか?よくある間違いはありますか?逃した一般的な手順はありますか?高解像度のフレームは後で使用される可能性があります-フレームサイズが大きいほど、圧縮率が向上すると思いますか?

UPD .:

  • このライブラリをライスエンコーディングに使用しました。ライブラリは非常に低速です(著者自身が実際の使用ではなく学習用と記述しています)。たとえば、ループでビットを1つずつ読み書きするため、パフォーマンスが低下します。最初は〜20 FPSしか与えられませんでしたが、いくつかの非常に基本的な最適化の後、40 FPS(上記のように)になり、後でさらに最適化して80になりました。
  • しかし、ベクトル化に関しては、残念ながら、Riceコードをベクトル化する方法を考えることができませんでした(それが可能かどうかさえわからない-Riceコードに関するデータを見つけることができませんでした、ハフマンコードについて見つけることができることはこれはシーケンシャルであり、効率的にベクトル化することはできません。これは、ライスコードや他の可変長コードに適用される可能性があります。
  • また、まったく異なるアプローチを試みました。データを小さな断片に分割し(例:64ピクセルごとに)、単純なゼロ抑制を使用します。ブロック内で最大の数を見つけ、それを表すために必要なビット数をブロックの先頭に書き込みます(私の場合、追加の4ビットが必要でした)。次に、ブロック内のすべての数を同じ数に減らします。ビット。私は圧縮率が悪いと思っていましたが、断片が小さい場合、それらの多くはノイズスパイクを持たないため、バイナリ差は値ごとに4〜6ビットのようなものに減らすことができ、実際にはそれだけでしたRiceコードよりも約5%悪いですが、約2倍高速です(たとえば、私の場合は160 FPS)。私はそれをベクトル化しようとしましたが、ベクトル化をちょっと嫌っています。

負数には先行ゼロがないため、バイナリ差分の後、ライス/ゼロ抑制の前にジグザグエンコーディングを適用しました。


10ビットモードをサポートするh264などの標準コーデックを使用できます。「-crfまたは-qpを0に設定すると、x264がロスレスモードになり、-preset設定が速度/サイズ比のみに影響します。」(しかし、リアルタイムパフォーマンスを管理できるかどうかはわかりません)
CodesInChaos

@CodesInChaos、それはたった2つのフレームで多くのことをしますか?
ヘッドクラブ

おそらく、さらに重要なこと-標準コーデックは、バイエル画像をエンコードすることさえできますか?誤解しない限り、BayerのRGBへの変換には補間が含まれるため、元に戻すことはできません。
ヘッドクラブ

回答:


4

時間的な予測はありますが、空間はありません。速度を犠牲にしてより良い圧縮を行うには、現在のフレームの現在のピクセルの上と左のピクセルを予測子として使用し、前のフレームの同じ場所のピクセルを使用できる必要があります。上と左を見ているだけの理由は、前のフレームだけを見ている理由と同じです。既にデコードしたデータのみに依存し、保持する必要のあるデータの量を制限します。

ライスコードは、おそらく効率と速度の間の良いトレードオフですが、静的なハフマンコード(ビデオデータのサンプルで事前に計算された)は、より効率的で同等に高速です。

速度に関しては、正しいコンパイラフラグとコードパターンを使用してコンパイラが自動ベクトル化できるようにするか、コードを手書きしてベクトル組み込み関数またはアセンブリを使用することにより、コードがベクトル化されるようにします。

最後に、ピクセルあたり8ビットにドロップダウンする可能性はありますか?明らかにそれは「ロスレス」の領域を残していますが、圧縮出力のサイズを縮小するだけでなく、ベクトル化されたコードを使用すると、スループットを最大2倍に増やすことができます。


10bppを8に減らすことはできないと思いますが、文字を格納するためにUTF-8が1または2バイトを使用するのとほぼ同じ方法で、より少ないビットでデルタを格納することが可能です。デルタが常にほぼ0である場合、10ビットすべてが変化するのを見るのは非常にまれであり、それらを格納するために1または2バイトを決定する努力は価値があります。
gbjbaanb

@gbjbaanbは、Riceコーディングが達成することです。ほとんどのデルタは小さいため、数ビットしか使用しません。
ホッブズ

@hobbs、「空間予測」とは、ピクセル値x5を差で置き換えるようなもの(x5 - x4)ですか?
ヘッドクラブ

@Headcrab-私が以前に使用したアプローチは、前のピクセルと現在のフレームの上下のピクセルの中央値を使用することです。
ジュール

@Julesピクセルが周囲のピクセルのある種の中央値に置き換えられた場合、元の値を復元することは可能ですか?
ヘッドクラブ

0

おそらく、圧縮と解凍の既存の実装を使用するのが最適です。既存の実装はHuffYUVコーデックに類似しているように見えるため、十分に機能するかどうかを確認する価値があるかもしれません。


libx264「preset ultrafast」は歴史的にFWIWに非常によく役立っています
...-rogerdpack

@rogerdpack-ロスレスエンコーディング用のlibx264の設定により、H.264に準拠していない出力が発生し、一部のプレーヤーで破損することに注意してください。ただし、少なくともOPのアプリケーションには役立つ可能性があります。
ジュール

おもしろいことへのリンクはありますか?バグレポート?また、HuffyYUVでエンコードされたビデオはおそらく「ユニプレーヤーフレンドリー」でもないことに注意してください。私は想像します:)
rogerdpack
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.