Dlaczego śnieg i konfetti psują jakość filmu?

Jeden z wpisów na moim blogu został zalinkowany pod treścią na Wykopie o tym samym tytule. Wpis na wykopie linkował do wideo, którego autor w bardzo prosty sposób wyjaśniał skąd bierze się pogorszenie jakości wideo w przypadku pojawienia się “szumów” w postaci śniegu czy czegoś w rodzaju konfetti.
Przy okazji dziękuję społeczności Wykopu za linka do mojego bloga, nigdy wcześniej nie  miałem tylu odwiedzin.

Zapraszam do zapoznania się z oryginalnym wpisem “Dlaczego śnieg i konfetti psują jakość filmu?”. Ja tymczasem spróbuję zagłębić się w ten temat trochę bardziej.

1. Kwantyzacja DCT

Przypomnijmy z jakich etapów składa się kompresja pojedynczego obrazka, na przykładzie JPEGa:

Podpróbkowanie –> Cięcie na bloki –> transformacja DCT bloków –> kwantyzacja –> kodowanie entropijne

JPEG, tak jak h.263,4,5 i inne mpegi – to kodeki stratne. Gdyby były bezstratne, to jak wspomina autor filmiku z Wykopu, nie dałoby się fizycznie przepychać wideo o dużej rozdzielczości przez współczesne łącza sieciowe. Zatem w którym etapie następuje strata?
Pominę etap podpróbkowania, chociaż tam występują pierwsze straty. Właściwa strata, mająca zasadniczy wpływ na obserwowaną jakośc wideo, jak także na rozmiar lub inaczej bitrate (przepływność), odbywa się wyłącznie w etapie kwantyzacji.

W tym momencie postaram się zilustrować jak działa kwantyzacja przykładzie. Wyobraźmy sobie, że macierz poniżej jest macierzą współczynników DCT, jak wiadomo, DCT ma skłonność do kumulowania informacji w lewym górnym rogu. Żeby było wiarygodnie, postanowiłem podkraść konkretne współczynniki ze strony naukowca z Uniwersytetu Stanforda:

Teraz dokonajmy takiej biednej kwantyzacji, podzielmy każdy współczynnik przez 5 w sposób, w jaki zrobiłby to procesor, czyli np 4/5 = 0, 5/5 = 1 itd..

W przykładzie z linku użyta została konkretna tablica kwantyzacji, która ma tę cechę, że wspólczynniki w niej rosną w kierunku dolnego prawgo rogu, odwrotnie niż w przypadku macierzy DCT. Taka tablica kwantyzacji w zasadzie wycina większość współczynników “wyższych częstotliwości”.

Jak widać, kwantyzacja doprowadziła do tego, że po pierwsze mamy w niej mniej unikalnych liczb, pewne liczby powtarzają się dość często, to na pewno ucieszy kodek entropijny, który lubi, jak w serii danych ma mało unikalnych symboli, a mechanizm RLE po prostu kocha serie z powtarzającymi się symbolami, szczególnie, gdy są to zera.

Jednak dekoder w docelowym odtwarzaczu musi jeszcze przeprowadzić operację odwrotną, macierz po kwantyzacji pomnożyć przez 5:

Wartości oczywiście nie wróciły do stanu sprzed kwantyzacji, to dość logiczne. Pozostały też te liczne zera, jednak jak pokazał wpis o DCT, nawet zupełne wycięcie współczynników z prawego dolnego rogu macierzy DCT nie powoduje widocznej utraty jakości klatki.

Wniosek jest tutaj taki – im większe wartości współczynników kwantyzacji, tym więcej współczynników odpowiedzialnych za drobne szczegóły zostanie wyciętych. Chcąc zmniejszyć rozmiar klatki po zakodowaniu wystarczy “docisnąć” kwantyzację, czyli zwiększyć współczynniki w tablicy, żeby z kolei zachować więcej szczegółów, trzeba osłabić kwantyzację. Granicznym przypadkiem jest tryb bezstratny, kiedy kwantyzacja nie występuje, lub, inaczej pisząc, tablica kwantyzacji to same jedynki.

2. Kodowanie ze stałą kwantyzacją

Autor filmiku z Wykopu aby uwidocznić stratę jakości podczas śnieżenia i konfetti manipulował bitratem, tzn stopniowo go zmniejszał, aż do momentu, kiedy kodek, musząc zapewnić stały niski bitrate, musiał rozkręcić kwantyzację do tego stopnia, że zanikły niemal wszystki szczegóły wideo, wszystko zaczęło się zlewać i pojawiły się “efekty blokowe”.

My zrobimy trochę odwrotnie, weźmiemy poniższe wideo, w którym początek to bardzo mało dynamiczna sekwencja, z niewieloma szczegółami, a przede wszystkim bez szumienia w stylu śniegu czy konfetti, po niej następuje druga sekwencja ze spienionym morzem, zdecydowanie więcej “szumu”:

