5.18. Histogramy i statystyki

Obok operacji, które zmieniają piksele obrazu, klasa Image udostępnia rodzinę metod, które je mierzą – podsumowują rozkład wartości pikseli, zwracają średnią i medianę jasności, znajdują optymalny próg podziału między ciemnymi a jasnymi pikselami oraz raportują rozproszenie kanałów koloru. Pomiary te zasilają aplikacje na dwa sposoby: jako dane wejściowe dla kodu, który decyduje, jakiego progu użyć, jakie wzmocnienie ustawić i jak wygląda profil tonalny sceny; oraz jako sygnały diagnostyczne – „czy scena jest wystarczająco jasna?” – na które aplikacja może zareagować, nie podejmując decyzji dotyczącej żadnego konkretnego piksela.

Punktem wyjścia dla niemal każdego pomiaru jest histogram.

5.18.1. Histogram

Histogram obrazu to zliczenie, ile pikseli ma każdą możliwą wartość jasności. Dla obrazu w skali szarości jest to lista zliczeń indeksowana wartościami od 0 do 255. Dla obrazu kolorowego są to trzy takie listy – po jednej na kanał.

get_histogram() go oblicza:

h = img.get_histogram()

Zwracany obiekt to wynik histogram, który udostępnia listy przedziałów dla poszczególnych kanałów oraz kilka zapytań wysokiego poziomu na ich temat. Zliczenia w przedziałach są znormalizowane, tak aby sumowały się do 1.0 – histogram opisuje profil rozkładu, a nie bezwzględną liczbę pikseli, co sprawia, że pomiary są porównywalne między obrazami o różnych rozmiarach.

Dla obrazów w skali szarości histogram ma jeden kanał przedziałów, dostępny jako h.bins() (lub równoważnie h[0]). Dla obrazów RGB565 histogram jest obliczany w przestrzeni koloru LAB przedstawionej na stronie poświęconej progowaniu binarnemu, z trzema kanałami przedziałów dostępnymi jako h.l_bins(), h.a_bins(), h.b_bins() (lub h[0], h[1], h[2]). LAB to ten sam wybór, którego używają metody progowania i śledzenia; histogramy zgadzają się z progami co do przestrzeni, w której mierzony jest kolor.

5.18.2. Przedziały i ich liczba

Domyślny histogram ma jeden przedział na każdą możliwą wartość piksela – 256 przedziałów dla kanału 8-bitowego. Czasem jest to drobniejsza rozdzielczość, niż potrzebuje aplikacja. Klasyfikator, którego interesuje jedynie ogólny profil rozkładu, może lepiej działać z mniejszą liczbą przedziałów – 32 lub nawet 8 – co zarówno przyspiesza działanie, jak i daje czystszy wynik wobec szumu. Słowo kluczowe bins (oraz l_bins, a_bins, b_bins dla poszczególnych kanałów koloru) ustawia tę liczbę:

h = img.get_histogram(bins=32)

Ograniczanie zakresu przez ROI i progi działa tak samo jak w każdej innej metodzie pomiarowej. Przekaż roi, aby ograniczyć histogram do prostokątnego obszaru pikseli; przekaż listę thresholds, aby uwzględnić tylko piksele pasujące do tych zakresów. Forma z progami sprawia, że „oblicz histogram wyłącznie pasujących pikseli” jest operacją jednego wywołania – częsty wzorzec, gdy aplikacja chce scharakteryzować teksturę już wykrytego obszaru bez konieczności samodzielnego przechodzenia po pikselach.

Histogram w skali szarości narysowany jako rząd słupków w zakresie jasności od 0 do 255. Rozkład ma dwa szczyty -- mniejszy ciemny i większy jasny -- rozdzielone wyraźną doliną. Nałożone są trzy pionowe linie: próg Otsu w dolinie, średnia przesunięta ku większemu jasnemu szczytowi oraz mediana dalej w prawo, gdzie skumulowana liczba pikseli osiąga połowę.

Histogram w skali szarości z nałożonymi trzema podsumowującymi pomiarami: próg Otsu (granica, która najlepiej rozdziela ciemne i jasne skupiska), średnia oraz mediana. Każdy z pomiarów mówi coś innego o tym samym rozkładzie.

5.18.3. Statystyki

Histogram jest opisem częstości występowania każdej wartości; statystyki to wyprowadzone z niego liczbowe podsumowania. Obiekt statistics zwracany przez get_statistics() zawiera standardowy zestaw:

  • mean – średnia arytmetyczna wartości pikseli.

  • median – wartość, poniżej której leży połowa pikseli.

  • mode – najczęściej występująca pojedyncza wartość.

  • stdev – odchylenie standardowe, miara rozproszenia wokół średniej.

  • min i max – najjaśniejsze i najciemniejsze obecne wartości pikseli.

  • lq i uq – progi dolnego i górnego kwartyla.

