Půltónování a chybová difůze Třetí fáze při redukci počtu barev mají na starosti algoritmy, které obdrží Truecolor bitmapu a paletu, přičemž na výstupu je bitmapa v indexovaném barevném formátu. Úkolem je přiřadit každému pixelu index palety tak, aby výsledný optický dojem byl co nejlepší.
Nejbližší soused Nejjednodušší způsob, jak „natáhnout“ paletu na vstupní bitmapu, je prostě každému pixelu přiřadit tu nejpodobnější barvu, jaká je v paletě obsažena. Konečný výstupní obrázek má potom skutečně minimální odchylku od původního. Metoda nejbližšího souseda má u konverze do monochromatických bitmap obdobu metody pevného prahu (fixed treshold), která se velmi snadno implementuje. Vstupní pixely mají různou intenzitu (stupeň šedi), která je obvykle v rozsahu hodnot 0-255. Pro převod zvolíme určitou hodnotu v tomto intervalu (práh), podle které se bude řídit přiřazení buď černé, nebo bílé barvy. Práh lze sice počítat podle různých kritérií (varianční práh, entropický práh), ale pro jednoduchost stačí zvolit střední hodnotu, tedy aritmetický průměr minimální a maximální intenzity pixelu:
T=
0 + 255 = 127,5 2
Všechny pixely, které mají intenzitu menší než T budou nastaveny jako černé, ostatní jako bílé. U plnobarevných bitmap je problém trochu složitější. Existují různé implementace. Například se pro každý pixel projde celá paleta a spočítá se barevná odchylka pixelu a položky palety podle vztahu:
∆ = R − R′ + G − G ′ + B − B′ Tato implementace je však časově velmi náročná, protože pro každý pixel musí spočítat odchylku tolikrát, kolik položek má paleta. Ačkoliv by bylo možné tento problém zredukovat například setříděním palety, je výhodné použít oktalové stromy (viz kap. Datové struktury v počítačové grafice). Ve stromu je pro determinování přesné barvy potřeba pouze osm kroků, takže pokud jsou všechny barvy palety umístěny ve stromu, nemusejí se při průchodu obrázkem počítat odchylky, stačí vždy pouze několik operací porovnání. Výsledky
algoritmus Nearest neighbor, zleva: černá a bílá, 256 barev
Metoda náhodného rozptylu Ačkoliv rozptylovací (rozmývací) metody přidávají do obrázku určitou chybu, pro náš zrakový systém odhalují v obrázku detaily, které u prostého přiřazování nejbližší barvy zanikají. Důvodem použití těchto metod je schopnost představit si neexistující barvu smíšením barev sousedních pixelů, dokonce i u černobílé bitmapy (řidší rozptyl bílých pixelů znamená tmavší barvu, než když jsou hustěji u sebe). Tato primitivní, ale dobře fungující metoda, přičte ke každému pixelu náhodnou chybu (resp. k hodnotě každé barevné složky přičte stejnou chybu). Chyba je zde náhodné číslo, které může nabývat kladných i záporných hodnot. V příkladu je použita chyba v intervalu −63, 63 . Posunuté hodnoty původních pixelů je třeba zarovnat do intervalu 0, 255 . K posunutým hodnotám se přiřazují barvy palety metodou nejbližšího souseda (což platí u všech rozptylovacích algoritmů).
Metoda náhodného rozptylu při konverzi do monochromatických bitmap může fungovat stejně, jako metoda prahování, přičemž hodnota prahu náhodně osciluje kolem střední hodnoty. Čím větší vzdálenost prahu od střední hodnoty, tím více šumu je do obrázku vneseno. Nevýhodou této metody jsou artefakty, které vznikají podle použitého generátoru náhodných čísel. Tato metoda je vhodná u rozostřených obrázků, případně obrázků, kde není kladen důraz na drobné detaily. Výhoda náhodného rozptylu je v dobré reprezentaci ploch a přechodů, kde u jiných metod vznikají opakující se vzory. Výsledky
Random dithering algoritmus, zleva: černá a bílá, 256 barev
Prahování pomocí matic Pro prahování (tresholding) existuje třída algoritmů, u nichž je práh předem určen podle matice, která má obvykle čtvercové rozměry. Tyto algoritmy slouží obvykle k převodu do černobílých bitmap. Při procházení obrázku je vždy potřeba zjistit aktuální pozici v matici. Pokud je šířka a výška matice dána hodnotami width a height, pozice pixelu souřadnicemi x, y; pak pozice v matici se spočítá jako:
x′ = x mod width y′ = y mod height Jsou-li rozměry matice např. 3x3, pak matice obsahuje hodnoty 1-9. Intenzitu pixelu je třeba přesunout do tohoto intervalu, aby bylo možné určit, zda se nachází nad nebo pod prahovou hodnotou. Podle toho se pak pixel nastaví na černý nebo bílý. Intenzita pixelu se potom z barvy určí podle vztahu:
R+G+ B width ⋅ height ⋅ width ⋅ height ⋅ ( R + G + B ) 3 = I= 255 765 Tato hodnota se potom porovnává s hodnotou v matici na pozici, která je určena vztahem výše. Podle výsledku porovnání (je menší / je větší) se nastaví výsledný pixel na černý / bílý. Čím větší matici použijeme, tím jemnější bude výstupní bitmapa. Nejlepšího výstupu bychom dosáhli s maticí o velikost 16x16, protože ta by obsahovala 256 prahů. Vyšší jemnost už není potřeba, avšak v praxi se používají menši matice. Nejmenší použitelná matice má velikost 2x2:
1 3 4 2
Výstupní obrázek při použití matice 2x2 Existuje rekurzivní postup, kterým lze odvodit i větší matice:
1 13 4 16
9 5 12 8
3 15 2 14
11 7 10 6
výsledný obrázek při použití matice 4x4
0 48 12 60 3 51 15 63
32 8 40 2 34 10 42 16 56 24 50 18 58 26 44 4 36 14 46 6 38 28 52 20 62 30 54 22 35 11 43 1 33 9 41 19 59 27 49 17 57 25 47 7 39 13 45 5 37 31 55 23 61 29 53 21
výsledný obrázek při použití matice 8x8
Existují další typy matic, kde jsou body buď rozptýlené, nebo shluknuté (novinový tisk):
8 3 4 6 1 2 7 5 9
shluková matice (3x3)
22 25 15 12 18
23 10 20 14 3 8 5 17 6 1 2 11 9 4 7 21 19 13 24 16
shluková matice (5x5)
1 7 4 5 8 3 6 2 9
disperzní matice (3x3)
2 16 3 13 10 6 11 7 4 14 1 15 12 8 9 5
disperzní matice (4x4)
Distribuce chyby Ačkoliv je tato metoda nejpomalejší z výše uvedených, patří k nejpoužívanějším metodám. U prahování pomocí matic je v obrázku příliš výrazná textura, u náhodného rozptylu zase nemáme žádnou záruku dobrého výsledku v detailech. Algoritmus distribuce chyby (chybové difúze, dithering) je poměrně jednoduchý na implementaci. Pro každý pixel vstupního obrázku se najde v paletě nejbližší barva a určí se chyby, tj. rozdíly mezi hodnotami na jednotlivých barevných složkách (event. jedné složce, pokud pracujeme např. ve stupních šedi). Záměrně nepoužívám pro termín odchylka, protože hodnota chyby může být i záporná. Platí
chyba = barva − paleta [ nejlepší _ barva ] . Pozor ovšem na záměnu menšence a menšitele. U odchylky mohou být zaměněny, ale v tomto případě nikdy. Pixel nejbližší barvy můžeme poslat na výstup. Předtím, než načteme ze vstupu další bod, provedeme ve vstupním obrázku změny. K pixelům v nejbližším okolí, které se budou číst později (tj. vlevo a níže od aktuální pozice), se přičtě zlomek vypočítané chyby. Jakou frakci chyby se přičíst na kterou pozici určuje diagram podobný matici (viz níže). V tomto diagramu je hvězdičkou označen aktuální bod a kolem něj počty částí chyby, která se „rozprostře“ na odpovídající pozice. Jak velká je tato část, udává zlomek vpravo dole. Filtr Floyd-Steinberg (1975)
* 7 3 5 1 116 Dejme tomu, že hodnota vstupního pixelu je 173 a k němu nejbližší hodnota je 182. Pixel s hodnotou 182 se pošle na výstup a vypočítá se chyba, která bude 173-182=-9. Ve vstupním obrázku přičteme k hodnotě pixelu o jedna vpravo 7/16 chyby, tedy (-7).(7/16)=-49/16≈-3. Pixel vpravo má hodnotu 25, po přičtení chyby bude mít 25-3=22. Musíme dát pozor, aby byla hodnota pixelu po přičtení ve povoleném intervalu hodnot. Tedy pokud je záporná, stanovíme ji rovnu 0, pokud bude větší než 255, stanovíme ji rovnu 255. Stejné přičtení chyby se provede v pixelu vlevo dole, dole a vpravo dole. Filtr je tedy předpis, který říká, jak bude chyba rozložena do okolních pixelů. Obecně platí, že čím dál filtr zasahuje, tím kvalitnější bude výsledek. Často ale záleží na subjektivním dojmu, protože každý filtr vykazuje v homogenních oblastech charakteristický vzorek. Filtr Floyda a Steinberga byl výsledkem jejich výzkumu v roce 1975 a je to jakýsi standardní filtr, obecně nejpoužívanější.
filtr Floyd-Steinberg Filtr „false“ Floyd-Steinberg Někdy se v literatuře a na webu tento filtr mylně zmiňuje jako Floyd-Steinbergův, proto přídomek „false“. Vzhledem k nedostatečné distribuci chyby produkuje filtr až příliš viditelné artefakty; nouzově se však dá eventuálně použít v časově kritických aplikacích.
* 3 3 2 18
filtr „false“ Floyd-Steinberg Filtr Jarvis-Judice-Ninke (1976) Tento filtr vyniká dobrým rozložením chyby. Musí se určovat pouhá 1/48 chyby, protože ta se nakumuluje v pixelech, ke kterým bude chyba přičítána vícekrát, právě díky rozsáhlosti filtru.
* 7 5 3 5 7 5 3 1 3 5 3 1 1 48
filtr Jarvis-Judice-Ninke Filtr Stucki (1977)
O rok později vydal P. Stucki tento filtr jako přepracování filtru Jarvise, Judice a Ninkeho. Výstup by měl být poněkud čistší a ostřejší.
* 8 4 2 4 8 4 2 1 2 4 2 1 1 42
filtr Stucki Filtr Burkes (1988) D. Burkes později přepracoval filtr Stucki, což mělo vést ke snížení výpočetní náročnosti jeho implementace. Snaha byla místo dělení používat více bitových posunů a tím filtrování výrazně urychlit. Důležitá byla tedy změna dělitele, jinak co se týče distribuce chyby, byl pouze odstraněn poslední řádek filtru Stucki.
* 8 4 2 4 8 4 2 132
filtr Burkes Filtry Sierra (1989) Nejpozději vyvinutá rodina filtrů F. Sierry přináší lepší výsledky, než původní filtr Floyd-Steinberg. Tři verze těchto filtrů se liší velikostí a tím i náročností. Je možné z nich vybrat podle požadovaného výkonu a tím zvýšit škálovatelnost aplikace používající rozptylování.
* 2 1 1 14
filtr Sierra 2-4A („Lite“)
* 4 3 1 2 3 2 1 116
filtr Sierra 2
* 5 3 2 4 5 4 2 2 3 2 1 32
filtr Sierra 3