świstak.codes

O programowaniu, informatyce i matematyce przystępnym językiem

Jak komputer zapisuje kolory?

Poruszając kilka tematów z zakresu grafiki komputerowej, do tej pory skupiałem się na algorytmach i matematyce odpowiedzialnych za rysowanie tego, co widzimy na ekranie. Przy okazji opowiadałem o sprzętowych podstawach działania, ale jeszcze nigdy nie poświęciłem czasu temu, co faktycznie obserwujemy na ekranie, czyli kolorom, barwom. A jest to ciekawy i jak zwykle złożony temat, który postaram się przedstawić w prosty sposób.

Teoria koloru

Zanim przejdziemy do meritum artykułu od strony technicznej, musimy poznać nieco teorii nietechnicznej. Ogólnie rzecz ujmując, dział wiedzy, który poruszymy, to teoria koloru. Jest to nauka interdyscyplinarna, bo znajdziemy tu zagadnienia z fizyki, biologii oraz psychologii. Jednak spokojnie, wszystko to będzie miało jak zawsze przełożenie na informatykę, co zobaczysz w dalszej części artykułu.

Czym jest kolor?

Na początek nieco filozoficznie, bo chciałoby się napisać, że co to jest kolor, widzi prawie każdy. Jednak taka definicja nikogo nie zadowala. Najlepiej można powiedzieć, że kolor to wrażenie psychiczne wywoływane w mózgu po odebraniu przez odpowiedni narząd (oko) promieniowania elektromagnetycznego w pewnym zakresie. W przypadku człowieka jest to zakres ok. 400-700 nanometrów, czyli tzw. światło widzialne. Widzialne dla człowieka, bo wiele zwierząt ma inne zakresy widzenia i generalnie za światło uznaje się fale elektromagnetyczne w zakresie od 100 nanometrów do 1 milimetra. Jednak my, z raczej wiadomych powodów, skupimy się tylko na tej części widzialnej przez człowieka.

Warto też dodać, że kolor to nie tylko wrażenie psychiczne. Jest to także wielkość mierzalna i to będzie nas najbardziej interesować w tym artykule. Barwy możemy zapisywać liczbowo w tak zwanych przestrzeniach barw, a mierzyć np. spektrofotometrem.

Od razu dodam, że w artykule będę na przemian stosować słowa kolor i barwa. Są to synonimy z nieco innym znaczeniem, jednak w kontekście, w jakim my operujemy, oznaczają to samo. Tam, gdzie się je rozróżnia, np. w poligrafii, barwą nazywa się wrażenie wzrokowe, a kolorem cechę materii, np. farby.

Teoria Younga-Helmholtza

Kluczową w teorii kolorów jest teoria Younga-Helmholtza, która wyjaśnia, jak powstają barwne wrażenia wzrokowe, które widzimy. Sformułował ją w 1802 r. T. Young, a rozbudował w 1852 r. H. Helmholtz.

W 1801 r. Young wygłosił, że w siatkówce oka znajdują się trzy rodzaje włókien nerwowych, które reagują na promieniowanie całego widma światła widzialnego. Trzy, ponieważ każde z nich reaguje na różne zakresy długości fal, które odpowiadają barwom podstawowym — czerwonej, żółtej i niebieskiej. Jednocześnie stwierdził, że gdy wszystkie trzy rodzaje włókien są pobudzone tak samo, to widzimy biel, a jeśli w ogóle — czerń; jeśli są pobudzone w różnym stopniu, to widzimy różne barwy.

Helmholtz zmodyfikował założenia Younga, stwierdzając, że powstawanie wrażeń barwnych zawdzięczamy procesom fotochemicznym zachodzącym pod wpływem promieniowania w trzech rodzajach światłoczułych receptorów. Tutaj Helmholtz założył, że trzy kolory podstawowe to czerwony, zielony i fioletowy. Oprócz tego wprowadził takie pojęcia, jak jasność, odcień, nasycenie, i rozróżnił mieszanie barw na subtraktywne i addytywne.

