Histogram obrazu

Histogram obrazu jest opisem statystycznym wartości obrazu (jasność / intensywność). 

Histogram 1D

W przypadku obrazów w skali szarości, gdzie kolory pikseli są opisane za pomocą jednej liczby (w zakresie $[0,255]$), histogram pokazuje ile występuje elementów (pikseli) każdego z kolorów. 

Algorytm tworzenia histogramu $h$ dla obrazu w odcieniach szarości $f (i, j)$ można przedstawić w następujący sposób:

// Initialise the histogram
for (i = 0; i <= 255; i++){
  h(i) = 0
}
// Compute the histogram
for (i = 0; i < MAX_column; i++){
  for (j = 0; j < MAX_row; j++){
    h(f(i,j))++
  }
}

Kod programu tworzący histogram: OpenCV (C++).

  

Globalne i lokalne maksima i minima w histogramie mogą dostarczać użytecznych informacji, chociaż jak widzimy na powyższym rysunku może być wiele lokalnych maksimów i minimów. Aby zmniejszyć tę liczbę, histogram można wygładzić. Można w tym celu użyć filtrów opisanych w poprzednim rozdziale, takich jak filtr średniej ruchomej, filtr Gaussowski czy filtr medianowy OpenCV (C++)

Aby uzyskać powyższy wynik zastosowaliśmy filtr średniej ruchomej z szerokością okna 5. Zawsze w takich przypadkach trzeba uważać na końce histogramu. Jest wiele technik radzących sobie z tym problemem. My po prostu nie uśredniamy dwóch pierwszych i dwóch ostatnich wartości.

Histogram dla zdjęć kolorowych

Kolejną bardzo ważną kwestią jest histogram dla zdjęć kolorowych. Jedną z technik jest stworzenie histogramu dla każdego z kanałów osobno (OpenCV (C++),).

  

Wyrównywanie Histogramu 

Obrazy bardzo często zawierają elementy, które  są trudne do zauważenia. W szczególności gdy zdjęcie jest w odcieniach szarości, a obiekty są zacienione. Stwierdzono, że ludzkie oko odróżnia od 700 do 900 odcieni szarości w optymalnych warunkach widzenia. W bardzo ciemnych lub jasnych częściach obrazu człowiek widzi dużo mniej. Ludzkie oko lepiej rozpoznaje obiekty gdy są one dobrze odseparowane (relatywnie duże różnice w barwie).

Jedną z technik poprawiających ostrość / jakość na obrazie jest wyrównywanie histogramu. Metoda ta polega na wyrównaniu poziomów szarości, tak aby histogram był płaski (czyli wszystkie stopnie szarości miały dokładnie taką samą liczbę punktów). W praktyce nie jest to możliwe, więc otrzymany histogram często jest postrzępiony.

Wyrównanie histogramu można otrzymać za pomocą tablicy LUT (LUT). W pierwszym kroku musimy stworzyć dystrybuantę empiryczną:

\[ D[n] = \frac{h_0 + h_1 + \ldots + h_n}{ sum } \]

gdzie 

  • $h_n$ - to ilość punktów na obrazie o n-tym poziomie szarości,
  • $sum$ - to liczba wszystkich punktów obrazu.

W drugim kroku możemy stworzyć tablicę LUT:

\[ LUT[i] = \frac{D[i] - D_0 }{ 1 - D_0 } \cdot (k-1) \]

gdzie 

  • $D_0$ - to pierwsza niezerowa wartość dystrybuanty obrazu źródłowego,
  • $k$ to liczba możliwych wartości jasności obrazu (zwykle 256).

Zacznijmy od równania histogramu na zdjęciu w odcieniach szarości OpenCV (C++).

  

  

Analogiczną procedurę możemy przeprowadzić w przypadku zdjęć kolorowych. Nie będziemy jednak wyrównywać histogramów poszczególnych kanałów RGB. Najczęściej stosowaną metodą jest przejście do formatu YCbCr i wyrównane histogramu tylko na komponencie $Y$ (luminancji) OpenCV (C++).

  

  

Rozciągnięcie histogramu