https://www.dropbox.com/s/76cr4ip6gdak7d2/amos_crf25a.mp4?dl=0

Wideo pochodzi ze stronki Divx zawierającej próbki wideo, podkład muzyczny zawdzięczamy TheFatRat‘owi.

Mała uwaga, gdy plik jest odtwarzany w playerze Dropboxa jego jakość jest zaskakująco gorsza niż odtwarzając ten sam plik lokalnie.

Teraz zakodujemy te wideo za pomocą tandemu ffmpeg/x264 w trybie CQP, czyli Constant Quantization Paramter. Innymi słowy cały film, od początku do końca, zostanie zakodowany z niezmiennymi parametrami kwantyzacji (ze stałą jakością). Ten tryb nie jest zbyt często wykorzystywany, ponieważ wyjściowy bitrate jest niemożliwy do przewidzenia. A w tym przypadku właśnie o to chodzi, żeby zobaczyć, jak zmienia się bitrate w zależności od tego co się dzieje na ekranie.

A teraz posłużę się niezwykle ciekawym i przydatnym narzędziem plotbitrate do wykreślania bitrate’u plików wideo w funkcji czasu. I otrzymujemy:

graph

Widać, jak dokładnie w połowie filmu, przy przeskoku do sceny bardzo dynamicznej ze spienionym morzem, bitrate wzrasta aż dwunastokrotnie. Innymi słowy, żeby zapewnić jednakową jakość przez cały film, druga część musi być zakodowana ze znacznie większym bitrate’em. Odwracając teraz to zdanie, żeby zakodować cały film ze stałym bitrate’em, jego druga część musi być kodowana w znacznie gorszej jakości, czyli ze znacznie “podkręconą” kwantyzacją.

3. Kodowanie ze stałym bitrate’em

Kodowanie ze stałym bitrate’em określa się skrótem CBR (Const. Bit Rate). Taki sposób kodowania utrzymuje się głównie w systemach live i to tych, dla których kanałem są fale radiowe. Na przykład w telewizji cyfrowej DVB-T, gdzie do dyspozycji pozostaję jedynie kilkadziesiąt megabitów (zależnie od modulacji) w ramach jednego multipleksu, a musi się w nim zmieścić kilka kanałów TV.

Zakodujmy zatem ten sam wyjściowy materiał ze stałym bitratem. Aby zilustrować różnice w jakości ustawiłem bitrate na 256 kbit/s.

Otrzymujemy filmik:

https://www.dropbox.com/s/nvmxhfv6e17s0eh/cbr256k.mp4?dl=0

Wykres bitrate’u jest względnie płaski, nie licząc klatek kluczowych (intra), one *zawsze* mają rozmiary znacznie przewyższające pozostałe typy klatek – P i B.

graph2

Zgodnie z przewidywaniami, druga część filmiku ma koszmarną jakość.

4. Kompensacja ruchu

W osobnym wpisie przedstawiałem mechanizm działania kompensacji ruchu, który pozwala zaoszczędzić masę bitów, wykorzystując informacje z innych klatek wideo. Wiadomo, w wielu sekwencjach części obrazu pozostają niemal niezmienione przez długie sekundy, często jest to tło na którym toczy się jakaś akcja. Dzięki temu kompensacja ruchu jest w stanie odtworzyć np. z poprzedniej klatki większość klatki obecnej, a tę różnicę, która pozostaje po rekonstrukcji, zakodować używając DCT. Śnieg, konfetti, deszcz, piana czy inne szumy kompletnie dezorganizują proces kompensacji ruchu. Wektory ruchu mogą czasem zupełnie nie odpowiadać przemieszczeniom na samym filmie, a poza tym ta różnica między klatką złożoną na podstawie wektorów ruchu a klatką rzeczywistą jest w obecności dodatkowego szumu bardzo duża.

Na koniec przyjrzyjmy się jeszcze wektorom ruchu:

https://www.dropbox.com/s/ea9ejtevqsq18m6/cbr_mv.mp4?dl=0

Można je uzyskać korzystając z pewnych funkcji ffmpega:

 

Podsumowując:

Efekty szumowe w wideo, takie jak śnieżenie, deszcz, wybuchy, konfetti, powodują pojawienie się w wideo wielu drobnych szczegółów. Dodatkowo, z powodu chaotycznego ruchu tych drobinek, przestają być skuteczne algorytmy kompensacji ruchu.
Aby zakodować zaszumioną część filmu w zadowalającej jakości wymagany jest zwiększony bitrate, nawet o rząd wielkości. W przypadku, gdy kodek ustawiony jest w tryb stałego bitrate’u, aby utrzymać stałą przepływność kodek zwiększa współczynniki kwantyzacji, co momentalnie skutkuje pogorszeniem jakości wideo.

 

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *

Możesz użyć następujących tagów oraz atrybutów HTML-a: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">