Bir video akışının hızlı, kayıpsız sıkıştırılması


14

Sabit bir kameradan gelen bir videom var. Hem çözünürlük hem de FPS oldukça yüksek. Aldığım veriler Bayer biçimindedir ve piksel başına 10 bit kullanır. Platformumda 10 bit veri türü olmadığından, orijinal veriler 16 bit sözcükler kullanılarak bellekte saklanır. Verileri bir ağ üzerinden aktarmadan önce bir tür kayıpsız sıkıştırma uygulamak istiyorum .

  • Kamera hareket etmiyor, bu yüzden ardışık çerçevelerin büyük bölümleri neredeyse aynı - ancak yine de tamamen kaçınılmaz gürültü nedeniyle (denoising bir seçenek değil, kayıpsız olması ve gürültüyü bile “kaybetmemesi” gerektiği için) ).
  • Yüksek FPS nedeniyle, değişen parçalar bile art arda iki kare arasında çok fazla değişmez.
  • Ancak, kamera da biraz titriyor gibi görünüyor. Çok az, ama yine de, sabit nesneler bile görüntü alanında tamamen öyle değildir.
  • Sıkıştırma anında yapılmalıdır, bu yüzden çok fazla kare toplayamıyorum ve hepsini birlikte sıkıştıramıyorum, ancak 1 kare geriye bakabilir ve referans olarak kullanabilirim.

Yukarıdakilere dayanarak, ilk düşüncem veriyi bit paketlemektir, böylece bu 6 yedek bit her kelimede boşa harcanmaz. Bununla birlikte, eğer bazı entropi kodlaması (örn. Huffman vb.) Kullanırsam, fazlalık otomatik olarak dikkate alınacağını düşündüm, bu yüzden fazladan paketlemeye gerek yoktur. Bu yüzden aşağıdakileri yaptım:

  • Birbirini takip eden iki kare arasında ikili fark yarattı. Orijinal veri aralığı 0 ~ 1023'tür (örneğin işaretsiz 10 bit). Fark verileri imzalanır ve aralık -1023 ~ 1023'e yükselir, ancak veri varyasyonu (veya doğru matematiksel terim nedir) orijinal verilerden çok daha az olur, aslında, değerlerin çoğu şaşırtıcı değildir, sıfıra yakındır .
  • Farkı uygulayan Pirinç kodlaması. Anladığım kadarıyla, çoğunlukla küçük sayısal değerlere sahip veri setleri için iyi bir seçim gibi görünüyor.

