Redukcja chrominancji (ang. Chroma Subsampling) to jedna z operacji kompresji polegająca na zmniejszeniu informacji na temat koloru w naszym obrazie. Wykorzystujemy tutaj fakt, że ludzkie oko jest bardziej wrażliwe na zmianę jasności (Luminancja), niż koloru (Chrominancja). Subsampling zatem wykonujemy na warstwach Cb oraz Cr (dla każdej z nich osobno). Jego rodzaj opisywany jest przez 3 wartości opisane w ciągu J:a:b jak tak to pokazano na poniższym schemacie.

Schemat naszej wersji algorytmu JPEG — bieżący krok Chroma Subsampling i Chroma Resampling

Pierwszy parametr J określa, jak dużo pikseli w poziomie będziemy analizować, zwykle jest to wartość \(4\). Kolejny parametr a określa, ile wartości z pierwszego analizowanego przez nas wiersza będziemy zapisywać, natomiast parametr b opisuje liczbę wartości w drugim wierszu. Na przykładzie graficznym zapisywane zostają wartości zaznaczone jako czerwone kwadraty. Jak widzimy w przypadku 4:4:4 wszystkie wartości zostają zapisane, więc nic nie ulega zmianie. W pozostałych przypadkach zawsze tracimy jakieś informacje. Działanie funkcji odwrotnej polega na odtworzeniu całej warstwy naszego obrazu na podstawie zapisanych przez nas wcześniej informacji. Jeżeli nie mamy dostępnej informacji o wartości piksela, to zastępujemy (w zależności gidze się on znajduje) inną najbliższą wartością z tego lub poprzedniego wiersza. Przykładowo dla 4:4:0 będziemy uzupełniać drugi wiersz wartościami z pierwszego, dla 4:2:0 jedna wartość będzie propagowana na 4 piksele, dla 4:1:1 nowa wartość będzie zastępowała cały wiersz, a dla 4:1:0 nowa wartość będzie rozchodziła się dla wszystkich 8 pikseli. W ramach tych laboratoriów interesują nas dwie wersje 4:4:4 - czyli obraz bez zmian oraz 4:2:2 - czyli redukcja ilości pikseli o 50% w poziomie (każda wartość będzie odtwarzana za pomocą piksela na lewo od niego). Pamiętajcie, że sposób kompresji chrominancji naszego obrazu powinien również zostać zapisany wewnątrz naszej struktury, żeby dekoder również wiedział, w jaki sposób go odtworzyć. Więcej informacji na temat redukcji chrominancji można przeczytać w artykule na Wikipedii z innymi przykładami graficznymi.

Jak do tego podejść programistycznie?

Po pierwsze nie musimy procesu redukcji chrominancji przeprowadzać na poszczególnych blokach. Możemy na raz przetwarzać całą warstwę, czyli nie potrzebujemy żadnych pętli.

Druga podpowiedź, czyli w jaki sposób zdecydować jaką redukcję robić. Tutaj można spróbować coś automatyzować, ale w waszym przypadku najwygodniej napisać odpowiedni zestaw if, elif, else. Macie dzięki temu lepszą kontrolę nad tym, co działa, a co nie.

if ratio=="4:2:2":
    pass
elif ratio=="4:2:0":
    ## Nie dla labolatoriów z JPEG
    pass
else: #defalut "4:4:4"
    pass

Trzecia podpowiedź, czyli jak przeprowadzić redukcję. Tu sprawa jest prosta, pakiet NumPy daje nam możliwość dowolnego adresowania danych, więc możemy dokonać redukcji poprzez wybranie elementów macierzy, które nas interesują. Przypominam, że adresowanie przebiega w kolejności [wiersze, kolumny, warstwy]. W każdym z adresów możemy podać generator określający, które elementy nas interesują. Adres podajemy w formacie od:do:krok, gdzie od i do możemy pominąć, jeżeli chcemy wektor od początku do końca zakresu, a krok domyślnie jest równy \(1\). Czyli jeżeli chcemy dostać wektor zawierający co 4-tą kolumnę i co drugi wiersz nasze zapytanie powinno wyglądać tak:

B=A[::2,::4]

Trzecia podpowiedź, czyli jak uzupełniać dane przy resamplingu. Tu można albo ręcznie uzupełniać wykorzystując adresowanie, albo wykorzystać ułatwienie w postaci funkcji np.repeat. Tylko należy pamiętać, żeby w przypadku kilku z przypadków trzeba wykonać wpierw powielanie dla wierszy, a następnie dla kolumn.

Przykłady wizualne Załóżmy, że mamy jakąś macierz wejściową:

