środa, 24 marca 2010

Segmentacja skóry oparta o reguły Bayesa

Dzisiaj będzie trochę o prostej segmentacji skóry związanej z regułami Bayesa. Metody które opisywałem wcześniej, opierały się jedynie o wektor w pewnej przestrzeni kolorów. Powodowało to, że w różnych warunkach oświetleniowych czy nawet przy różnych kamerach wyniki znacząco się różniły. Uzyskiwaliśmy jednak wynik w postaci binarnej. Dzięki regułom Bayesa możemy w pewien sposób zapobiec wspomnianym różnicom, ale wynik będzie w zbiorze rozmytym - każdy piksel będzie na X % skórą. Poniżej opiszę krótko metodę, zaprezentuję kilka obrazów wynikowych a na końcu zamieszczę kod.

Reguły Bayesa

O regułach Bayesa można przeczytać np. na wikipedii (na angielskiej jest bardziej rozbudowany artykuł). W skrócie chodzi o ustalenie prawdopodobieństwa warunkowego. Dobrze ilustruje to przykład z wikipedii angielskiej którego sens wygląda mniej więcej tak:

Do pewnej szkoły uczęszcza 10 chłopców i 12 dziewczyn. Połowa dziewczyn nosi spodnie, połowa spódnice. Wszyscy chłopcy noszą spodnie. W oddali widzisz ucznia idącego do szkoły, widzisz tylko, że na pewno ma spodnie. Jaka jest szansa, że jest to dziewczyna?
Odpowiedź można uzyskać z reguł Bayesa. Sytuację tą przenosimy na detekcję skóry...

Twarz

Twarz można wykryć używając różnych metod (ja zastosuję tą znaną z bloga). Jest ona obszarem pokrytym skórą (zazwyczaj ;-)), więc może być dla nas źródłem informacji. Zakładamy, że wszystko co jest w obszarze twarzy jest skórą, a wszystko co poza nim, skórą nie jest (ważne jest zatem, aby inne części ciała lub twarze innych osób nie znalazły się w kadrze). Sama ramka nie rozdziela wyraźnie obszaru twarzy od otoczenia. Większą precyzję można uzyskać korzystając z algorytmu watershed. Działa on podobnie do zaznaczania różdżką w popularnych programach graficznych

Wathershed

Za ten algorytm odpowiada metoda

void cvWatershed( const CvArr* image, CvArr* markers );

Pierwszy parametr to kolorowy obraz, a drugi to 32-bitowa macierz. o identycznych jak image rozmiarach. W parametrze markers zapisujemy liczby 1,2,3 ... oznaczające, że dany piksel jest klasy 1.,2.,3. itd a 0 dla pikseli dla których to algorytm ma przydzielić klasę. Po wykonaniu funkcji w parametrze markers piksele będą miały już tylko wartości klas bądź -1 dla granic pomiędzy klasami. Dzięki temu uzyskamy piksele skóry i pozostałe z większą dokładnością niż prostokątna ramka. Zdarzają się oczywiście przekłamania, ale nic nie jest idealne, a metoda ta zdecydowanie poprawia uzyskiwane wyniki. Piksele klasyfikujemy przez kilkadziesiąt klatek a dane zbieramy do histogramów

Histogram

Potrzebne są dwa trójwymiarowe histogramy, jeden dla skóry i jeden dla pozostałych pikseli. Każdy z wymiarów odpowiada kanałowi obrazu kolorowego. Rozmiar każdego z wymiarów może być 256 co dopowiada wszystkim dopuszczalnym wartościom, ale lepiej sprawuje się mniejsza liczba wymiarów np. 64. Wówczas minimalne różnice nie wpływają aż tak na wynik, a uzyskany model skóry jest bardziej ogólny. Histogramy następnie normalizujemy i używamy w kolejnych klatkach do klasyfikowania czy dany piksel jest skórą czy nie.

Metoda jest szybka, wymaga jedynie wstępnego procesu "uczenia". Gdy zmienią się warunki oświetleniowe najlepiej algorytm rozpocząć od nowa. Poniżej wspomniane obrazy wynikowe

Uczenie:

Mapa prawdopodobieństwa:

Próg 30% (piksele o prawdopodobieństwie bycia skórą 30% i wyższej)

Próg 60%

Próg 90%

Kod dostępny jest na GitHubie. Program ma kilka parametrów opcjonalnych, wypisują się one w konsoli. Aby rozpocząć uczenie należy nacisnąć klawisz 'n'. Najlepiej poczekać chwilę, aż ustabilizuje się obraz. Później widzimy jak zaznaczane są kolejne obszary twarzy a na końcu widzimy działanie algorytmu dla kolejnych klatek z kamery. Program kończymy klawiszem 'k'.

Brak komentarzy: