Grafika komputerowa przyzwyczaiła nas w pewnym sensie do tego, że każdy element obrazu – piksel – przedstawiony jest jako trójka składowych R-G-B, czyli czerwony-zielony-niebieski. Jest to o tyle oczywiste, że z tych trzech kolorów w drodze addytywnego mieszania można stworzyć całą przestrzeń kolorów. Jednak w cyfrowym wideo w ogóle nie znalazło się miejsce dla RGB. Ba, już w standardzie JPEG, przeznaczonym dla zdjęć, zamiast RGB pojawiają się inne literki – YUV. Przestrzenie barw to temat na osobny, obszerny wpis, tutaj skoncentruję się na YUV a w szczególności na pewnej powszechnej i nieodzownej praktyce stosowanej w kodowaniu wideo, określanej jako podpróbkowanie chrominancji (chroma subsampling).
Trochę historii
Telewizja analogowa w swoich początkach i przez długi czas była telewizją czarno białą. Czerń i biel – czyli dwie skrajne wartości jasności, inaczej luminancji, a pomiędzy nimi cały zakres tzw. szarości. Tym widzowie musieli się zadowalać przez lata. Podczas transmisji wystawnej ceremonii koronacji Elżbiety II w czarno białej telewizji widzowie musieli nieco wysilić wyobraźnię polegając na relacji komentatorów.
Lecz wkrótce opracowano standardy telewizji kolorowej. Na analogowy sygnał luminancji nałożono wysokoczęstotliwościowy sygnał niosący informację o barwie i nasyceniu i tak powstała telewizja kolorowa. Ponieważ forma sygnału luminancji nie zmieniła się – nadal był to sygnał analogowy, linia po linii, gdzie wyższa wartość oznaczała plamkę jaśniejszą a niższa ciemniejszą – stare odbiorniki czarno białe mogły w dalszym ciągu odbierać telewizję bez zniekształceń.
Z kolei komputery, ich karty graficzne i wyświetlacze, od CRT do LCD, przyzwyczaiły nas do zapisu obrazów w przestrzeni RGB, dość naturalnej i bezpośrednio zrozumiałej, wszak każdą barwę na ekranie możemy przedstawić jako sumę trzech źródeł światła – czerwonego, zielonego i niebieskiego.
YUV
W telewizji cyfrowej mamy z kolei do czynienia z przestrzenią YUV. Y jest skłądową luminancji, odpowiadającą jasności, czyli obrazowi „czarno białemu”, a U i V to składowe chrominancji, które wspólnie decydują o barwie i nasyceniu piksela. Dość trudno jest zobrazować U i V, w przeciwieństwie do RGB. Wikipedia ukazuje rozkład na YUV w sposób następujący:
Jak widać Y odpowiada obrazowi w skali szarości (czarno białemu) a U i V barwom i nasyceniu.
W przypadku cyfrowego wideo naukowcy i inżynierowie poszli trochę dalej. Otóż ludzkie oko, mimo że widzi i rozróżnia kolory, nie jest zbyt czułe na niewielkie zmiany barw. I tu nie chodzi o legendarny spór czy kobiety lepiej rozróżniają kolory od mężczyzn – bardziej chodzi o biologię i konstrukcję oka. Pręcików, odpowiadających za rejestrację jasności mamy aż 20 razy więcej niż czułych na barwę czopków. A to pręciki powodują, że widzimy wyraźnie kontury, że jesteśmy w stanie zarejestrować nawet drobny ruch.
Idąc tym tropem inżynierowie już w standardzie JPEG wprowadzili podpróbkowanie chrominancji w stosunku 4:2:0. Co to znaczy? Że jeśli obrazek ma 100×100 pikseli, to próbek Y (luminancji) będzie 10000, lecz chrominancji U i V będzie odpowiednio tylko po 2500 U i 2500 V. Oko nie jest w stanie uchwycić, że w obrazie YUV 4:2:0 jest znacznie mniej informacji o barwie niż w obrazie oryginalnym.
O co w takim razie chodziło specom z JPEG i MPEG, że okradli nas z ładnych kilku bajtów obrazu ot tak? Chodzi przede wszystkim o oszczędność. Dzięki podpróbkowaniu, w przypadku schematu 4:2:0, rozmiar niezakodowanego obrazu spadł aż o połowę. Przez to możemy mówić o sporej stratności jeszcze przed etapem właściwej kompresji.
4:2:0, 4:1:1, 4:2:2 ?
Sposób próbkowania chrominancji oznacza się trzema liczbami 4:J:K . Pierwszą zawsze jest 4, bo oznacza liczbę próbek luminancji, do której odnosi się ten stosunek. Najłatwiej czytać tę czwórkę jako rząd 4 pikseli w poziomie. Na takie rzędy dzielimy cały obraz.
J jest liczbą próbek chrominancji w pierwszym polu (field) obrazu – termin pole wywodzi się z określania w ten sposób półobrazu w telewizji z przeplotem. Innymi słowy J mówi ile próbek każdej ze składowych chrominancji przypada na rząd próbek luminancji w nieparzystej linii. Trzecia liczba – K – mówi o tym ile dodatkowych próbek chrominancji w drugim polu przypada rząd próbek luminancji w linii parzystej. To niestety bezwzględnie wymaga ilustracji:
Stosunek 4:J:K wyznacza się w oparciu o prostokąt z próbkami luminancji od Y11 do Y24. Stąd można się już domyśleć, że obrazek bez podpróbkowania chrominancji będzie miał stosunek 4:4:4 . Na 4 próbki Y w pierwszym wierszu przypadać będzie po 4 próbki (czyli w sumie 8) chrominancji U i V, tak samo na 4 próbki w drugim wierszu przypadną po 4 kolejne próbki chrominancji.
4:4:4
Każda próbka luminancji ma odpowiadające sobie 2 próbki chrominancji U i V. Podpróbkowania tutaj nie ma. Weźmy zatem najpopularniejszy chyba schemat próbkowania – 4:2:0
4:2:0
Dla czterech próbek chrominancji z pierwszego wiersza mamy tylko po dwie próbki chrominancji. Trzecią cyfrą jest 0, co znaczy, że w drugim wierszu nie będzie dodatkowych próbek chrominancji, czyli że będą te, przypadające na wiersz pierwszy. Czyli na jeden kwadrat 2×2 pikseli przypada oddzielna para próbek chrominancji. Jest to już dość znaczne podpróbkowanie, aczkolwiek jak wspomniałem wyżej, bardzo częste.
4:1:1
W pierwszym wierszu tylko jedna para (U,V), w drugim dodatkowa pojedyncza para (U,V), w sumie ilość próbek będzie identyczna jak w próbkowaniu 4:2:0 . Ten schemat jest rzadko spotykany w cyfrowym wideo.
4:2:2
W przypadku 4:2:2 mamy dwie pary (U,V) na cztery Y w pierwszym rzędzie, oraz dodatkowe dwie pary w drugim rzędzie. Ten format jest spotykany czasami na przykład w wysokiej jakości materiałach kodowanych h264, który przewiduje zarówno próbkowanie 4:2:2 jak i 4:4:4. Czasami przy tym ostatnim schemacie używa się (moim zdaniem niepoprawnie) terminu „lossless”, co jednak tyczy się jedynie próbkowania a nie samej kompresji.
Można sobie spróbować wyobrazić pozostałe permutacje zapisu 4:J:K ale nie mają one większego sensu. Podobnie jak wspominany w Wikipedii schemat 3:1:1.
Zniekształcenia
W przypadku typowych filmów czy zdjęć JPEG nie da się w zasadzie zauważyć wpływu podpróbkowania chrominancji. Być może w przypadku kreskówki w rozdzielczości PAL, wysilając oczy i korzystając ze stopklatki dałoby się złowić gołym okiem jakieś zniekształcenia przy np. próbkowaniu 4:2:0. Dlatego przygotowałem specjalny materiał pokazujący jak podpróbkowanie może uwidocznić się na tyle, aby można było zaobserwować jego skutki.
W tym celu mam taki oto obrazek w rozmiarze 720×576:
Rozmiary prostokątów nie są równe. Krawędzie prostokątów spotykają się prawie w połowie szerokości i wysokości. Prawie, czyli w połowie minus jeden piksel. Chodzi o to, żeby w miejscu połączenia kodek był zmuszony uśrednić chrominancje sąsiadujących prostokątów przy próbkowaniu 4:2:0.
Teraz skorzystam z ffmpega, chociaż w zasadzie tym razem jest to avconv, czyli (nie do końca) niezależny fork ffmpega. Zamierzam zakodować przy pomocy x264 powyższy obrazek z próbkowaniem YUV 4:2:0
$ avconv -loop 1 -i chroma.png -c:v libx264 -tune stillimage -pix_fmt yuv420p -t 15 chroma.mp4
Oto co z tego wyszło:
https://dl.dropboxusercontent.com/u/24943126/chroma.mp4
Teraz w drugą stronę, czyli wybieramy pojedynczą zakodowaną ramkę i zapisujemy jako png
$ avconv -i chroma.mp4 -vframes 1 chroma420.png
Która prezentuje się tak:
Ciężko tu może coś wychwycić, więc pozwolę sobie na zbliżenie:
Tak objawiło się uśrednienie chrominancji na styku pól o różnych kolorach. W zasadzie jest to mało zauważalne zniekształcenie, co idealnie tłumaczy dlaczego tęgie głowy z JPEG i MPEG zdecydowały się na taki trik.
W poprzednich wpisach wspominałem, że w zasadzie cała stratna kompresja obrazu i wideo opiera się na niedoskonałościach naszej percepcji. Do tego można śmiało dołączyć operację podpróbkowania chrominancji, jest to kolejny magiczny trik, który pozwala zaoszczędzić pasmo i miejsce na nośniku bez widocznej utraty jakości wideo.