Badana Younga i Helmholtza były kontynuowane jeszcze przez wiele lat, i gdy szczegóły okazały się być nieco inne, sama idea działania widzenia barwnego wciąż pozostaje taka sama. Dziś wiemy, że barwniki wzrokowe znajdujące się w fotoreceptorach na siatkówce oka reagują na barwy: niebieską, zieloną i czerwoną. Za widzenie kolorów odpowiadają czopki, a dodatkowo posiadamy także pręciki umożliwiające widzenie czarno-białe.

Wykres absorpcji światła do długości fali przez czopki i pręciki w ludzkim oku.
Absorpcja światła, a dokładniej zakresów fal świetlnych przez czopki (K, Ś, D) i pręciki (Pr).
(CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=6244086)

Podstawowe pojęcia związane z barwami

Żeby już nie rozwlekać tej części teoretycznej, to w tym krótkim akapicie wypiszę kilka moim zdaniem istotnych terminów, które warto znać w kontekście barw:

  • Jasność koloru — całkowita ilość światła, jaką źródło zdaje się emitować lub odbijać. Co ciekawe, termin ten nie jest jasno sprecyzowany, dlatego Międzynarodowa Komisja Oświetleniowa (CIE) nie uznaje go.
  • Odcień — czysty, nasycony kolor. Technicznie jest zdefiniowany jako stopień, w którym bodziec można opisać jako podobny lub różny od tego, który jest opisany jako czerwony, zielony, niebieski i żółty.
  • Saturacja — inaczej nasycenie. Barwy bardziej nasycone są odbierane jako żywe, natomiast mniej nasycone są przytłumione i zbliżone do szarości.
  • Synteza subtraktywna — zjawisko mieszania kolorów przez odejmowanie. Ten rodzaj syntezy zachodzi przy mieszaniu farb, stąd jest wykorzystywana m.in. w druku.
  • Synteza addytywna — zjawisko mieszania barw przez sumowanie. Ten rodzaj syntezy zachodzi przy mieszaniu światła, stąd jest wykorzystywana m.in. w wyświetlaczach.
  • Kanał alfa — dodatkowa informacja, którą często spotykamy w informatyce przy określaniu barwy. Określa poziom przezroczystości wyświetlanej informacji graficznej. Zerowa wartość oznacza pełną przezroczystość, a maksymalna jej brak.
Synteza w przestrzeni CMY
Synteza subtraktywna.
(Quark67, CC BY-SA 2.5, via Wikimedia Commons)
Synteza w przestrzeni RGB
Synteza addytywna.
(Quark67, CC BY-SA 3.0, via Wikimedia Commons)

Przestrzeń barw

Do tej pory widzenie barw określaliśmy jako zjawisko w dużej mierze psychiczne. Jednak jeśli chcemy coś zapisać na komputerze, trzeba to określić liczbowo. Z pomocą przychodzi nam tu idea przestrzeni barw. Są to matematyczne modele umożliwiające zapisanie barwy. Oczywiście można teraz powiedzieć — przecież to fala elektromagnetyczna, więc moglibyśmy zapisać długość fali. Niestety, nie do końca tak to działa, bo są barwy, których nie określimy długością fali (np. biała, czarna, różowa). Lukę tę łatają przestrzenie barw w taki sposób, że bardziej są związane z ludzką percepcją barwy.

W tej części artykułu zapoznamy się z modelami przestrzeni barw, stawiając nacisk na te, które najczęściej spotykamy w informatyce. I to takie, na które trafimy przy przeróżnych aspektach pracy z grafiką komputerową.

RGB / RGBA / sRGB

Podstawowym modelem przestrzeni barw w informatyce jest model RGB. Jego nazwa wywodzi się od nazw trzech kolorów podstawowych — czerwonego

(red), zielonego
(green) i niebieskiego
(blue). Jest to model addytywny, w którym, jak można domyślić się z nazwy, określamy, jak mieszać ze sobą te trzy barwy w celu uzyskania pożądanego koloru. Obecnie model ten często rozszerza się do RGBA, gdzie A to kanał alfa (przezroczystość).