Rozciągnięcie histogramu (ang. histogram stretching) wykonuje się wówczas, gdy nie pokrywa on całego zakresu wartości składowych obrazu. Czasem operacja ta mylona jest z wyrównywaniem histogramu. Rozciągnięcie prowadzi do takiej konwersji zakresu wartości składowych, aby histogram obejmował wszystkie wartości (najczęściej [1,256]). Czyli jeżeli zakres składowej jest równy 0 - 255, a najmniejsza wartość w obrazie wynosi 4, największa natomiast wynosi na przykład 198, to po operacji rozciągnięcia wartości będą w pełnym zakresie 0 - 255. Czyli teraz najmniejsza wartość w obrazie wynosi 0, a największa 255. Operacje rozciągnięcia histogramu można przeprowadzić odpowiednio dobierając jasność i kontrast obrazu.

W praktyce rozciągnięcie histogramu sprowadza się do wykonania przekształcenia obrazu przy pomocy odpowiednio przygotowanej tablicy LUT LUT:

\[ LUT[i] = \frac{255}{ v_{max} - v_{min} } \cdot ( i - v_{min} ) \]

gdzie

  • $v_{max}$ - oznacza maksymalną wartość składowej w obrazie (najczęściej 255),
  • $v_{min}$ - oznacza minimalną wartość składowej w obrazie (najczęściej 0).

Zacznijmy od rozciągnięcia zdjęcia w odcieniach szarości:

  

  

Kod realizujący rozciągnięcie histogramu znajduje się tutaj: OpenCV (C++)

W przypadku zdjęć kolorowych można zastosować identyczną technikę jak przy wyrównywaniu histogramu. Najpierw zapisujemy zdjęcie w formacie YCbCr, a następnie działamy tylko na komponencie $Y$ (luminancji).

  

  

Kod realizujący rozciągnięcie znajduje się tutaj: OpenCV (C++).

Porównanie Histogramów

Pobierania obrazów, które są podobne do danego lub takich, które zawierają określoną zawartość jest dobrze znanym zagadnieniem. Większość przeglądarek zapewniają taką funkcjonalność. Najczęściej proces ten odbywa się za pomocą znaczników meta-danych związanych z każdym obrazem.

Dzięki analizie rozkładu kolorów na obrazie, można zapewnić wsparcie dla tego procesu. 

Istnieje wiele wskaźników / miar, które są powszechnie stosowane do porównania histogramów:

  • \[ D_{Correlation}(h1,h2) = \frac{\sum_{i} (h_1(i) - mean(h_1) ) ( h_2(i) - mean(h_2)  ) }{ \sqrt{ \sum_{i} (h_1(i) - mean(h_1) )^2 \sum_{i} (h_2(i) - mean(h_2) )^2  } } \]
  • \[ D_{Chi\_Square} (h1,h2) = \sum_{i} \frac{( h_1(i) - h_2(i) )^2}{ (h_1(i) + h_2(i) ) }  \]
  • \[ D_{Intersection} (h1,h2) = \sum_{i} \min \{ h_1(i), h_2(i)  \} \]
  • \[ D_{Bhattacharyya} (h1,h2) = \sqrt{ 1- \frac{1}{ \sqrt{ mean(h1) man(h2) } } \sum_i \sqrt{h_1(i) h_2(i)} } \]

gdzie

  • $N$ - ilość binów w histogramach
  • $mean(k) = \sum_{i} \frac{h(i)}{N} $

Zasymilujmy problem wyszukiwania podobnych obiektów. Podobny eksperyment jest opisany w http://www.laganiere.name/opencvCookbook/. Obrazy użyte w tym poniższym porównaniu pochodzą z repozytorium udostępnionego przez autora wspomnianej książki zdjęcia

Załóżmy, że mamy zdjęcie c1.jpg. I chcemy znaleźć zdjęcia podobne do niego w repozytorium składającym się z  c2.jpgc3.jpgc4.jpgc5.jpgc6.jpg

   

c1.jpg                           c2.jpg                       c3.jpg

    

c4.jpg                           c5.jpg                       c6.jpg

Rozwiązanie jest proste. Najpierw tworzymy dla każdego ze zdjęć histogram a następnie porównujemy histogramy ze sobą. Zacznijmy od histogramu w odcieniach szarości.

    

