Obraz cyfrowy

Obraz cyfrowy jest wizualizacją świata rzeczywistego, który otrzymujemy poprzez zapisanie zdjęcia (otrzymanego np. aparatem czy kamerą) w pamięci komputera. Obraz cyfrowy można rozumieć jako tablicę lub macierz (w przypadku kolorowych zdjęć kilku takich elementów).

Aparat fotograficzny

Każdy aparat jest w praktyce czarną skrzynką z otworem z przodu, przez który przechodzi światło z otoczenia i pada na tylną ściankę skrzynki, gdzie umieszcza się materiał światłoczuły. Najprostszą możliwą konstrukcją aparatu jest tzw. camera obscura, czyli pudło z małym otworkiem z przodu i płytą światłoczułą na tylnej ściance, na której zapisywany jest obraz wpadający przez otworek.

  

Na powyższym rysunku model najprostszego aparatu (po  lewej stronie), natomiast po prawej model aparatu współczesnego. Dla naszych potrzeb wystarczy wyróżnić podstawowe elementy aparatu (więcej informacji można znaleźć tutaj). 

A więc aparat w najprostszej wersji składa się ze światłoczułej płaszczyzny obrazu (który wykrywa ilość światła, która pada na niego), obudowy (zapobiega ona padaniu światła rozproszonego na światłoczułą płaszczyznę obrazu) i obiektywu w obudowie, który pozwala światłu padać na płaszczyznę światłoczułą obrazu w kontrolowany sposób (promienie świetlne są skupiane na płaszczyźnie obrazu przez soczewki). 

Jednym z najprostszych modeli aparatu, który dobrze tłumaczy jego działanie, jest właśnie pinhole camera model (model kamery otworkowej), w której rolę soczewki odgrywa otwór, patrz ilustracja poniżej.

Wszystkie promienie światła, które trafiają na płaszczyznę światłoczułą obrazu muszą przyjść poprzez otwór umieszczony przed płaszczyzną światłoczułą. 

Aby zbudować model zacznijmy od najprostszej sytuacji. Ustawmy nasz otwór w punkcie $C$ o współrzędnych $(0,0)$

Naszym celem jest przekształcenie punktu $P=(X, Y, Z)$ w świecie 3D w punkt $p=(x, y)$ na płaszczyźnie obrazu, którą umieścimy tym razem pomiędzy punktem, w którym znajduje się otwór a rzutowanym punktem. Łatwo zauważyć, że odpowiada to modelowanej sytuacji (gdy płaszczyzna obrazu znajduje się po drugiej stroni).

Zauważmy, że $z$ jest stałe dla każdej sceny (płaszczyzna, na którą rzutujemy jest w stałej odległości od środka). Aby wyznaczyć współrzędne punktu $p$ na scenie znajdującej się w odległości $f$ (długość ogniskowej) od punktu $C=(0,0)$ wystarczy przemnożyć odpowiednie współrzędne przez czynnik skalujący

\[ x= X \cdot \frac{f}{Z}, \]

\[ y= Y \cdot \frac{f}{Z}. \]

Jest to prosta konsekwencja Twierdzenie Talesa. Aby wyznaczyć współrzędną $y$ wystarczy zauważyć, że

\[ \frac{y}{f} = \frac{Y}{Z}. \]

Analogicznie, można wyznaczyć współrzędną $x$.

Naszym celem jest odzwierciedlić obraz rzeczywisty za pomocą obrazu cyfrowego, czyli pikseli. W większości przypadków zapisujemy kwadraty. Jeżeli obiekty, które rozważamy nie są dokładnie kwadratami wtedy w naszym modelu musimy dodać czynniki opisujące długości boków $f_x = k \cdot f$ oraz $f_y = l \cdot f$ (gdzie $k,l$ to czynniki skalujące boki prostokątu). W konsekwencji otrzymujemy wzory:

\[ x= X \cdot \frac{f_x}{Z}, \]

\[ y= Y \cdot \frac{f_y}{Z}, \]

Możemy jeszcze uwzględnić sytuację, w któerej środek układu współrzędnych znajduje się w dowolnym punkcie $C=(c_x,c_y)$. Wtedy nasze wzory przyjmują postać najbardziej ogólną:

\[ x= X \cdot \frac{f_x}{Z} + c_x, \]

\[ y= Y \cdot \frac{f_y}{Z} + c_y. \]

W przypadku współrzędnych jednorodnych czyli zadanych za pomocą wektora $x = [x,y,1]$ powyższe przekształcenie można przedstawić w postaci macierzowej.

\[ \begin{bmatrix} x \\ y \\ w \end{bmatrix}= \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} X \\ Y \\ Z \end{bmatrix} \]

gdzie $w$ może być traktowane jako parametr skali.

Przykład. 

Załóżmy, że mamy aparat z długością ogniskowej równą 5mm. Będziemy szukać obrazu punktu $(X,Y,Z)=(1m,2m,5m)$ na płaszczyźnie światłoczułej (x,y).

Aby to obliczyć możemy użyć poniższych wzorów: 

\[ x= X \cdot \frac{f}{Z} = 5mm \frac{1m}{5m} = 1 mm, \]

\[ y= Y \cdot \frac{f}{Z} = 5mm \frac{2m}{5m} = 2 mm. \]

