Kompresi aliran video yang cepat dan tanpa kehilangan

14

Saya punya video yang berasal dari kamera stasioner. Baik resolusi dan FPS cukup tinggi. Data yang saya dapatkan adalah dalam format Bayer dan menggunakan 10 bit per piksel. Karena tidak ada tipe data 10 bit di platform saya, data asli disimpan dalam memori menggunakan kata-kata 16-bit. Saya ingin menerapkan semacam kompresi data tanpa kehilangan sebelum mentransmisikannya melalui jaringan.

  • Kamera tidak bergerak, jadi bagian besar dari frame yang berurutan hampir identik - tetapi masih belum sepenuhnya, karena noise yang tidak terhindarkan (denoising bukan pilihan, karena seharusnya lossless dan tidak boleh "kehilangan" bahkan noise) ).
  • Karena FPS tinggi, bahkan bagian yang berubah tidak banyak berubah di antara dua frame yang berurutan.
  • Namun, sepertinya kamera juga bergetar sedikit. Sangat sedikit, tapi tetap saja, bahkan benda-benda yang diam tidak sepenuhnya berada di ruang gambar.
  • Kompresi harus dilakukan dengan cepat, jadi saya tidak bisa mengumpulkan banyak frame dan mengompres semuanya, tapi saya bisa melihat 1 frame kembali dan menggunakannya sebagai referensi.

Berdasarkan hal di atas, pikiran pertama saya adalah meng-bit-data, sehingga 6 bit redundan itu tidak terbuang sia-sia untuk setiap kata. Namun, saya berpikir bahwa jika saya menggunakan beberapa pengkodean entropi (misalnya Huffman dll.), Redundansi itu akan secara otomatis diperhitungkan, jadi tidak perlu pengepakan tambahan. Jadi saya sudah melakukan yang berikut:

  • Mengambil perbedaan biner antara dua frame berturut-turut. Rentang data asli adalah 0 ~ 1023 (mis. 10 bit yang tidak ditandatangani). Perbedaan data menjadi masuk dan kisarannya meningkat menjadi -1023 ~ 1023, tetapi variasi data (atau apa istilah matematika yang benar) menjadi jauh lebih sedikit daripada dalam data asli, pada kenyataannya, sebagian besar nilai, tidak mengherankan, mendekati nol .
  • Pengodean Beras Terapan untuk perbedaan. Dari apa yang saya mengerti, sepertinya pilihan yang baik untuk set data nilai numerik sebagian besar kecil.

Ini memberi saya pengurangan sekitar 60% dalam ukuran untuk 1280x720 frame, dan sistem pengujian saya (Linux dalam VirtualBox pada satu inti) dapat melakukan ~ 40 kompresi seperti itu per detik (tanpa banyak optimasi). Tidak terlalu bagus, tapi masuk akal, kurasa (atau itu?).

Apakah ada cara yang lebih baik? Adakah kesalahan umum yang saya buat? Adakah langkah umum yang saya lewatkan? Bingkai resolusi yang lebih tinggi dapat digunakan nanti - haruskah saya mengharapkan tingkat kompresi yang lebih baik untuk ukuran bingkai yang lebih besar?

UPD .:

  • Saya menggunakan perpustakaan ini untuk pengkodean Rice. Perpustakaan sangat lambat (penulis sendiri menggambarkannya sebagai sesuatu untuk belajar daripada untuk penggunaan nyata), misalnya membaca dan menulis bit satu per satu dalam loop, yang membunuh kinerja. Awalnya hanya memberi saya ~ 20 FPS, setelah beberapa optimasi yang sangat dasar menjadi 40 FPS (seperti yang dilaporkan di atas), kemudian saya optimalkan lagi, menjadi 80. Itu adalah pada inti i7 tunggal tanpa vektorisasi.
  • Sedangkan untuk vektorisasi, sayangnya, saya tidak bisa memikirkan cara untuk membuat vektor kode Beras (bahkan tidak tahu apakah itu mungkin - tidak dapat menemukan data pada kode Beras, apa yang dapat saya temukan tentang kode Huffman menunjukkan bahwa ini berurutan dan tidak dapat secara efisien di-vektor, yang mungkin berlaku untuk kode Beras serta kode panjang variabel lainnya).
  • Saya juga mencoba pendekatan yang sama sekali berbeda: memecah data menjadi potongan-potongan kecil (misalnya, masing-masing 64 pixel) dan menggunakan penekanan nol sederhana. Kami menemukan angka terbesar dalam sebuah blok, menulis jumlah bit yang diperlukan untuk mewakilinya ke awal blok (4 bit tambahan diperlukan untuk itu, dalam kasus saya), kemudian mengurangi semua angka dalam blok ke jumlah yang sama bit. Saya perkirakan tingkat kompresi menjadi buruk, tetapi jika kepingannya kecil, banyak dari mereka tidak akan memiliki lonjakan noise, oleh karena itu perbedaan binernya dapat dikurangi menjadi sekitar 4 ~ 6 bit per nilai, dan itu, pada kenyataannya, hanya sekitar 5% lebih buruk daripada kode Beras, sementara menjadi sekitar dua kali lebih cepat (misalnya 160 FPS untuk kasus saya). Saya mencoba melakukan vektorisasi, tetapi saya agak menyedot vektorisasi, jadi mungkin karena itu saya hanya dapat mencapai sekitar x1.8 percepatan lebih lanjut.