c1.jpg                           c2.jpg                       c3.jpg

    

c4.jpg                                   c5.jpg                               c6.jpg

Wyniki prezentuje tabela poniżej:

Metoda 1c.jpg 2c.jpg 3c.jpg 4c.jpg 5c.jpg 6c.jpg
Correlation 1.0 0.3614 0.7413 0.5997  0.0445  0.3168
Chi Square 0.0  499.91 162.26 460.38 1056.84  131.86
Intersection 37.6586 31.4271 29.6570  33.2416 31.4297 25.8859
Bhattacharyya 0.0 0.3625 0.3425 0.3629  0.4236  0.4236

Program do generowania poniższej tablicy można pobrać stąd: OpenCV (C++)

Używanie tylko histogramu dla odcieni szarości czasami jest niewystarczające. Można użyć też bardziej skomplikowanych obiektów takich jak histogram 2D lub 3D.

Histogram 2D i 3D

Jak już mówiliśmy, każdy z kolorów może być rozpatrywany osobno (lewy obraz na ilustracji poniżej). Oczywiście czasami rozważamy tylko obrazy w odcieniach szarości i wtedy mamy do czynienia tylko z jednym kanałem. Jeżeli chcemy wykorzystać pełną informację o kolorze, to możemy stworzyć histogram 2D lub 3D (rysunek po prawej stronie poniższej ilustracji). W takim przypadku przestrzeń kolorów (np. RGB) jest dzielona na kostki (a nie na przedziały jak w 1D). Narysowanie histogramu 3D jest trudne, natomiast w  2D można stworzyć go w miarę łatwo.

Aby stworzyć histogram 2D musimy wybrać dwie współrzędne. Najbardziej intuicyjne jest rozważanie hue oraz saturation z formatu HSV. Porównajmy histogramy 2D dla zdjęć s1.jpgs2.jpgs3.jpg.

      

s1.jpg                            s2.jpg                             s3.jpg

      

s1.jpg                            s2.jpg                             s3.jpg

Histogram 2D w: OpenCV (C++)

Jeżeli mamy już histogram w 2D to możemy go użyć do porównywania obrazków.

Zacznijmy od porównania dłoni (OpenCV (C++)): 

Metoda s1.jpg s2.jpg s3.jpg
Correlation 1.0 0.2045 0.0664
Chi Square 0.0 2697.98 4763.8
Intersection 18.8946 5.4408 2.5817
Bhattacharyya 0.0 0.6798 0.8741

Możemy też porównać obrazki z poprzedniego przykładu (OpenCV C++)

Metoda 1c.jpg 2c.jpg 3c.jpg 4c.jpg 5c.jpg 6c.jpg
Correlation 1.0 0.2368 0.1755 0.1615 0.2709 0.0343
Chi Square 0.0 10214.98 10204 20890.61 4258.5 7265.14
Intersection 9.6387 5.8012 3.5468 3.7167 5.47 1.2454
Bhattacharyya 0.0 0.6222 0.7311 0.7708 0.609 0.8453

Back-projection

Na końcu rozdziału opisującego kolory rozważaliśmy kilka bardzo prostych metod segmentacji (kolor skóry oraz czerwone oczy) Zdjęcia kolorowe. Było to bardzo proste podejście. Teraz zajmiemy się troszeczkę innym sposobem, który pozwoli nam wydobywać komponenty- Back-projection.

Metoda back-projection polega na:

  • Wybierz reprezentatywną próbkę kolorów, których będziesz szukał,
  • Stwórz histogram z próbek,
  • Znormalizuj histogram,
  • Zamień oryginalne kolory, na te które powstały w wyniku tworzenia histogramu.

Zauważ, że w wyniku tworzenia histogramu, kolory, które znajdą się w jednym przedziale stają się tego samego koloru. Wynik powyższej operacji zależy od ilości i szerokości binów.

My weźmiemy pod uwagę cały obraz. Poniżej prezentujemy wynik Back-projection dla ilości binów od 1 do 9.

   

  

Powyższy efekt można uzyskać za pomocą: OpenCV (C++)

Oczywiście możemy manipulować parametrem szerokości binów w histogramie w zakresie od 1 do 256 (OpenCV (C++)).