Dla obrazu RGB565 formy dla poszczególnych kanałów (l_mean, a_median, b_mode itd.) dostarczają tych samych pomiarów kanał po kanale.

Większość z tych liczb pojawia się w określonych kontekstach. mean i stdev razem dają oszacowanie szumu: scena, która powinna być jednolita, ma małe stdev, podczas gdy zaszumiony sensor nadaje tej samej scenie większe stdev. min i max dają kontrast obrazu: im są bliżej siebie, tym płaszcza scena; im dalej od siebie, tym większy zakres dynamiczny, z którym algorytm może pracować. median jest odpornym środkiem, gdy rozkład zawiera wartości odstające (kilka bardzo jasnych pikseli nie przeciąga mediany tak, jak przeciąga średnią). mode to pojedyncza najczęściej występująca wartość, przydatna do znalezienia poziomu tła obrazu, którego tło pokrywa większość pikseli.

get_statistics() wykonuje wewnętrznie przebieg histogramu, a następnie go podsumowuje; przekazanie tych samych argumentów thresholds i roi co przy wcześniej obliczonym histogramie daje statystyki dla tego samego zbioru pikseli.

5.18.4. Percentyle i odczyty z dystrybuanty (CDF)

Obiekt histogram udostępnia metodę get_percentile(), która zamienia ułamek na wartość piksela – wartość, poniżej której leży żądany ułamek pikseli. h.get_percentile(0.5) to mediana; h.get_percentile(0.05) i h.get_percentile(0.95) razem dają odporne min/max, które ignoruje dolne i górne 5% jako wartości odstające.

To właśnie ta forma jest używana przez aplikację, gdy chce ona scharakteryzować zakres wartości pikseli bez dopuszczenia, by garstka pojedynczych jasnych lub ciemnych pikseli zniekształciła wynik. Odporne min/max z 5. i 95. percentyla jest również naturalnym wejściem dla przebiegu rozciągania kontrastu – przekształcenia każdego piksela, które omawia rozdział o korekcjach tonalnych.

5.18.5. Metoda Otsu

Histogramy odpowiadają na jeszcze jedno pytanie warte osobnego wyróżnienia: mając obraz, którego piksele dzielą się na skupisko „ciemne” i „jasne”, gdzie przebiega granica między nimi? Strona o progowaniu nazwała już ten mechanizm po jego wyniku – pojedynczym globalnym progu, który aplikacja może przekazać do binary() – ale odłożyła jak. Tym „jak” jest metoda Otsu i działa ona na histogramie.

Intuicja: obraz z wyraźnym pierwszym planem i tłem ma dwa skupiska w histogramie jasności, z doliną między nimi. Właściwym miejscem na próg jest dno doliny – wartość, przy której oba skupiska są najlepiej rozdzielone. Metoda Otsu przeszukuje każdą możliwą granicę i wybiera tę, dla której wariancje wewnątrz skupisk są najmniejsze (co jest równoznaczne ze stwierdzeniem, że wariancja między skupiskami jest największa), a wynikiem jest optymalny podział binarny dla rozkładu danego, konkretnego obrazu.

Obiekt histogram udostępnia metodę Otsu poprzez get_threshold:

h = img.get_histogram()
t = h.get_threshold()

Zwracany obiekt threshold ma atrybuty value (dla skali szarości) lub l_value / a_value / b_value (dla koloru) przenoszące wybraną granicę. Podanie wyniku z powrotem do binary() daje samoregulujący się globalny próg, którego granicę wybiera sam obraz:

img.binary([(t.value, 255)])

Ten wzorzec nie rozwiązuje problemu nierównomiernego oświetlenia, który rozwiązuje próg adaptacyjny oparty na filtrach; rozwiązuje on pytanie „przy jakiej wartości powinienem przeciąć?”, gdy progowanie globalne jest już właściwym podejściem. Dla sceny, w której rozróżnienie pierwszego planu od tła jest dobrze zdefiniowane, wartość wybrana przez Otsu jest zwykle w granicach kilku jednostek od tego, co człowiek wybrałby na oko.

5.18.6. Obliczenia na obrazie różnicowym

Przydatny szczegół dotyczący get_histogram() i get_statistics(): obie akceptują słowo kluczowe difference, które przyjmuje inny obiekt Image i oblicza histogram (lub statystyki) różnicy między źródłem a tym obrazem dla każdego piksela, bez alokowania osobnego obrazu różnicowego. To tani sposób, by zapytać „jak bardzo scena zmieniła się od ramki referencyjnej?”, bez płacenia za jawne wywołanie difference() w celu utworzenia obrazu, którego jedynym celem jest bycie zmierzonym. Przy skrypcie wykrywania ruchu działającym w sposób ciągły oszczędności się sumują.