Bardziej skomplikowany model aparatu można zbudować na podstawie soczewki. W takim układzie soczewka pozwala skupić promienie świetlne w odpowiednim miejscu na płaszczyźnie światłoczułej. Taki model dokładniej odpowiada temu co się dzieje wewnątrz ludzkiego oka.

Obraz cyfrowy

Obraz (2D), który dostajemy za pomocą odwzorowania rzeczywistej sceny (3D) za pomocą powyższego mechanizmu może być odbierany jako funkcja dwóch zmiennych $f \colon \mathrm{R} \times \mathrm{R} \to \mathrm{R}$. Aby przechować taki obraz w pamięci komputera musimy dokonać dwóch kroków:

  1. Próbkowania - do macierzy ($M$-wierszy i $N$ kolumn)
  2. Kwantyzacji - tak by każdy element w macierzy przyjmował wartość całkowitą z zadanego przedziału (najczęściej przyjmują one wartości od [0,256]).  

Ilustracja. Efekt próbkowania i kwantyzacji.

Powyższy proces został przedstawiony na obrazku. Po przekształceniu nasz obiekt jest złożony z pikseli, które można traktować jako małe kwadraciki tego samego koloru.

Próbkowanie OpenCV

Pierwszy raz użyjemy biblioteki OpenCV. Więcej informacji oraz proste Tutoriale znajdziesz w odpowiednich podrozdziałach sekcji OpenCV naszego kursu. Polecamy rozdział Instalacja oraz Pierwszy program.

Próbkowanie polega na zapisaniu ciągłego obrazu za pomocą macierzy (tablicy). W praktyce polega ona na podzieleniu płaszczyzny światłoczułej na kwadraty. Czasami oddziela się te kwadraty za pomocą elementów, które nie są światłoczułe, tak by uzyskać coś w rodzaju kraty. Powoduje to utratę pewnych informacji.  

W zależności na jak duże kwadraty podzielimy nasz obraz, to dostaniemy różną jakość zdjęcia. Im więcej pikseli (kratki są mniejsze), tym jakość naszego obrazu jest większa.

    

Próbkowanie można uzyskać za pomocą kodu: OpenCV (C++)

Kwantyzacja

Dokonajmy kwantyzacji na obrazie wir.

Kwantyzacja polega na zapisaniu ciągłego obrazu za pomocą skończonej ilości (najczęściej $[0,255]$) całkowitych wartości. Odbywa się to, najczęściej poprzez podzielenie obrazu na rozłączne kwadraty (jak na obrazku powyżej). Każdemu kwadratowi, który odpowiada pikselom, przydzielany jest jeden kolor. Najczęściej jest to średnia z kolorów w kwadracie.

     

     

   

 

Próbkowanie można uzyskać za pomocą kodu: OpenCV (C++).

LookUp Table (LUT) 

Tablicowanie – technika programistyczna wykorzystująca strukturę nazywaną tablicą (ang. lookup table) do przechowywania przygotowanych wcześniej danych, co umożliwia zaoszczędzenie czasu wymaganego na ich obliczenie kosztem większego zużycia pamięci Lookup table

Zdjęcie możemy traktować jako funkcję $f \colon [0, width] \times [0,height] \to [0,255]$. Każdy piksel o współrzędnych $(i,j)$ posiada kolor $f(i,j)$.
Rozważmy przekształcenie zdjęcia opisanego funkcją $F \colon [0,255] \to [0,255]$. Czyli każdy piksel $(i,j)$ w zależności od swojego koloru $f(i,j)$  zmienia swoją barwę na $F(f(i,j))$:

\[  f(i,j) \to F(f(i,j)) \]

W takim przypadku należy wykonać:

for (i = 0; i < height; i++){
  for (j = 0; j < weight; j++){
    f(i,j) = F(f(i,j));
  }
}

Pytanie jest czy to się opłaca? Funkcja $F$ wykonuje się $width \cdot height$ razy.

Aby zmniejszyć ilość wykonanych pętli, możemy najpierw wyznaczyć na jaki kolor zmienia się piksel o danym kolorze. Ilość kolorów jest ograniczona ([0,255]).

for (i = 0; i < 256; i++){
    LUT(i) = F(i);a
}

A następnie zmienić kolory odpowiednich pikseli używając tylko tablicy LUT:

for (i = 0; i < height; i++){
  for (j = 0; j < weight; j++){
    f(i,j) = LUT[f(i,j)];
  }
}

W taki sposób, funkcja $F$ została wykonana tylko 256 razy.

Za pomocą tablicy LUT również możemy dokonać kwantyzacji. Niech $B=8$ będzie ilością bitów przeznaczoną do zapisu koloru jednego piksela. Jeżeli chcemy zmienić ilość bitów przeznaczonych na zapis koloru $newB \in \{ 1,\ldots,8 \}$ możemy to zrobić za pomocą LUT.

Najpierw potrzebujemy wskaźnika $\delta$

\[ \delta = \frac{2^B}{2^{newB}} \] 

A następnie musimy stworzyć tablicę LUT:a

\[ LUT[i] = floor \{  \max \{ \frac{i-\frac{\delta}{2}-1}{\delta} , 0 \} \cdot \delta + \left( \frac{\delta}{2} - 1 \right) \} \]

Program wykorzystujący LUT OpenCV (C++)