Bu bana 1280x720 kareler için boyutta yaklaşık% 60 azalma sağlar ve test sistemim (tek bir çekirdekteki VirtualBox'ta Linux) saniyede ~ 40 sıkıştırma yapabilir (fazla optimizasyon olmadan). O kadar büyük değil, ama makul, sanırım (ya da öyle mi?).

Daha iyi yollar var mı? Sık yaptığım hatalar var mı? Kaçırdığım genel adımlar var mı? Daha sonra daha yüksek çözünürlüklü çerçeveler kullanılabilir - daha büyük çerçeve boyutları için daha iyi sıkıştırma oranları beklemeli miyim?

UPD .:

  • Bu kütüphaneyi Rice kodlaması için kullandım . Kütüphane çok yavaştır (yazar bunu gerçek kullanım yerine öğrenme için bir şey olarak tanımlar), örneğin döngülerde bitleri tek tek okur ve yazar, bu da performansı öldürür. Başlangıçta bana sadece ~ 20 FPS verdi, bazı çok temel optimizasyonlardan sonra 40 FPS oldu (yukarıda bildirildiği gibi), daha sonra biraz daha optimize ettim, 80 oldu. Bu, vektörizasyon olmadan tek bir i7 çekirdeğinde.
  • Vectorization gelince, ne yazık ki, Rice kodunu vektörleştirmek için bir yol düşünemedim (mümkün olup olmadığını bile bilmiyorum - Rice kodu hakkında herhangi bir veri bulamadık, Huffman kodu hakkında ne bulabiliriz Sıralı ve verimli bir şekilde vektörleştirilemez, bu Rice koduna ve diğer değişken uzunluklu kodlara uygulanabilir).
  • Ayrıca tamamen farklı bir yaklaşım denedim: verileri küçük parçalara ayırın (örneğin 64 piksel gibi) ve basit sıfır bastırma kullanın. Bir bloktaki en büyük sayıyı buluyoruz, onu bloğun başına temsil etmek için gereken bit sayısını yazıyoruz (benim durumumda bunun için 4 ek bit gerekli), ardından bloktaki tüm sayıları aynı sayıda bit. Sıkıştırma oranının kötü olmasını bekledim, ancak parçalar küçükse, çoğunda gürültü sivri olmayacak, bu nedenle ikili farkları değer başına 4 ~ 6 bit gibi bir şeye indirgenebilir ve aslında, sadece Rice kodundan yaklaşık% 5 daha kötü, yaklaşık iki kat daha hızlı (örneğin benim durumum için 160 FPS). Onu vektörleştirmeyi denedim, ama vektörleşmeyi emmek gibi, belki de bundan dolayı sadece yaklaşık x1.8 daha fazla hızlanma elde edebildim.

Negatif sayılar önde gelen sıfırlara sahip olmadığından, ikili farktan sonra ve Rice / sıfır bastırmadan önce zikzak kodlaması uyguladım .


10 bit modunu destekleyen h264 gibi standart bir codec bileşeni kullanabilirsiniz . "-Crf veya -qp değerini 0 olarak ayarlamak, x264'ü kayıpsız modda zorlar, -preset ayarları yalnızca hız / boyut oranını etkiler." (Ama gerçek zamanlı performansı yönetip yönetmeyeceğini bilmiyorum)
CodesInChaos

@CodesInChaos, sadece iki kare için çok şey yapar mı?
Headcrab

Belki de daha da önemlisi - standart kodekler Bayer görüntülerini bile kodlayabilir mi? Yanılmıyorsam, Bayer'in RGB'ye dönüştürülmesi enterpolasyon içerir ve bu nedenle geri döndürülemez.
Headcrab

Yanıtlar:


4

Zamansal bir tahmininiz var, ancak uzamsal değil. Hız pahasına daha iyi sıkıştırma için, geçerli karedeki geçerli pikselin üstündeki ve solundaki pikselleri öngörücüler olarak ve önceki karedeki aynı konumdaki pikseli kullanabilmeniz gerekir. Sadece yukarı ve sola bakma nedeni, yalnızca önceki çerçeveye bakma nedeniyle aynıdır; yalnızca daha önce deşifre ettiğiniz verilere güvenmek ve ne kadarını saklamanız gerektiğini sınırlamak istiyorsunuz.

Pirinç kodları büyük olasılıkla verimlilik ve hız arasında iyi bir dengedir, ancak statik bir Huffman kodu (sizin tarafınızdan bir video verisi örneğinde önceden hesaplanmıştır) daha verimli ve eşit derecede hızlı olabilir.

Hıza gelince, kodunuzun vektörelleştirildiğinden emin olun - derleyicinin otomatik olarak vektörleşmesine izin vermek için doğru derleyici bayraklarını ve kod kalıplarını kullanarak veya vektör intrinsiklerini veya montajını kullanmak için kodu elle yazarak .

Son olarak, piksel başına 8 bite düşmek bir olasılık mı? Açıkçası bu "kayıpsız" alanını bırakıyor, ancak sadece sıkıştırılmış çıktınızın boyutunu küçültmekle kalmıyor, aynı zamanda vectorized kodla, veriminizi 2 kata kadar artıracaktı.


Sanırım 10bpp'yi 8'e düşürmek mümkün değil, ancak UTF-8'in bir karakteri saklamak için 1 veya bazen 2 bayt kullandığı gibi deltaları daha az bitte saklamak mümkün olabilir. Eğer deltalar her zaman yaklaşık 0 ise, o zaman 10 bitin de değiştiğini görmek oldukça nadir olurdu ve bu yüzden bunları saklamak için 1 veya 2 bayt belirleme çabasına değer.
gbjbaanb

@gbjbaanb Rice kodlamasının başardığı şey budur. Çoğu delta küçük olacaktır ve bu nedenle sadece birkaç bit kullanacaktır.
ocaklar

@hobbs, "uzamsal tahmin" x5ile bir piksel değerini farkla değiştirmek gibi bir şey mi demek istediniz (x5 - x4)?
Headcrab

@Headcrab - Daha önce kullandığım bir yaklaşım, önceki pikselin medyan değerini ve geçerli karede yukarıdaki ve soldaki pikselleri kullanmaktır.
Jules

@ Bir piksel, etrafındaki piksellerin bir tür medyan değeri ile değiştirilirse, orijinal değerini geri yüklemek mümkün mü?
Headcrab

0

Muhtemelen en iyi şekilde, mevcut sıkıştırma ve dekompresyon uygulamaları kullanılarak sunulur. Mevcut uygulamanız HuffYUV codec bileşenine benziyor , bu nedenle sizin için yeterince iyi çalışıp çalışmadığını görmek faydalı olabilir.


libx264 "preset ultrafast" bana geçmişte oldukça iyi hizmet etti FWIW ...
rogerdpack

@rogerdpack - libx264'ün kayıpsız kodlama ayarının, H.264 uyumlu olmayan ve bazı oynatıcılarda kesilen bir çıktıyla sonuçlandığını belirtmek gerekir. Ancak en azından OP'nin uygulaması için yararlı olabilir.
Jules

ilginç herhangi bir bağlantı var mı? Hata raporu? Ayrıca, HuffyYUV ile kodlanmış bir videonun muhtemelen "uni oynatıcı dostu" olmadığını unutmayın, hayal ediyorum :)
rogerdpack
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.