Jeżeli założymy, że poszczególne kolory przyjmują wartości od 0% do 100%, to przykładowe barwy w tym modelu wyglądałyby następująco:

  • czarny
    : R 0%, G 0%, B 0%
  • biały
    : R 100%, G 100%, B 100%
  • zielony
    : R 0%, G 100%, B 0%
  • żółty
    : R 100%, G 100%, B 0%

W informatyce zazwyczaj spotykamy się z zakresem wartości 0-255 dla każdej ze składowych barw (zapis 24-bitowy), stąd w modelu tym możemy przedstawić maksymalnie 2563=16777216256^3 = 16777216 barw.

RGB jest modelem teoretycznym i każde urządzenie może nieco inaczej odwzorowywać zapisane w nim barwy. Z tego powodu powstał standard sRGB, początkowo opracowany przez HP i Microsoft, a obecnie jest nadzorowany przez Międzynarodową Komisję Elektrotechniczną (IEC) jako standard IEC 61966-2-1.

Diagram chromatyczności z zaznaczonym zakresem sRGB
Diagram chromatyczności przedstawiający zakres barw modelu sRGB. Szary obszar reprezentuje światło widziane przez człowieka (przy brzegu na niebiesko zostały opisane długości fal elektromagnetycznych). Punkt na środku (D65) to barwa biała.
(By PolBr - Own work, CC BY-SA 4.0, https://commons.wikimedia.org/w/index.php?curid=98545086)

CMYK

CMYK to model przestrzeni barw wykorzystywany w poligrafii i wszędzie tam, gdzie mamy do czynienia z mieszaniem farb, czyli jest modelem reprezentującym syntezę subtraktywną. Jednak podobnie do RGB jego nazwa wywodzi się od użytych kolorów:

  • C — cyjan
    . W RGB uzyskamy jako połączenie kolorów zielonego i niebieskiego.
  • M — magenta
    . Jest to połączenie kolorów czerwonego i niebieskiego.
  • Y — żółty (od ang. yellow)
    . Jest to połączenie czerwonego i zielonego.
  • K — czarny
    . Litera K oznacza ostatnią literę w angielskiej nazwie black, ewentualnie key color (kolor kluczowy).

Teoretycznie kolor czarny powinno się dać uzyskać przez połączenie C, M i Y, jednak w praktyce otrzymuje się głęboki, ciemny brąz. Do tego dochodzi argument oszczędności farb (czarny jest najczęściej stosowanym np. do druku tekstu), stąd dołożono dodatkowo czarną farbę.

CMYK nie jest modelem idealnym. Mimo że teoretycznie moglibyśmy otrzymać tak każdą barwę, to jednak w praktyce nie da się uzyskać idealnie czystych farb odpowiadających kolorom składowym. Z tego powodu dla uzyskania lepszych barw czasami dodaje się także inne barwniki niż czarny, bądź też miesza się kolory na mniej oczywiste sposoby. Przykładowo, niebieski uzyskany z połączenia barw C 100% i M 100% jest bardziej zbliżony do fioletowego, stąd zwykle odejmuje się nieco składowych C i M oraz dodaje trochę czerni. Warto o tym wiedzieć, ponieważ komputerowe reprezentacje często przeliczają kolory w najprostszy możliwy sposób.

YUV / YCbCr

Ten model przestrzeni barw ma zupełnie inną historię niż powyższe. RGB to przełożenie syntezy addytywnej wprost na liczby, a CMYK syntezy subtraktywnej. Natomiast pochodzenie tej grupy modeli odnajdziemy w telewizji. Jak wiadomo, oryginalnie telewizja była czarnobiała, i nie wdając się w szczegóły, modulacja amplitudy fali elektrycznej wyznaczała jasność punktu na ekranie. Gdy opracowano sposób na rejestrację obrazu kolorowego, chciano przesyłać go tak, aby czarnobiałe odbiorniki wciąż mogły odbierać sygnał. Wymyślono wówczas, żeby do przesyłanego już kanału jasności (Y) wysyłać dwa dodatkowe kanały kodujące barwę (chrominancję).

W europejskim standardzie PAL dodatkowe kanały nazwano U oraz V, gdzie U to przeskalowana różnica między barwą niebieską a jasnością; V to analogiczna różnica między czerwonym a jasnością. Analogiczne systemy powstały dla standardu NTSC używanego w USA (YIQ) oraz francuskiego SECAM (YDbDr). W późniejszych latach opracowano jeszcze popularny we wczesnych zastosowaniach HD YPbPr (w component video) oraz jego współczesny cyfrowy odpowiednik YCbCr. Z powodu zaniku telewizji analogowej dziś często pod nazwą YUV ukrywa się tak naprawdę YCbCr.

Poniżej możesz zobaczyć, jak wygląda obraz wraz z jego składowymi w różnych odmianach tego modelu przestrzeni barw:

Składowe obrazu w YUV
YUV
(źródło)
Składowe obrazu w YIQ
YIQ
(CC BY 2.5, źródło)
Składowe obrazu w YDbDr
YDbDr
(CC BY 2.5, źródło)
Składowe obrazu w YCbCr
YCbCr
(źródło)

W przypadku YPbPr i YCbCr składowe modelu możemy wyznaczyć następująco z modelu RGB:

Y=KrR+(1KrKb)R+KbBPb=12(1Kb)(BY)Pr=12(1Kr)(RY),gdzie:R,G,B[0;1]Y[0;1]Pb,Pr[0,5;0,5]Y = Kr\cdot R + (1-Kr-Kb)\cdot R + Kb \cdot B \\ Pb = \frac{1}{2 \cdot (1 - Kb)} \cdot (B - Y) \\ Pr = \frac{1}{2 \cdot (1 - Kr)} \cdot (R - Y) \text{,} \\ \text{gdzie:} \\ R,G,B \in [0; 1] \\ Y \in [0; 1] \\ Pb, Pr \in [-0,5; 0,5]

Wartości współczynników Kr i Kb zależą od konkretnego standardu. W przypadku standardu ITU-R BT.709 (HDTV) wynoszą:

Kb=0,0722Kr=0,2126Kb = 0,0722 \\ Kr = 0,2126

Ten model przestrzeni barw jest nie tylko stosowany w telewizji, ale jest to też jeden ze sposobów transmisji obrazu po kablach HDMI. Jednak nas z perspektywy algorytmicznej powinien ciekawić najbardziej dlatego, że jest wykorzystywany w algorytmach kompresji stratnej obrazów i wideo, takich jak JPEG czy MPEG. Dlaczego? Otóż ludzki wzrok lepiej rozróżnia poziomy jasności od konkretnych barw. Stąd można nie określać składowych Cb i Cr dla każdego z pikseli, a jedynie co kilka i używać wcześniejszych wartości, tym samym oszczędzając zajęte miejsce.

HSL / HSV

O ile powyższe modele są standardem w swoich zastosowaniach, to mają jedną poważną wadę — nie są intuicyjne dla człowieka. Patrząc na barwę, nie jesteśmy w stanie określić, w jakim stopniu składa się z każdego z kolorów podstawowych. Przykładowo zrobienie czegoś takiego jak „trochę mniej nasycony czerwony” nie jest w żadnym stopniu intuicyjne w modelu RGB. Problem ten rozwiązują modele takie jak HSL i HSV (znany też jako HSB), które operują na wartościach bardziej intuicyjnych dla ludzi.

Modele te reprezentowane są graficznie jako stożek bądź walec. Składają się z następujących wartości reprezentujących współrzędne punktu na jednej z tych brył:

  • H (hue), czyli odcień światła. Wyrażany jest kątem na kole reprezentującym koło barw.
  • S (saturation), czyli nasycenie. Jest to promień podstawy bryły wyrażany w procentach.
  • W zależności od modelu mamy V (Value), czyli wartość (alternatywnie B od brightness, czyli jasność), albo L (Lightness) będące średnią ilością światła białego. Również są wyrażane w procentach i stanowią wysokość bryły.

Poniższe rysunki najlepiej przedstawiają różnicę między tymi dwoma modelami:

Reprezentacja modelu HSL
Cylindryczna reprezentacja modelu HSL.
(By HSL_color_solid_cylinder.png: SharkDderivative work: SharkD Talk - HSL_color_solid_cylinder.png, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=9801661)
Reprezentacja modelu HSV
Cylindryczna reprezentacja modelu HSV.
(By HSV_color_solid_cylinder.png: SharkDderivative work: SharkD Talk - HSV_color_solid_cylinder.png, CC BY-SA 3.0, https://commons.wikimedia.org/w/index.php?curid=9801673)

Inne modele przestrzeni barw

Pokazane wyżej modele wybrałem jako te najbardziej znane. Warto jednak wiedzieć, że istnieje ich o wiele więcej. Jeśli ten temat Cię interesuje, warto zapoznać się z modelami opracowanymi przez Międzynarodową Komisję Oświetleniową (CIE), takimi jak CIEXYZ, CIELAB i CIELUV. Są to modele pokrywające całe spektrum światła widzialnego, a tym samym umożliwiają odwzorowanie dowolnej barwy.

Diagram chromatyczności CIE1931
Diagram chromatyczności modelu CIE z 1931 r. Modele CIE są trójwymiarowe, tutaj jednak widzimy tylko dwa wymiary dla uproszczenia schematu. Pokazane kolory są lekko zakłamane. Wyświetlacze w standardzie sRGB (większość dostępnych) nie są w stanie odwzorować wszystkich dostępnych barw. Wcześniej w artykule pokazałem, jaki wycinek tego diagramu reprezentuje sRGB.
(źródło: By BenRG - File:CIExy1931.svg, Public Domain, https://commons.wikimedia.org/w/index.php?curid=7889658)

Dobrym przykładem zastosowania tych systemów jest ustawa z dnia 31 stycznia 1980 r. o godle, barwach i hymnie. Była to pierwsza próba standaryzacji naszych symboli państwowych, w tym kolorów. Do tej pory kolory flagi były określane słownie, a wraz z tą ustawą otrzymaliśmy konkretne wartości z przestrzeni barw CIELUV, które następnie można przeliczać na inne systemy, jak RGB (do wyświetlania) czy CMYK (do druku):

  • biały — x=0,314;y=0,320;Y=82;ΔE=4x = 0,314; y = 0,320; Y = 82; \Delta E = 4 (czyli w sRGB mniej więcej #E9E8E7
    ; obliczenie za polską Wikipedią)
  • czerwony — x=0,57;y=0,305;Y=16;ΔE=8x = 0,57; y = 0,305; Y = 16; \Delta E = 8 (czyli w sRGB mniej więcej #D4213D
    )

Oprócz tego mamy też standardy nazywania kolorów, jak Międzynarodowy Indeks Barw (CI) czy Pantone Matching System. Nie sposób omówić i pokazać je wszystkie, zachowując przy tym zwięzłość i merytorykę tekstu.

Sposób zapisu barw

Omówiliśmy teorię, teraz czas przełożyć ją na praktykę. Zobaczmy, jak to wszystko, co widzieliśmy wyżej, wykorzystuje się do przechowywania informacji o barwach.

Zacznijmy jednak od tego, że barwy można przechowywać na wiele sposobów:

  • Stosować palety dostępnych barw z identyfikatorami kolorów, do których się następnie odnosimy.
  • Zapisywać wprost wartości liczbowe z modelu przestrzeni barw.
  • Zapisywać wartości z modelu przestrzeni barw w postaci złączonej w jedną dużą liczbę.

Niezależnie od sposobu zapisu, jest on ograniczony rozmiarem bądź zakresem liczb, co wpływa na dostępną liczbę kolorów. Ogólna zasada jest taka, że im większy rozmiar zmiennych, tym większa rozdzielczość tonalna (czyli liczba możliwych do uzyskania kolorów).

Palety barw

Pierwszy najstarszy, ale wciąż używany sposób to wykorzystanie palet barw. Sposób ten wywodzi się stąd, że pierwsze karty graficzne wyświetlały bardzo ograniczony zakres kolorów. W przypadku palet możemy wyróżnić dwa podstawowe rodzaje działania: indeksowany kolor (narzucone z góry barwy) i konfigurowalne palety (CLUT, z ang. color lookup table).

Palety były szczególnie popularne w pierwszych latach komputerów. Możemy tutaj wyróżnić takie wczesne standardy (dla komputerów PC), jak:

  • MDA (Monochrome Display Adapter) wspierający tylko dwie barwy — czarną (brak koloru) i jasną (zależnie od monitora: biała, szara, zielona). Oryginalne MDA nie wspierały wyświetlania grafiki, tylko tekst, jednak w 1982 r. powstała karta Hercules, zgodna z MDA, jednak oferująca też tryb graficzny (czarno-biały, 720 × 348 pikseli). W przypadku systemu Hercules każdy piksel był opisany jednym bitem opisującym kolor.
  • CGA (Color Graphics Adapter) — standard opracowany przez IBM w 1981 r. W trybie tekstowym obsługiwał 16 kolorów (4 bity), natomiast w trybie graficznym cztery kolory. W przypadku trybu graficznego dostępne były trzy palety, każda w dwóch odmianach jasności: czerwono-zielono-brązowa, cyan-magenta, cyan-czerwony. Rozszerzeniem tego standardu było Tandy, które oferowało te same 16 barw zarówno w trybie tekstowym, jak i graficznym.
  • EGA (Enhanced Graphics Adapter) to standard na swój sposób rewolucyjny. Obsługujące go karty graficzne posiadały dużą jak na swoje czasy pamięć RAM (64 kB, późniejsze 256 kB) pozwalającą trzymać w pamięci kilka klatek obrazu jednocześnie, zwiększając jego płynność. My jednak nie o tym. Oferowała wyświetlanie jednocześnie do 16 kolorów, jednak można było skonfigurować paletę na własną rękę z dostępnych 64 barw. Można ją było definiować, stosując model RGB składający się z dwóch bitów na kolor czerwony, dwóch na zielony i dwóch na niebieski.
  • VGA (Video Graphics Array) — w tym standardzie można było zdefiniować paletę 256 kolorową, czyli 8-bitową. Co ciekawe, tutaj też można było ręcznie definiować barwy palety: również w modelu RGB po 6 bitów na kolor, czyli dostępne było de facto ponad 260 tysięcy kolorów.

Poniżej możesz zobaczyć porównanie grafiki w grze Grand Prix Circuit (z 1988 r.). Z lewej widzimy grę uruchomioną w trybie CGA (4 kolory, paleta cyan-magenta), a z prawej w trybie EGA (16 kolorów). Jak widać, już 16 kolorów wystarczało, aby uzyskać przyjemnie wyglądającą grafikę.

Zrzut ekranu z gry Grand Prix Circuit w wersji CGA
CGA
Zrzut ekranu z gry Grand Prix Circuit w wersji EGA
EGA

Standardy te są dość wiekowe (ostatnie z nich, VGA, to rok 1987). Jednak, co ciekawe, palety wciąż są w użyciu. Świetnym tego przykładem jest popularny format GIF, w którym obraz jest dzielony na bloki, gdzie każdy blok korzysta z 256 kolorowej palety.

Innym dzisiejszym użyciem odgórnie ustalonej palety są kolory w CSS. Oczywiście można korzystać tam z dowolnych barw, ale mamy też 140 zdefiniowanych z nazwy, jak black, blue, green itd.

Głębia koloru

Mimo że, jak pisałem na końcu, palety wciąż mają swoje zastosowania, to jednak najczęściej barwy zapisuje się w postaci liczbowej, odnosząc się do konkretnego modelu przestrzeni barw; najczęściej do RGB (lub RGBA). Jednak muszą istnieć pewne ograniczenia, a dokładniej — jakim zakresem liczb możemy zapisać wielkości liczbowe w modelu. Nazywamy to głębią koloru, którą wyraża się w liczbie bitów na piksel albo bitów na pojedynczy kanał koloru. O ten temat zahaczyłem lekko przy okazji omawiania plików BMP, gdzie zachęcam zajrzeć później.

Najczęściej spotykamy się z następującymi głębiami kolorów:

  • 16 bitów na piksel (high color) — zwykle jest to 5 bitów na kanały czerwony i niebieski, 6 bitów na zielony. Daje to 216=655362^{16} = 65536 kolorów. Format ten był stosowany dawniej, gdy karty graficzne jeszcze nie obsługiwały 24-bitowego koloru, ale mimo to wciąż jest w użyciu tam, gdzie nie potrzeba wiernego odwzorowania barw, a trzeba przyspieszyć operacje na obrazach — np. w szczególnych przypadkach przy renderowaniu grafiki trójwymiarowej.
  • 24 bity na piksel (true color) — trzy kanały po 8 bitów każdy. Jest to zdecydowanie najpopularniejszy dziś model zapisu plików graficznych bez przezroczystości. 24-bitowe przechowywanie kolorów kojarzy się zwykle z przestrzenią barw RGB, jednak w przypadku filmów DVD czy Blu-ray są one zapisane w przestrzeni YCbCr. Zapewnia 224=167772162^{24} = 16777216 kolorów.
  • 32 bity na piksel — cztery kanały po 8 bitów każdy. Jest to model analogiczny do powyższego z tą różnicą, że obsługuje przezroczystość (czwarty kanał to kanał alfa). Jest też bardziej naturalny do obsługi w językach programowania, ponieważ typy całkowitoliczbowe mają wielkości wyznaczane przez kolejne potęgi liczby 2 (8, 16, 32, 64).
  • 30 bitów na piksel (deep color) — trzy kanały po 10 bitów. Standard ten jest wykorzystywany w UHDTV (4K), a także w standardzie HDR10 (Ultra HD Blu-Ray, konsole do gier z generacji Playstation 4/Xbox One). Znajdziemy także jego 40-bitową odmianę zawierającą kanał alfa. Mamy tutaj do czynienia z 230=10737418242^{30} = 1073741824 kolorami.

Problem zbyt niskiej rozdzielczości tonalnej

24 bity są uważane za głębię całkowicie wystarczającą do codziennych zastosowań. Kolorów jest na tyle dużo, że ludzkie oko nie jest w stanie tak łatwo wychwycić braków w kolorach w większości przypadków. Braki te są jednak szczególnie widoczne przy mniejszych głębiach. Mamy wówczas do czynienia z tzw. bandingiem (pasmowaniem). Objawia się tym, że przy przejściach między odcieniami widzimy pasy kolorów.

Gradient w 24 bitowej głębi kolorów
24bpp
Gradient w 16 bitowej głębi kolorów
16bpp
Gradient w 8 bitowej głębi kolorów
8bpp
Gradient w 4 bitowej głębi kolorów
4bpp
Gradient w 2 bitowej głębi kolorów
2bpp
Gradient w 1 bitowej głębi kolorów
1bpp

Najprostszym sposobem zapobiegania bandingowi jest oczywiście zwiększenie głębi kolorów, jednak nie zawsze jest to możliwe. Alternatywnym, nieperfekcyjnym sposobem, ale dającym zadowalające rezultaty, jest dithering. Jest to technika polegająca na stawianiu naprzemiennie pikseli o różnych barwach, dzięki czemu uzyskujemy wrażenie uzyskania dodatkowych barw. Szczególnie dobrze wygląda to przy dużych rozdzielczościach, gdzie piksele są na tyle małe, że nie widać przejść na pierwszy rzut oka. Przykład użycia ditheringu mogliśmy zobaczyć nieco wcześniej w tym artykule, kiedy pokazałem zrzuty ekranu z gry Grand Prix Circuit.

Gradient w 8 bitowej głębi kolorów z ditheringiem
8bpp
Gradient w 4 bitowej głębi kolorów z ditheringiem
4bpp
Gradient w 2 bitowej głębi kolorów z ditheringiem
2bpp
Gradient w 1 bitowej głębi kolorów z ditheringiem
1bpp

Widzimy tutaj ten sam gradient co wcześniej, jednak przy zmniejszaniu głębii kolorów zastosowano dithering (algorytm Floyda-Steinberga).

Zapis w plikach

Jeśli już dowiedzieliśmy się wszystkiego na temat zapisu barw, warto byłoby zobaczyć, jak faktycznie one trafiają do plików opisujących grafikę.

Zacznijmy od najprostszych formatów plików, czyli takich, które są opisane tekstowo. Jako przykład możemy wyróżnić grafikę wektorową w formacie SVG, gdzie styl figur opisuje się CSS-em (czyli tym samym językiem co wygląd stron internetowych). Mamy do dyspozycji następujące sposoby opisania kolorów:

  • Pojedyncza liczba reprezentująca kolor w przestrzeni RGB, zapisana systemem szesnastkowym, poprzedzona #. Może być zapisana 24-bitowo w formacie #RRGGBB, 32-bitowo #RRGGBBAA albo 12-bitowo #RGB. Barwa czerwona może zostać zapisana następująco:
    • #FF0000
    • #FF000000
    • #F00
  • Nazwa koloru z predefiniowanej palety. Kolor czerwony w tym zapisie to po prostu red.
  • Wykorzystanie notacji funkcyjnej odnoszącej się do wybranej przestrzeni barw. W przypadku SVG (tym samym też CSS) dostępne są:
    • rgb() i rgba(); kolor czerwony to wówczas rgb(1, 0, 0) albo rgb(100%, 0%, 0%). Uzyskane kolory są w przestrzeni sRGB.
    • hsl() i hsla(); kolor czerwony to wówczas hsl(0, 100%, 50%). Uzyskane kolory są w przestrzeni sRGB.
    • Kolory zapisane w przestrzeniach barw LCH (lch()), CIELAB (lab()) lub dowolnej innej (color()). Można za ich pomocą uzyskać dowolny widzialny kolor. Niestety, na obecną chwilę wspiera to jedynie przeglądarka Safari.

Jednak większość formatów graficznych jest binarna. Wówczas nie możemy tekstowo zapisać koloru. Zamiast tego poszczególne składowe przestrzeni barw zapisujemy wprost liczbowo. Aby jednak dane te poprawnie odczytać, musimy wiedzieć następujące rzeczy:

  • Jaka jest głębia kolorów? Definiuje nam ona, ile bitów zajmuje informacja o kolorze, więc wiemy, ile bitów musimy odczytać. Z perspektywy programisty najwygodniejsza jest głębia 24-bitowa, ponieważ każdy z kanałów barw zajmuje dokładnie 1 bajt (8 bitów), czyli tyle, ile odczytujemy na raz z pamięci komputera.
  • Jaka jest przestrzeń barw? Najczęściej mamy do czynienia z RGB, ale format może korzystać z palety (GIF) albo YCbCr (niektóre JPG). Formaty mogą też wspierać zupełnie inne modele przestrzeni barw, szczególnie te wykorzystywane w profesjonalnych zastosowaniach.
  • Jaka jest końcówkowość w formacie pliku? W przypadku plików binarnych liczby możemy czytać od lewej do prawej (big endian) lub na odwrót (little endian). Przykładowo, format BMP zapisuje barwy w postaci little endian, stąd są one de facto zapisane jako BBGGRR.

Dochodzi też kwestia kompresji plików, jednak jest ona zupełnie odrębnym tematem. Jeśli chcesz zobaczyć, jak zapis wygląda w praktyce w przypadku plików BMP, to ponownie zapraszam do mojego starszego artykułu „Przetwarzanie plików w praktyce — obrazy BMP”.

Literatura

(zdjęcie na okładce: lienyuan lee, CC BY 3.0, via Wikimedia Commons)