Wykrywanie twarzy na zdjęciach przy pomocy kaskad Analiza i przetwarzanie obrazów Sebastian Lipnicki Informatyka Stosowana,WFIIS
Spis treści 1. Wstęp... 3 2. Struktura i funkcjonalnośd... 4 3. Wyniki... 6 4. Podsumowanie... 11 2
1. Wstęp Zadaniem projektu było stworzenie aplikacji która pozwala wykryd twarz na zdjęciach. Aplikacja została napisana w języku Java oraz wykorzystuje już istniejące kaskady stworzone dla biblioteki opencv która jest napisana w języku C++. Program przetwarza wspomniane kaskady zapisane w plikach XML w celu pobrania istotnych danych (cech twarzy), a następnie wykorzystuje je w analizie zdjęcia pobranego na wejściu a następnie wykrywa miejsca w których znajduje się twarz. Kaskady zawarte w plikach XML zostały stworzone przez projekt opencv na podstawie wielu danych testowych (twarzy). Każda testowa twarz została przeanalizowana w celu wyciągnięcia ciemniejszych i jaśniejszych miejsc. Wartości jasności tych obszarów (progi kolorów szarości dla których obszar spełnia wymagania) jak i same obszary zostały zapisane w tym pliku XML. Na podstawie wielu takich próbek testowych, kaskada potrafi dokładnie wydedukowad jak powinna wyglądad twarzy, tj. posiada informacje jakie obszary względem jakich są jaśniejsze lub ciemniejsze oraz zna progi koloru jakie powinny spełniad te obszary aby można było nazwad je twarzą. Taka kaskadę zastosowano do implementacji tego projektu. Szczegóły tej implementacji kaskad można znaleźd na stronie: http://docs.opencv.org/master/d7/d8b/tutorial_py_face_detection.html 3
2. Struktura i funkcjonalność Program został podzielony na 2 główne moduły: HaarFaceDetector klasa zajmująca się parsowaniem pliku XML w celu mapowania pliku XML zawierającego dane na temat twarzy do pamięci aplikacji. Wykorzystuje zewnętrzną bibliotekę jdom w celu poruszania się po pliku XML. W momencie tworzenia otrzymuje jako parametr nazwę do pliku XML który w momencie konstrukcji parsuje. FaceDetector klasa dziedzicząca po klasie HaarFaceDetector. Zajmuje się obróbką zdjęcia, tj. zaznaczeniem zielonych prostokątów na zdjęciu w których się znajdują twarze. Dodatkowo zostały dodane 4 klasy modelowe które przetrzymują cała strukturę i dane z kaskady pliku XML: FeatureTester jeden test na rozpoznanie twarzy z pliku XML Segment klasa przechowująca wierzchołki prostokąta (fragmentu twarzy) któremu dany test odpowiada FeatureContainer pojemnik na testy Node pojedyncza testowana cecha która składa się z progu oraz kilku segmentów których dotyczy Została stworzona również klasa Main jako inicjator aplikacji. Ścieżkę do zdjęcia wejściowego można wysład przy pomocy parametru wywołania programu. Struktura pliku XML (kaskady) wygląda następująco: SizeX SizeY (najmniejsza ilośd pikseli która trzeba analizowad dla tej kaskady) FeatureTests*+ (zbiór testów) o FeatureTest (jeden z testów) Features[] (zbior cech) Feature. o FeatureTest Feature (pojedyncza cecha) o Segment*+ (zbiór prostokątów) o Treshold 4
Każda z cech z całego pliku XML musi przejśd test poprawnie aby twarz została wykryta. Jeżeli dany fragment zdjęcia zostaje poddane analizie, to dla każdego testera cech (FeatureTester) zostaje sprawdzona każda cecha na tym obszarze. Jeżeli dany fragment zdjęcia przejdzie poprawnie wszystkie testy, ten fragment zostaje obramowany zielona ramką na głównym zdjęciu (wykryto twarz). Sprawdzenie danej cechy jest robione na zasadzie pobraniu części analizowanego fragmentu zdjęcia, którego wielkośd wyznacza wartości Segmentu tej cechy (cecha posiada kilka segmentów których dotyczy) a następnie wyznaczenie średniej wartości kolor szarości na tym obszarze. Jeżeli ta średnia wartośd jest powyżej wartości Treshold (cecha posiada wartośd Treshold która wyznacza próg powyżej jakiego obszar jest definiowany jako pozytywny), to ten segment jest oznaczony jako pozytywny. Wszystkie segmenty muszą byd pozytywne aby test dla tej cechy był pozytywny. Natomiast wszystkie testy posiadające cechy muszą byd pozytywne, aby założyd, że na tym obszarze znajduje się twarz. Aby aplikacja analizowała poprawnie duże i małe obrazy został zaimplementowany specjalny mechanizm do wyznaczania wielkości analizowanych fragmentów obrazu. Na początku obraz zostaje podzielony na małe prostokąty o najmniejszym możliwym do przeanalizowania obszarze które wyznacza kaskada (w pierwszym wierszu jako sizex i sizey). Każdy taki obszar jest poddawany testom w celu wykrycia twarzy. Dzięki temu nawet na bardzo dużym obrazku na którym znajduje się wiele małych twarzy, zostanie wykryta twarz gdyż bardzo małe obszary są analizowane. Następnie taki obszar zostaje powiększony o 10% poprzednio analizowanego obszaru oraz zostaje ponownie poddany analizie twarzy. Twarze wykryte w każdym etapie działania aplikacji zostają automatycznie nałożone na kopie oryginalnego obrazu. Obszar jest powiększany aż do osiągnięcia maksymalnej wielkości badanego obszaru, tak, że większy obszar wykroczyłby poza rozmiary zdjęcia. Obszar jest zwiększany multiplikatywnie, a nie addytywnie, w celu osiągnięciu lepszego czasu wykonania programu przy znikomej utracie jakości wykrywania twarzy. Przy wielokrotnej analizie jednego zdjęcia jest możliwośd, że dana twarz zostanie wykryta kilka razy (w różnych etapach). Aby zapobiec temu, został zaimplementowany system który usuwa zaznaczone prostokąty które są zbyt 5
blisko siebie, oraz zostawia najmniejszy z tych wszystkich. Dzięki temu otrzymamy tylko najbardziej dopasowany prostokąt zawierający daną twarzy. Prostokąty mogą na siebie nachodzid (w przypadku gdy dwie twarze są rzeczywiście blisko siebie) jednakże ich wspólna powierzchnia nie może byd większością jednego ze zdjęd. Dzięki temu otrzymujemy jeden prostokąt dla jednej twarzy. 3. Wyniki Przykładowe wyniki dla pojedynczych twarzy Czas szukania twarzy: 28,960 sekund (w C++ 3,12s) Czas szukania twarzy: 26,599 sekund (w C++ 2,32s) 6
Czas szukania twarzy: 14,601 sekund (w C++ 1,93s) Czas szukania twarzy: 25,480 sekund (w C++ 2,48s) 7
Przykładowe wyniki dla wielu twarzy Czas szukania twarzy: 22,928 sekund (w C++ 3,81s) Czas szukania twarzy: 30,104 sekund (w C++ 4,14s) 8
Czas szukania twarzy: 20,395 sekund (w C++ 3,54s) Czas szukania twarzy: 11,441 sekund (w C++ 0.89s) Czas szukania twarzy: 60,956 sekund (w C++ 8,31s) 9
Czas szukania twarzy: 51,066 sekund (w C++ 5,76s) Czas szukania twarzy: 24,123 sekund (w C++ 4,03s) Jak widad z otrzymanych wyników, czas wyszukiwania twarzy tym samym algorytmem napisanym w języku C++ i Java dają różne czasy wyszukiwania twarzy. Algorytm działa znacznie szybciej w języku C++. Czas trwania jest również w dużym stopniu zależny od wielkości obrazka. Widad również, że aplikacja ma problem z ludźmi o ciemniejszej karnacji skóry. 10
4. Podsumowanie Jak widad z otrzymanych wyników aplikacja poprawnie wykrywa twarze na zdjęciach. Dzięki zastosowaniu odpowiedniej metody do fragmentacji zdjęcia otrzymujemy aplikacje która wykrywa twarze w dośd krótkim czasie. Ten czas zależy w dużym stopniu od wielkości zdjęcia jednakże nawet dla dużych zdjęd nie trzeba długo czekad aby wykryd twarz. Dzięki systemowi do zapobiegania kilkukrotnemu wykrywaniu tych samych twarzy, nigdy nie ma sytuacji w której jedna twarz zostaje zaznaczona wiele razy oraz zawsze zaznaczony prostokąt jest jak najbardziej przylegający do twarzy. Niektóre twarze nie zostają rozpoznane ze względu na różne atrybuty które posiadają (okulary, nakrycia głowy), mimikę twarzy która za bardzo zmienia całkowity wizerunek twarzy oraz zbyt mocny makijaż (zmiana koloru skóry). Jednakże dla większości zdjęd aplikacja działa poprawnie oraz dobrze znajduje twarze na zdjęciu. Aplikacja również wykrywa twarze gdy zdjęcie jest rozmyte. 11