In this project I have tried to create tool for gender classification by face photos. The task is split in two subproblems. First - find characteristic points of face using OpenCV. Second - build classifier using collected informations. In my project I have used three types of classifier
Problem, który jest rozwiązywany przez implementację projektu dotyczy rozpoznawania płci na podstawie zdjęcia twarzy.
Mając dane zdjęcie (w formacie *.jpg) chcemy stwierdzić, czy osoba zaprezentowana na tej fotografii jest kobietą, czy mężczyzną.
Zadanie rozpoznawanie płci na podstawie zdjęcia twarzy składa się z dwóch części. Pierwszą jest wykrycie charakterystycznych punktów twarzy
(w moim projekcie - oczy, nos, usta). Drugą częścią jest zastosowanie metod uczenia na wydzielonym zbiorze danych.
W moim projekcie zastosowałem następujące metody uczenia:
W celu rozpoznawania charakterystycznych punktów twarzy wykorzystałem "Open Sourcową" bibliotekę do obróbki zdjęć - OpenCV. Dodatkowo potrzebne były też wyuczone klasyfikatory Haar'a dostępne m.in. na stronie http://alereimondo.no-ip.org/OpenCV/34 .
Wykorzystałem wyuczone klasyfikatory znajdujące prostokąty obejmujące:
Niestety klasyfikatory Haar'a nie zawsze zwracały dokładny wynik. Często zwracały wiele sprzecznych wyników albo nie zwracały w ogóle wyniku. Aby poradzić sobie z tym problemem zastosowałem kilka heurystyk:
Następnie wszystkie punkty przeskalowałem tak, że prostokąt obejmujący twarz miał wymiary 100x100. Na sam koniec dane o znalezionych punktach zapisywałem do bazy w pliku csv.
Zdjęcia przed oznaczeniem:
Zdjęcia o oznaczeniu:
Po znalezieniu charakterystycznych punktów twarzy oraz zapisaniu ich do bazy dzieliłem bazę na dane uczące i testowe (w stosunku 3:1). Następnie wykorzystałem metody uczenia na danych uczących, aby zaklasyfikować dane testowe.
Pierwszą metodą klasyfikacji danych, którą zastosowałem był Naiwny Klasyfikator Bayesa. Metoda ta polega na wykorzystaniu wzoru Bayesa do zaklasyfikowania danych, Wzór Bayesa:
gdzie
W naiwny sposób zakładamy, że zdarzenia są niezależne, zatem:
Na sam koniec, aby zaklasyfikować nieznaną twarz, korzystamy ze wzoru:
Wartość P(C) , to procent danych w bazie uczącej należących do klasy C, a P(F_i | C) - procent danych zaklasyfikowanych jako C mających odpowiednią wartość F_i.
Jako, że w przypadku prezentowanego zadania klasyfikacji zdjęcia twarzy, cechy charakterystyczne nie są wartościami nominalnymi ( mają wartości rzeczywiste) należy wprowadzić do algorytmu jeszcze jedne usprawnienie. P(F_i | C) liczymy w następujący sposób - dzielimy wartości atrybutu F_i z bazy uczącej na równe przedziały. Definiujemy funkcję, która każdą wartość F_i przyporządkowuje odpowiedniemu przedziałowi. P(F_i | C) jest to liczba elementów klasy C, których atrybut F_i należy do tego samego przedziału, co atrybut F_i danych do zaklasyfikowania.
W tym przypadku zadanie klasyfikacji opiera się o wyszukanie k rekordów z bazy, które mają najmniejszą wartość odległości względem danych do zaklasyfikowania. Klasa , do której zaklasyfikujemy dane, to klasa , do której zaklasyfikowana jest większość "sąsiadów".
Funkcja odległości w moim projekcie została zdefiniowana następująco:
Ostatnią metodą klasyfikacji, którą zastosowałem w projekcie, było programowanie genetyczne, czyli algorytmy ewolucyjne na drzewach. Przebieg algorytmu był podobny, jak w algorytmie SGA. Inaczej zostały tylko zdefiniowane operatory mutacji, krzyżowania oraz inaczej został zdefiniowany osobnik.
Osobnikiem było drzewo decyzje. W węzłach pośrednich były zadawane pytania : czy x[i] <= v (czy wartość atrybutu F_i jest mniejsza równa od v).
W węzłach terminalnych była trzymana informacja o klasie, do które powinny być zaklasyfikowane dane (kobieta/mężczyzna).
Krzyżowanie dwóch osobników (dwóch drzew):
Mutacja na drzewach przybierała kilka postaci:
Do implementacji projektu wykorzystałem język programowania Python oraz system operacyjny Ubuntu Linux. Dodatkowo, tak jak wcześniej wspomniałem, do detekcji charakterystycznych cech twarzy i obróbki obrazu wykorzystałem bibliotekę OpenCV dostosowaną do Pythona .
W projekcie wykorzystałem 428 zdjęć (217 zdjęć panów i 211 zdjęć pań) znalezionych w wyszukiwarce grafik Google'a (po wpisaniu haseł: passport, arrest, ID, hairstyle).
Przy wykrywaniu charakterystycznych punktów twarzy wykorzystałem klasyfikatory Haar'a dostępne na stronie http://alereimondo.no-ip.org/OpenCV/34 .
python main.py -f
Szuka punktów charakterystycznych dla wszystkich zdjęć w katalogu './Faces/faces' i zapisuje te informacje w './DataBase/baza.csv'
python main.py -d 0.75
Dzieli plik './DataBase/baza.csv' na dwa pliki './DataBase/learn.csv' i './DataBase/class.csv'. Rekord z pliku 'baza.csv' trafia do pliku 'learn.csv' (baza wykorzystana do uczenia) z prawdopodobieństwem 75%. Reszta rekordów trafia do bazy 'class.csv' (baza wykorzystana do testów).
python main.py -a 'NBC,200' -c 'test,_'
Klasyfikowane są dane z pliku 'class.csv' przy użyciu Naiwnego Klasyfikatora Bayesa z podziałem na 200 grup. NBC wykorzystuje dane z pliku 'learn.csv'.
Przykładowy wynik:
(Poprawne, wszystkie) Współczynniki poprawności
(67, 125) 0.536
python main.py -a 'NN,5' -c 'test,_'
Przykładowy wynik:
(Poprawne, wszystkie) Współczynniki poprawności
(87, 125) 0.696
python main.py -a 'EVO,The Best' -c 'test,_'
Przykładowy wynik:
(Poprawne, wszystkie) Współczynniki poprawności
(107, 125) 0.856
python main.py -a 'EVO,The Best' -c 'clas,55.jpg'
Klasyfikuje zdjęcie twarzy z pliku '55.jpg'
Przykładowy wynik:
Szukanie charakterystycznych punktów
Klasyfikacja
male
Testy przeprowadzono w następujący sposób - dzielono bazę na dane uczące i testowe według współczynnika podziału. Do zbioru uczącego trafiało losowe t% danych, a do danych testowych (100-t)% . Następnie sprawdzano procent poprawnych odpowiedzi udzielonych przez odpowiednią metodę na zbiorze testowym z wykorzystaniem do nauki danych uczących. Oto otrzymane wyniki
Procent podziału | NBC 10 | NBC 50 | NN 5 | NN 21 | EVO 1 | EVO 2 | EVO 3 |
25% | 0.708 | 0.506 | 0.720 | 0.630 | 0.863 | 0.813 | 0.658 |
50% | 0.726 | 0.585 | 0.726 | 0.722 | 0.863 | 0.799 | 0.722 |
75% | 0.704 | 0.612 | 0.724 | 0.744 | 0.867 | 0.846 | 0.744 |
Przeprowadziłem jeszcze jeden test. Spośród 428 zdjęć wyselekcjonowałem 100 (50 mężczyzn, 50 kobiet), które zostały najprecyzyjniej oznaczone (charakterystyczne punkty twarzy zostały dokładnie oznaczone). Następnie wykorzystałem Naiwny Klasyfikator Bayesa do klasyfikacji. Współczynniki przy NBC podzieliłem przez cztery. Oto wyniki:
Procent podziału | NBC 3 | NBC 13 |
25% | 0.75 | 0.63 |
50% | 0.85 | 0.72 |
75% | 0.88 | 0.71 |
Względnie niski współczynnik poprawności przetestowanych metod może wynikać ze słabej dokładności klasyfikatorów Haar'a przy rozpoznawaniu charakterystycznych punktów twarzy. Wyselekcjonowanie 100 najprecyzyjniej oznaczonych zdjęć zdaje się potwierdzać tą tezę . Niestety nie udało mi się znaleźć innego darmowego, skutecznego, łatwo dostępnego narzędzia do znajdowania charakterystycznych punktów twarzy. Inne (komercyjne lub mniej precyzyjne) narzędzia to np. VeriLook, FaceCropper, faceAPI, Betaface.
Niski współczynnik poprawności może też wynikać z trudności zadania. Pomimo wyselekcjonowania 100 zdjęć, klasyfikator Bayesa nie przekroczył skuteczności 90%.