\[ Q= \begin{bmatrix} 6 & 1 & 5 & 9 & 1 & 2 & 5 & 3 \\ 9 & 7 & 9 & 2 & 5 & 5 & 2 & 4 \\ 6 & 0 & 7 & 7 & 1 & 0 & 8 & 4 \\ 0 & 8 & 2 & 4 & 3 & 6 & 3 & 6 \\ 6 & 6 & 7 & 8 & 9 & 5 & 2 & 3 \\ 9 & 9 & 9 & 9 & 0 & 7 & 6 & 7 \\ 3 & 3 & 6 & 0 & 4 & 9 & 7 & 1 \\ 9 & 0 & 0 & 5 & 5 & 3 & 8 & 5 \\ \end{bmatrix} \]

Podzielmy ją sobie na bloki 2x4 odpowiadające domyślnemu działaniu chroma subsamplingu.

\[ Q= \left[ \begin{array}{cccc|cccc} 6 & 1 & 5 & 9 & 1 & 2 & 5 & 3 \\ 9 & 7 & 9 & 2 & 5 & 5 & 2 & 4 \\ \hline 6 & 0 & 7 & 7 & 1 & 0 & 8 & 4 \\ 0 & 8 & 2 & 4 & 3 & 6 & 3 & 6 \\ \hline 6 & 6 & 7 & 8 & 9 & 5 & 2 & 3 \\ 9 & 9 & 9 & 9 & 0 & 7 & 6 & 7 \\ \hline 3 & 3 & 6 & 0 & 4 & 9 & 7 & 1 \\ 9 & 0 & 0 & 5 & 5 & 3 & 8 & 5 \\ \end{array} \right] \]