Karena bilangan negatif tidak memiliki nol di depan, saya menerapkan pengkodean zigzag setelah perbedaan biner dan sebelum penekan Rice / nol.

Headcrab
sumber
Anda dapat menggunakan codec standar seperti h264 yang mendukung mode 10 bit. "Pengaturan -crf atau -qp ke 0 memaksa x264 dalam mode lossless, pengaturan -reset hanya berdampak pada kecepatan / rasio ukuran." (Tapi saya tidak tahu apakah itu akan mengatur kinerja waktu nyata)
CodesInChaos
@CodesInChaos, apakah itu akan banyak membantu hanya untuk dua frame?
Headcrab
Mungkin, yang lebih penting - dapatkah codec standar bahkan menyandikan gambar Bayer? Jika saya tidak salah, konversi Bayer ke RGB melibatkan interpolasi, dan karenanya, tidak dapat dipulihkan.
Headcrab

Jawaban:

4

Anda punya prediksi temporal, tetapi tidak ada spasial. Untuk kompresi yang lebih baik dengan biaya kecepatan, Anda harus dapat menggunakan piksel di atas dan di sebelah kiri piksel saat ini di bingkai saat ini sebagai prediktor, serta piksel di lokasi yang sama di bingkai sebelumnya. Alasan untuk hanya melihat ke atas dan ke kiri adalah sama dengan alasan untuk hanya melihat pada bingkai sebelumnya; Anda hanya ingin bergantung pada data yang sudah Anda dekodekan, dan batasi berapa banyak yang harus Anda simpan.

Kode Rice mungkin merupakan tradeoff yang baik antara efisiensi dan kecepatan, tetapi kode Huffman statis (yang diperhitungkan oleh Anda pada sampel data video) mungkin lebih efisien dan sama cepatnya.

Sedangkan untuk kecepatan, pastikan kode Anda mendapatkan vektor - baik dengan menggunakan flag compiler yang tepat dan pola kode untuk memungkinkan kompiler untuk auto-vectorize, atau dengan menulis tangan kode untuk menggunakan intrinsik vektor atau perakitan.

Akhirnya, apakah turun menjadi 8 bit per piksel kemungkinan? Jelas itu meninggalkan ranah "lossless", tetapi tidak hanya akan mengurangi ukuran output terkompresi Anda, itu juga, dengan kode vektor, mungkin meningkatkan throughput Anda hingga 2x.

hobbs
sumber
Saya kira mengurangi 10bpp menjadi 8 tidak mungkin, tetapi bisa saja menyimpan delta dalam bit yang lebih sedikit, dengan cara yang sama seperti UTF-8 menggunakan 1 atau kadang-kadang 2 byte untuk menyimpan karakter. Jika delta hampir 0 sepanjang waktu, maka akan sangat jarang untuk melihat semua 10 bit berubah, dan sangat sepadan dengan upaya menentukan 1 atau 2 byte untuk menyimpannya.
gbjbaanb
@ gbjbaanb itulah yang dicapai oleh pengkodean Rice. Kebanyakan delta akan berukuran kecil, dan karenanya hanya menggunakan beberapa bit.
hobbs
@ hobbs, dengan "prediksi spasial", maksud Anda seperti mengganti nilai piksel x5dengan perbedaan (x5 - x4)?
Headcrab
@ Headcrab - pendekatan yang pernah saya lihat digunakan sebelumnya adalah menggunakan nilai median dari piksel sebelumnya dan piksel di atas dan dibiarkan dalam bingkai saat ini.
Jules
@ Jules jika sebuah piksel diganti dengan semacam nilai median piksel sekitarnya, apakah mungkin untuk mengembalikan nilai aslinya?
Headcrab
0

Anda mungkin paling baik dilayani dengan menggunakan implementasi kompresi dan dekompresi yang ada. Implementasi Anda saat ini tampaknya mirip dengan codec HuffYUV , jadi mungkin ada baiknya mencoba itu untuk melihat apakah itu bekerja cukup baik untuk Anda.

Jules
sumber
libx264 "preset ultrafast" telah melayani saya dengan cukup baik secara historis FWIW ...
rogerdpack
@rogerdpack - Perlu dicatat bahwa pengaturan libx264 untuk hasil enkode lossless menghasilkan output yang tidak sesuai dengan H.264 dan merusak beberapa pemain. Tapi itu bisa berguna untuk aplikasi OP, setidaknya.
Jules
menarik apakah Anda memiliki tautan ke sana? Laporan bug? Juga perhatikan bahwa video yang dikodekan dengan HuffyYUV mungkin juga bukan "ramah pemain", saya bayangkan :)
rogerdpack