Autor: Jiří Hnídek / jiri.hnidek@tul.cz
Snahou tohoto procesu je dosáhnout podobného obrazového vjemu při omezení počtu barev v obraze.
Obecně platí:
$$ V_{in} -> V_{out}; V_{in} \in \langle 0, s \rangle; \quad V_{out} \in \langle 0, t \rangle; t \leq s $$Existuje několik metod, které jsou vhodné pro různé případy.
Formáty splňující BT.601
$$ Y = 0.299 R + 0.587 G + 0.114 B $$Formáty splňující BT.709
$$ Y = 0.2126 R + 0.7152 G + 0.0722 B $$Nejprve si ukážeme omezení obrázků, které jsou v šedotónové stupnici na obrázky, které obsahují pouze černé a bílé body.
Základní jednoduchá metoda vhodná například pro vytváření jednoduché masky.
for V_in in pixels.values():
if V_in > threshold:
V_out = max
else:
V_out = min
Výsledný obrázek více připomíná výslednou předlohu, ale je zatížen velkým šumem.
for V_in in pixels.values():
if V_in > random(min, max):
V_out = max
else:
V_out = min
Vstupní hodnoty i hodnoty v matici k.M musí být ve stejném rozsahu.
for pixel in pixels:
V_in = pixel.value
x = pixel.x
y = pixel.y
if V_in > k*M[x mod n, y mod n]:
V_out = max
else:
V_out = min
Matice je čtverocvá a její řád je vždy mocnou 2. Lze ji generovat rekurzivně pomocí:
$$ M_{(2n)} = \begin{bmatrix} 4M_{(n)} & 4M_{(n)} + 3J_{(n)} \\ 4M_{(n)} + 2J_{(n)} & 4M_{(n)} + J_{(n)} \\ \end{bmatrix} $$kde $J_{(n)}$ čtvercová matici obsahující samé jedničky a $M_{(1)}$ je jednoprvková matice obsahující nulu.
Povšimňete si, že hodnoty narůstají v zavírající se spirále. Ve výsledku výsledný obrázek obsahuje puntíky.
$$ M_{4} = \begin{bmatrix} 1 & 5 & 9 & 2 \\ 8 & 12 & 13 & 6 \\ 4 & 15 & 14 & 10 \\ 0 & 11 & 7 & 3 \\ \end{bmatrix} $$Tato metoda vychází z prahování a základní myšlenka algoritmu spočívá v tom, že chyba způsobená omezením vstupní barevné informace jednoho pixelu se distribuuje na dosud nezpracované okolní pixely.
for pixel in pixels:
V_in = pixel.value
x = pixel.x
y = pixel.y
if V_in > threshold:
V_out = max
else:
V_out = min
chyba = V_out - V_in
pixels[x+1,y] += (7/16)*chyba
pixels[x-1,y+1] += (3/16)*chyba
pixels[x,y+1] += (5/16)*chyba
pixels[x+1,y+1] += (1/16)*chyba
Distribuci zaokrouhlovací chyby lze použít i u maticového rozptylu.
$$ \frac{1}{16} \begin{bmatrix} 0 & 0 & 0 \\ 0 & 0 & 7 \\ 3 & 5 & 1 \end{bmatrix} $$Barevná paleta je vytvořena, tak aby v ní byly zastoupeny nejčastěji se vyskytující barvy ve vstupním obrázku.
V algoritmu se využívá RGB krychle. Nejprve krychli naplníme body podle pixelů v daném obrázku a určíme krajní body ohraničující obálky:
x_min = y_min = z_min = 1.0
x_max = y_max = z_max = 0.0
for pixel in pixels:
pnt.x, pnt.y, pnt.z = pixel.r, pixel.g, pixel.b
x_min = (x_min > pnt.x) ? pnt.x : x_min
y_min = ...
x_max = (x_max < pnt.x) ? pnt.x : x_max
y_max = ...
Následne určíme nejdelší stranu ohraničující obálky:
diff_x = x_max - x_min
diff_y = y_max - y_min
diff_z = z_max - y_min
Ohraničující obálku rozděl kolmým řezem na vybranou souřadnicovou osu. Místo řezu nutné volit tak, aby v obou nových částech byl přibližně stejný počet barev (lze předpočítat v předchozím kroku).
Následně aktualizujeme ohraničující obálky pro nové oblasti.
Dělení ohraničujících obálek se opakuje dokud celkový počet ohraničujících obálek není roven požadovanému počtu barev v barevné paletě.
Každé ohraničující obálce přiřaď barvu (medián, případně průměrná barva).
Často se místo kartézské soustavy souřané používají homogenní souřadnice. Každý bod $P=[X, Y]$ má učitou váhu: w
Převod z homogenních souřadnice do kartézské soustavy souřadné:
$$ \begin{align} X' &= \frac{X}{w} \\ Y' &= \frac{Y}{w} \\ \end{align} $$Obecná transformační matice pro 2D transformace má následující tvar:
$$ \begin{bmatrix} X' \\ Y' \\ w' \\ \end{bmatrix} = \begin{bmatrix} m_{1,1} & m_{1,2} & m_{1,3} \\ m_{2,1} & m_{2,2} & m_{2,3} \\ m_{3,1} & m_{3,2} & m_{3,3} \\ \end{bmatrix} \begin{bmatrix} X \\ Y \\ w \\ \end{bmatrix} $$Posun můžeme vyjádřit vektorem posunutí $(dx, dy)$ a maticovým násobením:
$$ \begin{bmatrix} X' \\ Y' \\ w' \\ \end{bmatrix} = \begin{bmatrix} 1 & 0 & dx \\ 0 & 1 & dy \\ 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} X \\ Y \\ w \\ \end{bmatrix} $$Zvětšení nebo zmenšení může být ve směru os různé a je vztažené vůči počátku soustavy souřadné:
$$ \begin{bmatrix} X' \\ Y' \\ w' \\ \end{bmatrix} = \begin{bmatrix} S_{x} & 0 & 0 \\ 0 & S_{y} & 0 \\ 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} X \\ Y \\ w \\ \end{bmatrix} $$Zkosení ve směru jedné osy. V tomto případě ve směru osy x
$$ \begin{bmatrix} X' \\ Y' \\ w' \\ \end{bmatrix} = \begin{bmatrix} 1 & s_{x} & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} X \\ Y \\ w \\ \end{bmatrix} $$Transformační matice pro otočení vůči počátku soustavy souřadné:
$$ \begin{bmatrix} X' \\ Y' \\ w' \\ \end{bmatrix} = \begin{bmatrix} \cos\alpha & -\sin\alpha & 0 \\ \sin\alpha & \cos\alpha & 0 \\ 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} X \\ Y \\ w \\ \end{bmatrix} $$Transformační matice se skládají násobením matice, ale v opačném pořadí než se aplikují.
Příklad: Chceme-li vytvořit matici otočení o $\pi$ vůči bodu $P=[3,4]$, tak výslednou matici vytvoříme následovně:
$$ M = \begin{bmatrix} 1 & 0 & 3 \\ 0 & 1 & 4 \\ 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} \cos\pi & -\sin\pi & 0 \\ \sin\pi & \cos\pi & 0 \\ 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix} 1 & 0 & -3 \\ 0 & 1 & -4 \\ 0 & 0 & 1 \\ \end{bmatrix} $$V případě, že máme pouze 1D signál:
$$ y = \frac{y_{1} - y_{0}}{x_{1} - x_{0}}(x - x_{0}) + y_{0} $$V případě, že máme 2D signál, tak hodnotu $v_{R}$ na souřadnici $R = [x_{R}, y_{R}]$ spočítáme pomocí 3 lineárních interpolací ze 4 okolních bodů $P_{i} = [x_{Pi}, y_{Pi}]$:
$$ \begin{align} v_{Q0} &= \frac{v_{P1} - v_{P0}}{x_{P1} - x_{P0}}(x - x_{P0}) + v_{P0} \\ v_{Q1} &= \frac{v_{P3} - v_{P2}}{x_{P3} - x_{P2}}(x - x_{P2}) + v_{P2} \\ v_{R} &= \frac{v_{Q1} - v_{Q0}}{y_{Q1} - y_{Q0}}(y - y_{Q0}) + v_{Q0} \\ \end{align} $$Uvažujme, že všechny hodnoty jsou v rozsahu $\langle 0, 1\rangle$
$$ c = \alpha_{1} c_{1} + \alpha_{2} c_{2}; \quad \alpha_{1} + \alpha_{2} = 1 $$Rastr s nenulovým alfa kanálem (fg) umisťujeme na rastr, kde uvažujeme všechny pixely neprůhledné (bg).
$$ c = \alpha c_{fg} + (1 - \alpha) c_{bg} $$Mějme animovanou sekvenci (start) a tu chceme od času $t_{0}$ postupně prolnout s animovanou sekvencí (end) za dobu: $\Delta t$
$$ \begin{align} \alpha_{end} &= \frac{1}{\Delta t}(t - t_{0}) \\ \alpha_{start} &= 1 - \alpha_{end} \\ c &= \alpha_{end} c_{end} + \alpha_{start} c_{start} \end{align} $$Uvažujeme klíčování na zelené pozadí a rozsah hodnot barevných kanálů je: $\langle 0, 1\rangle$. Dále si stanovíme hodnoty $\alpha_{min}$ a $\alpha_{max}$, které odlišují pozadí od popředí. Přechod mezi popředím a pozadím je pozvolný a určený alfa kanálem:
$$ \alpha = 1 - G - \max(R,B) $$Pak je možné spočítat barvu jednotlivých barevných kanálů:
$$ c = \begin{cases} \alpha > \alpha_{max}; & c_{fg} \\ \alpha < \alpha_{min}; & c_{bg} \\ \alpha \in \langle \alpha_{min}, \alpha_{max} \rangle; & \alpha c_{fg} + (1 - \alpha) c_{bg} \end{cases} $$Histogram lze vytvořit vždy pouze pro jeden barevný kanál (jas, R, G, B, apod.). Hodnoty v daném kanále mohou nabývat pouze určitého počtu hodnot: N
for i in range(0, N):
hist[i] = 0
for V_in in pixels.values():
hist[V_in] += 1