Teraz przejdźmy do przykładów dla kilku wybranych rodzajów subsamplingu (\(Q\)- macierz startowa,\(Q_S\) - macierz po subsamplingu, \(Q_r\) macierz po rekonstrukcji ):

  1. 4:4:4 - czyli bez zmiany:

    \[ Q= \left[ \begin{array}{cccc|cccc} 6 & 1 & 5 & 9 & 1 & 2 & 5 & 3 \\ 9 & 7 & 9 & 2 & 5 & 5 & 2 & 4 \\ \hline 6 & 0 & 7 & 7 & 1 & 0 & 8 & 4 \\ 0 & 8 & 2 & 4 & 3 & 6 & 3 & 6 \\ \hline 6 & 6 & 7 & 8 & 9 & 5 & 2 & 3 \\ 9 & 9 & 9 & 9 & 0 & 7 & 6 & 7 \\ \hline 3 & 3 & 6 & 0 & 4 & 9 & 7 & 1 \\ 9 & 0 & 0 & 5 & 5 & 3 & 8 & 5 \\ \end{array} \right] \qquad Q_s= \left[ \begin{array}{cccc|cccc} 6 & 1 & 5 & 9 & 1 & 2 & 5 & 3 \\ 9 & 7 & 9 & 2 & 5 & 5 & 2 & 4 \\ \hline 6 & 0 & 7 & 7 & 1 & 0 & 8 & 4 \\ 0 & 8 & 2 & 4 & 3 & 6 & 3 & 6 \\ \hline 6 & 6 & 7 & 8 & 9 & 5 & 2 & 3 \\ 9 & 9 & 9 & 9 & 0 & 7 & 6 & 7 \\ \hline 3 & 3 & 6 & 0 & 4 & 9 & 7 & 1 \\ 9 & 0 & 0 & 5 & 5 & 3 & 8 & 5 \\ \end{array} \right] \qquad Q_r= \left[ \begin{array}{cccc|cccc} 6 & 1 & 5 & 9 & 1 & 2 & 5 & 3 \\ 9 & 7 & 9 & 2 & 5 & 5 & 2 & 4 \\ \hline 6 & 0 & 7 & 7 & 1 & 0 & 8 & 4 \\ 0 & 8 & 2 & 4 & 3 & 6 & 3 & 6 \\ \hline 6 & 6 & 7 & 8 & 9 & 5 & 2 & 3 \\ 9 & 9 & 9 & 9 & 0 & 7 & 6 & 7 \\ \hline 3 & 3 & 6 & 0 & 4 & 9 & 7 & 1 \\ 9 & 0 & 0 & 5 & 5 & 3 & 8 & 5 \\ \end{array} \right] \]

  2. 4:2:2 - czyli redukujemy co drugą kolumnę:

    \[ Q= \left[ \begin{array}{cccc|cccc} (6) & 1 & (5) & 9 & (1) & 2 & (5) & 3 \\ (9) & 7 & (9) & 2 & (5) & 5 & (2) & 4 \\ \hline (6) & 0 & (7) & 7 & (1) & 0 & (8) & 4 \\ (0) & 8 & (2) & 4 & (3) & 6 & (3) & 6 \\ \hline (6) & 6 & (7) & 8 & (9) & 5 & (2) & 3 \\ (9) & 9 & (9) & 9 & (0) & 7 &( 6) & 7 \\ \hline (3) & 3 & (6) & 0 & (4) & 9 & (7) & 1 \\ (9) & 0 & (0) & 5 & (5) & 3 & (8) & 5 \\ \end{array} \right] \qquad Q_s= \left[ \begin{array}{cc|cc} 6 & 5 & 1 & 5 \\ 9 & 9 & 5 & 2 \\ \hline 6 & 7 & 1 & 8 \\ 0 & 2 & 3 & 3 \\ \hline 6 & 7 & 9 & 2 \\ 9 & 9 & 0 & 6 \\ \hline 3 & 6 & 4 & 7 \\ 9 & 0 & 5 & 8 \\ \end{array} \right] \qquad Q_r= \left[ \begin{array}{cccc|cccc} 6 & 6 & 5 & 5 & 1 & 1 & 5 & 5 \\ 9 & 9 & 9 & 9 & 5 & 5 & 2 & 2 \\ \hline 6 & 6 & 7 & 7 & 1 & 1 & 8 & 8 \\ 0 & 0 & 2 & 2 & 3 & 3 & 3 & 3 \\ \hline 6 & 6 & 7 & 7 & 9 & 9 & 2 & 2 \\ 9 & 9 & 9 & 9 & 0 & 0 & 6 & 6 \\ \hline 3 & 3 & 6 & 6 & 4 & 4 & 7 & 7 \\ 9 & 9 & 0 & 0 & 3 & 3 & 8 & 8 \\ \end{array} \right] \]

  3. 4:4:0 - czyli redukujemy co drugi wiersz:

    \[ Q= \left[ \begin{array}{cccc|cccc} (6) & (1) & (5) & (9) & (1) & (2) & (5) & (3) \\ 9 & 7 & 9 & 2 & 5 & 5 & 2 & 4 \\ \hline (6) & (0) & (7) & (7) & (1) & (0) & (8) & (4) \\ 0 & 8 & 2 & 4 & 3 & 6 & 3 & 6 \\ \hline (6) & (6) & (7) & (8) & (9) & (5) & (2) & (3) \\ 9 & 9 & 9 & 9 & 0 & 7 & 6 & 7 \\ \hline (3) & (3) & (6) & (0) & (4 )& (9) & (7) & (1) \\ 9 & 0 & 0 & 5 & 5 & 3 & 8 & 5 \\ \end{array} \right] \qquad Q_s= \left[ \begin{array}{cccc|cccc} 6 & 1 & 5 & 9 & 1 & 2 & 5 & 3 \\ \hline 6 & 0 & 7 & 7 & 1 & 0 & 8 & 4 \\ \hline 6 & 6 & 7 & 8 & 9 & 5 & 2 & 3 \\ \hline 3 & 3 & 6 & 0 & 4 & 9 & 7 & 1 \\ \end{array} \right] \qquad Q_r= \left[ \begin{array}{cccc|cccc} 6 & 1 & 5 & 9 & 1 & 2 & 5 & 3 \\ 6 & 1 & 5 & 9 & 1 & 2 & 5 & 3 \\ \hline 6 & 0 & 7 & 7 & 1 & 0 & 8 & 4 \\ 6 & 0 & 7 & 7 & 1 & 0 & 8 & 4 \\ \hline 6 & 6 & 7 & 8 & 9 & 5 & 2 & 3 \\ 6 & 6 & 7 & 8 & 9 & 5 & 2 & 3 \\ \hline 3 & 3 & 6 & 0 & 4 & 9 & 7 & 1 \\ 3 & 3 & 6 & 0 & 4 & 9 & 7 & 1 \\ \end{array} \right] \]

  4. 4:2:0 - czyli redukujemy co drugą kolumnę i co drugi wiersz:

    \[ Q= \left[ \begin{array}{cccc|cccc} (6) & 1 & (5) & 9 & (1) & 2 & (5) & 3 \\ 9 & 7 & 9 & 2 & 5 & 5 & ) & 4 \\ \hline (6) & 0 & (7) & 7 & (1) & 0 & (8) & 4 \\ 0 & 8 & 2 & 4 & 3 & 6 & 3 & 6 \\ \hline (6) & 6 & (7) & 8 & (9) & 5 & (2) & 3 \\ 9 & 9 & 9 & 9 & 0 & 7 & 6 & 7 \\ \hline (3) & 3 & (6) & 0 & (4) & 9 & (7) & 1 \\ 9 & 0 & 0 & 5 & 5 & 3 & 8 & 5 \\ \end{array} \right] \qquad Q_s= \left[ \begin{array}{cc|cc} 6 & 5 & 1 & 5 \\ \hline 6 & 7 & 1 & 8 \\ \hline 6 & 7 & 9 & 2 \\ \hline 3 & 6 & 4 & 7 \\ \end{array} \right] \qquad Q_r= \left[ \begin{array}{cccc|cccc} 6 & 6 & 5 & 5 & 1 & 1 & 5 & 5 \\ 6 & 6 & 5 & 5 & 1 & 1 & 5 & 5 \\ \hline 6 & 6 & 7 & 7 & 1 & 1 & 8 & 8 \\ 6 & 6 & 7 & 7 & 1 & 1 & 8 & 8 \\ \hline 6 & 6 & 7 & 7 & 9 & 9 & 2 & 2 \\ 6 & 6 & 7 & 7 & 9 & 9 & 2 & 2 \\ \hline 3 & 3 & 6 & 6 & 4 & 4 & 7 & 7 \\ 3 & 3 & 6 & 6 & 4 & 4 & 7 & 7 \\ \end{array} \right] \]

  5. 4:1:1 - czyli redukujemy wszystkie kolumny poza pierwszą (zostawiamy co 4 kolumnę):

    \[ Q= \left[ \begin{array}{cccc|cccc} (6) & 1 & 5 & 9 & (1) & 2 & 5 & 3 \\ (9) & 7 & 9 & 2 & (5 )& 5 & 2 & 4 \\ \hline (6) & 0 & 7 & 7 & (1) & 0 & 8 & 4 \\ (0) & 8 & 2 & 4 & (3) & 6 & 3 & 6 \\ \hline (6) & 6 & 7 & 8 & (9) & 5 & 2 & 3 \\ (9) & 9 & 9 & 9 & (0) & 7 & 6 & 7 \\ \hline (3) & 3 & 6 & 0 & (4) & 9 & 7 & 1 \\ (9) & 0 & 0 & 5 & (5) & 3 & 8 & 5 \\ \end{array} \right] \qquad Q_s= \left[ \begin{array}{c|c} 6 & 1 \\ 9 & 5 \\ \hline 6 & 1 \\ 0 & 3 \\ \hline 6 & 9 \\ 9 & 0 \\ \hline 3 & 4 \\ 9 & 5 \\ \end{array} \right] \qquad Q_r= \left[ \begin{array}{cccc|cccc} 6 & 6 & 6 & 6 & 1 & 1 & 1 & 1 \\ 9 & 9 & 9 & 9 & 5 & 5 & 5 & 5 \\ \hline 6 & 6 & 6 & 6 & 1 & 1 & 1 & 1 \\ 0 & 0 & 0 & 0 & 3 & 3 & 3 & 3 \\ \hline 6 & 6 & 6 & 6 & 9 & 9 & 9 & 9 \\ 9 & 9 & 9 & 9 & 0 & 0 & 0 & 0 \\ \hline 3 & 3 & 3 & 3 & 4 & 4 & 4 & 4 \\ 9 & 9 & 9 & 9 & 5 & 5 & 5 & 5 \\ \end{array} \right] \]

  6. 4:1:0 - czyli wszystkie wartości poza pierwszą wartością w pierwszym wierszu (pomijamy, co drugi wiesz i zostawiamy co 4-tą kolumnę):

    \[ Q= \left[ \begin{array}{cccc|cccc} (6) & 1 & 5 & 9 & (1) & 2 & 5 & 3 \\ 9 & 7 & 9 & 2 & 5& 5 & 2 & 4 \\ \hline (6) & 0 & 7 & 7 & (1) & 0 & 8 & 4 \\ 0 & 8 & 2 & 4 & 3 & 6 & 3 & 6 \\ \hline (6) & 6 & 7 & 8 & (9) & 5 & 2 & 3 \\ 9 & 9 & 9 & 9 & 0 & 7 & 6 & 7 \\ \hline (3) & 3 & 6 & 0 & (4) & 9 & 7 & 1 \\ 9 & 0 & 0 & 5 & 5 & 3 & 8 & 5 \\ \end{array} \right] \qquad Q_s= \left[ \begin{array}{c|c} 6 & 1 \\ \hline 6 & 1 \\ \hline 6 & 9 \\ \hline 3 & 4 \\ \end{array} \right] \qquad Q_r= \left[ \begin{array}{cccc|cccc} 6 & 6 & 6 & 6 & 1 & 1 & 1 & 1 \\ 6 & 6 & 6 & 6 & 1 & 1 & 1 & 1 \\ \hline 6 & 6 & 6 & 6 & 1 & 1 & 1 & 1 \\ 6 & 6 & 6 & 6 & 1 & 1 & 1 & 1 \\ \hline 6 & 6 & 6 & 6 & 9 & 9 & 9 & 9 \\ 6 & 6 & 6 & 6 & 9 & 9 & 9 & 9 \\ \hline 3 & 3 & 3 & 3 & 4 & 4 & 4 & 4 \\ 3 & 3 & 3 & 3 & 4 & 4 & 4 & 4 \\ \end{array} \right] \]