KursyPoradnikiInspirujące DIYForum

OpenCV – #3 – Detekcja i rozpoznawanie twarzy

OpenCV – #3 – Detekcja i rozpoznawanie twarzy

W tej części zajmiemy się detekcją twarzy w OpenCV. Za pomocą funkcji, które dostarcza nam biblioteka możemy zrobić to w prosty sposób.

Dodatkowo możemy wykryć szereg innych cech takich jak oczy, usta, nos, uszy itp.

« Poprzedni artykuł z seriiNastępny artykuł z serii »

Na początek napiszemy prosty program, który będzie wykrywał twarz, później zajmiemy się rozpoznawaniem jej na obrazach. Postaram się także wytłumaczyć w jaki sposób można budować własne bazy twarzy, które posłużą nam do trenowania naszego programu. Dodatkowo w trakcie kursu pojawi się kilka nowych funkcji, służących do przetwarzania obrazów. Zaczynamy!

Detekcja twarzy

Na pierwszy ogień pójdzie prosty program, którego jedynym zadaniem jest wykrycie twarzy na wczytanym z pliku obrazku. Dzięki temu zobaczymy jakie to proste w OpenCV i szybko załapiemy o co chodzi, bez zbędnego przebijania się przez tony kodu. Program następnie rozbudujemy tak by wygrywał bardziej szczegóły obiekty twarzy.

Należy umieścić obrazek z twarzą w folderze głównym programu. Zmieniając łańcuch można dostosować nazwę wczytywanego pliku do własnych potrzeb.

Efekt działania programu:

Efekt działania programu.

Efekt działania programu.

Żeby dobrze zrozumieć, o co chodzi w naszym programie, wypada opisać pokrótce metodę, której używa OpenCV do wykrywanie twarzy. Metoda ta wykorzystuje do wykrywanie obiektów klasyfikator kaskadowy „Haar Feature-based Cascade Classifier”.

Aby móc wykrywać obiekty takie jak twarz, nos, usta należy wytrenować taki klasyfikator. Nie musimy jednak tego robić sami, gdyż openCV dostarcza kilka gotowych, wytrenowanych już klasyfikatorów zapisanych w postaci plików xml.

Trenowanie klasyfikatora odbywa się poprzez dostarczenie kilkuset różnych próbek, na których znajduję się dany obiekt np. twarz, samochód, wyskalowanymi do tego samego rozmiaru, powiedzmy 50x50. Po wytrenowani klasyfikatora możemy przeszukiwać nasz obraz.

Bierzemy pewien wycinek obrazu taki sam jak rozmiar próbek przy trenowaniu, czyli np. 50x50 i skanujemy cały obraz. Funkcja zwraca 1 jeżeli wycinek obrazu z dużym podobieństwem przedstawia wyszukiwany obiekt (np. twarz) i 0 w przeciwnym przypadku.

Klasyfikator jest tak zaprojektowany by łatwo było go przeskalować co pozwala na znajdowanie obiektów bez względu na ich rozmiary i jest szybsze niż przeskalowywanie obrazu na którym przeprowadzamy detekcje obiektów. Więc, aby znaleźć obiekty o nieznanych wymiarach należy powtórzyć procedurę skanowania obrazu kilkakrotnie.

Z powyższego wynika, że aby móc wykrywać obiekty musimy dysponować wytrenowanym klasyfikatorem, w tym kursie skorzystamy z gotowych, wytrenowanych już klasyfikatorów dostarczonych wraz z biblioteką OpenCV.

Potrzebne pliki odnajdujemy, przechodząc do folderu w którym zainstalowaliśmy OpenCV i kolejno przez foldery data/haarcascades. Widzimy kilka dostępnych klasyfikatorów w formie plików .xml. Do wykrycia twarzy możemy wykorzystać plik haarcascade_frontalface_alt.xml.

W programie nazwę pliku mamy zapisaną w zmiennej:

Następnie tworzymy obiekt, klasyfikatora:

W funkcji main() wczytujemy zawartość pliku z klasyfikatorem do naszego obiektu:

Następnie wywołujemy funkcję wykrywającą twarz na obrazie:

Z racji że możemy na jednym obrazie znaleźć więcej niż jedną twarz, dane o nich będziemy przechowywać w wektorze kwadratów. Zostaną do niego wpisane współrzędne kwadratów otaczających twarze na obrazie.

Następnie konwertujemy nasz obraz wejściowy do odcieni szarości, gdyż zmniejszona liczba kolorów nie przeszkadza w rozróżnieniu twarzy na obrazie, ani nam ani komputerowi, a znacznie przyspiesza obliczenia.

Następnie, mamy metodę, gwóźdź programu. Odwala ona za nas "brudną robotę" i wykrywa twarz na obrazie. Jako argumenty podajemy obraz, na którym ma być szukany obiekt. Z racji, że funkcja zwraca wynik w postaci kwadratów otaczających miejsca na obrazie, w których znajdują się twarze, kolejnym argumentem jest wektor kwadratów.

Dalsze parametry określają o ile będzie skalowany obszar przeszukiwania przy kolejnych skanowaniach. Na koniec podajemy minimalny rozmiar twarzy, można dodać jeszcze jeden argument określający maksymalny możliwy rozmiar twarzy.

Następna funkcja rysuje kwadraty otaczające twarze na obrazku.

To by było na tyle.

Zaznaczanie ust, nosa i oczu

Teraz możemy nieco rozbudować nasz program, aby oprócz twarzy wykrywał usta, nos oraz oczy. Jest to zadanie bardzo proste i sprowadza się właściwie do wczytania kilku innych plików .xml z klasyfikatorami dla oczu, uszu i nosa. Na początek powinniśmy skopiować te pliki tak jak poprzednio z data/haarcascades do folderu z naszym programem. Poniżej zamieszczam kod:

Myślę, że większa część kodu nie nastarcza problemów, gdyż jest to właściwie powtarzanie tych samych czynności, co przy wykrywaniu twarzy.

Wczytujemy pliki z klasyfikatorami dla poszczególnych obiektów, sprawdzamy poprawność odczytu danych. Następnie przechodzimy do detekcji. Najpierw wykrywamy całą twarz. Potem tworzymy miejsce na kwadraty otaczające oczy, nos, usta.

Jak widać program nie jest optymalny, biorąc pod uwagę, że ludzie mają nos i usta w liczbie jeden. Jednakowoż lepiej utworzyć wektor, w razie gdyby np. komputer pomylił się i wykrył nam oczy jako usta, co się zdarza, albo badany miał szminkę odbitą na twarzy, co też się czasem zdarza.

W naszym programie na uwagę zasługuje poniższy fragment, za pomocą tej instrukcji tworzymy nowy obrazek, jest on mniejszy niż oryginał, a przedstawia wycięta z obrazu wykrytą twarz, pozwala to zoptymalizować wyszukiwanie oczu itp. gdyż będziemy ich od tej chili szukać w obrębie wykrytych twarzy.

OpenCV - Wykrycie oczu

Poniższy kod wykrywa oczy, metoda ta sama, co w przypadku wykrywania twarzy tyle, że wykorzystujemy kaskadę dla oczu. Następnie w pętli przechodzimy przez wszystkie wykryte oczy, normalnie dwa, i obrysowujemy je kwadratami.

W funkcji:

Musimy przesunąć kwadrat do współrzędnych twarzy, gdyż obraz, na którym wykrywamy oczy jest wycinkiem oryginalnego obrazu zawierającym tą jego część na której wykryto twarz. Musimy więc do współrzędnych wyrycia oczu dodać współrzędne wykrycia twarzy, aby wszystko było na sowim miejscu.

OpenCV - wykrycie ust

Przy wykrywaniu ust okazało się, że były one także wykrywane w miejscu oczu, ze względy na kształt powiek. Aby uniknąć takich pomyłek, mając na uwadze, że usta umiejscowione są w obszarze dolnej połowy twarzy, będziemy szukać ich na obrazku, który będzie wycinkiem dolnej połowy twarzy:

Dlatego też przy ustalaniu współrzędnych kwadratu otaczającego usta powinniśmy wprowadzić odpowiednie przesunięcie.

OpenCV - Wykrycie nosa

Na koniec wykrywamy nos, którego szukamy także w dolnej części twarzy.

Program oprócz obrazu, na który zaznaczone są poszczególne obiekty, wyświetla również, obrazki będące wycinkami twarzy oraz jej dolnej części. Efekt działania jest następujący:

opencv_twarz2

Efekt działania programu.

OpenCV - Rozpoznawanie twarzy

Teraz, kiedy potrafimy już wykryć twarze, możemy przystąpić do ich rozpoznawania. Choć temat wydaje się być o wiele bardziej skomplikowany, w OpenCV można go również prosto rozwiązać, dlatego że od wersji 2.4 mamy zaimplementowane funkcję wykonującą najcięższą robotę za nas.

Jak już wspomniałem od wersji 2.4 w OpenCV dostępna jest klasa FaceRecognizer, wspomagająca tworzenie aplikacji rozpoznających twarze.

Zaimplementowano w niej metody służące do trenowania algorytmu za pomocą bazy danych z twarzami, przewidywania (odgadywania) największego podobieństwa rozpoznawanej twarzy do tych z bazy danych, ładowania/zapisywania wytrenowanego modelu do pliku XML lub YAML. Obecnie biblioteka dysponuje, aż 3 różnymi algorytmami rozpoznawania twarzy:

  • Eigenfaces
  • Fisherfaces
  • LBPH

Bez zbędnego wnikania w działanie algorytmów, gdyż nie jest to celem tego kursu, postaram się pokazać jak można w praktyce rozpoznawać twarze w OpenCV. Postaram się to zilustrować prostym przykładem, tak aby zrozumienie najważniejszych jego części nie nastarczyło problemów.

Będzie to jedynie wprowadzenie do rozpoznawania twarzy. Być może natchnie ono kogoś by wgryźć się głębiej w problem. Po dodatkowe informacje odsyłam do dokumentacji OpenCV 2.4, gdzie można znaleźć przydatne linki i przykładowe programy, ten kurs bazuje zresztą na informacjach tam zawartych. Kod programu:

Zanim uruchomimy program powinniśmy dysponować bazą danych z twarzami, za pomocą której będziemy trenować naszą klasę FaceRecignizer. Taką bazę danych możemy pobrać ze strony w postaci archiwum .zip/.tar.

Następnie przechodzimy do folderu z naszym programem, tworzymy folder powiedzmy „orl_faces” i rozpakowujemy do niego pobrany plik, możemy zobaczyć w jaki sposób zorganizowana jest taka baza. Jest podzielona na foldery, w każdym z nich znajduje się po 10 zdjęć tej samej osoby. Różniących się min. oświetleniem, kątem skierowania twarzy itp.

Dla celów naszego programu wystarczy, jeśli zostawimy 5 pierwszych folderów s1-s5, pozostałe można usunąć. Następnie w każdym z folderów usuwamy 4 ostatnie zdjęcia tak by zostały pliki 1-6. Pięć pierwszych plików z każdego folderu będzie tworzyć dane do trenowania, szósty plik należy wyciąć z folderu i skopiować go do folderu głównego z naszym programem, zmieniając jego nazwę na test1 dla s1, test2 dla s2 itd. za ich pomocą sprawdzimy poprawność działania programu.

Mając tak spreparowaną bazę danych musimy znaleźć jakiś sposób na jej „automatyczne” wczytywanie do naszego programu. Użyjemy do tego pliku csv, plik ten będzie miał następującą budowę:

Jak widać, pojedyncza linia składa się ze ścieżki do pliku z obrazkiem oraz nr klasy do której należy obrazek, jego etykiety. Etykiety są po to by wskazać, że dana grupa obrazków (5 w tym przypadku) z jednego folderu reprezentuje twarz tej samej osoby.

Każdej osobie przypisywana jest numer, kiedy mamy już wytrenowany model i podajemy do niego obrazek w celu rozpoznania twarzy, metoda predykcji zwróci nam numer. Porównując go z poszczególnymi etykietami możemy stwierdzić, że dana twarz należy do tej lub innej osoby z bazy.

Z względy na to, że pojedyncza linia zawiera ścieżkę do pliku z obrazkiem w bazie danych, a ścieżki te będą się różnić na różnych komputerach, każdy musimy samemu wygenerować u siebie taki plik. Można to zrobić ręcznie, nie jest jednak to najlepszy pomysł.

Lepiej wykorzystać do tego skrypt, który zrobi to za nas. Można znaleźć go na stronie z dokumentacją OpenCV. Skrypt napisany jest w Python'ie:

Jest to wersja skryptu dla Python'a 3.0 (lub wyższej), na stronach dokumentacji OpenCV można znaleźć skrypty dla starszych wersji.

Aby uruchomić skrypt należy przejść do folderu z naszą bazą danych, zapisać go tam jako create_csv.py otworzyć cmd, przejść do folderu z naszym skryptem i wywołać go komendą

python create_csv.py C:\Users\ja\workspace\Face_Recognizer\orl_faces

Gdzie zamiast „C:\Users\ja\workspace\Face_Recognizer\orl_faces” podajemy nasz własny link do bazy danych. Po wykonaniu skryptu zostanie wygenerowana w konsoli zawartość pliku csv dla naszej bazy danych, należy ją zaznaczyć, skopiować i zapisać z rozszerzenie .csv np. „face.csv”.

Na początku zajmiemy się funkcją read_csv. Funkcja ta wczytuje utworzony wcześniej plik csv w moim przypadku face.csv. Następnie z pliku pobierane są ścieżki do kolejnych obrazków oraz ich etykiety. Obrazki są wczytywane z plików i umieszczane w wektorze images natomiast odpowiadające im etykiety umieszczane są w wektorze labels.

Czas na funkcję main, w której na początku wczytujemy obrazek z twarzą, którą postaramy się rozpoznać. Następnie tworzymy klasę rozpoznającą twarz, przy użyciu algorytmu Eigenface, później trenujemy klasę przekazując jako parametry wektory z danymi uczącymi.

W kolejnym kroku dokonujemy już właściwego rozpoznania twarzy za pomocą metody predict, do której przekazujemy obraz z twarzą którą chcemy rozpoznać. Jako wynik zwrócona zostanie liczba odpowiadająca etykiecie zbiorowi obrazków twarzy jednej z osób, która zgodnie z algorytmem wykazuje największe podobieństwo do testowanej.

Tzn. jeżeli np. zwróconą liczbą będzie 1 to znaczy, że zgodnie z algorytmem testowana twarz należy do osoby z folderu s2 gdyż wszystkie obrazki z tego folderu mają etykietę 1

C:\Users\ja\workspace\Face_Recognizer\orl_faces\s2/1.pgm ; 1

W dalszej części programu znajdziemy jeszcze kod odpowiedzialny z pokazanie wszystkich obrazków. Kolejne zdjęcia oglądamy naciskając spację.

Efekt działania jest następujący, po lewej mamy obrazek testowy, po prawej odpowiedź programu, czyli jeden z obrazków z bazy danych tej osoby którą komputer uważa za właściciela twarzy testowej. Przewijając spację możemy podglądać pozostałe obrazy twarzy tej osoby w bazie. Oto wynik działania dla dwóch obrazów testowych.

W powyższym przykładzie używaliśmy plików z jednej bazy danych. Miały one takie same rozmiary i liczbę kanałów. Jednak w większości przypadków, rozmiary obrazków są różne, dzieje się tak np. wtedy gdy w bazie danych mamy próbki uczące o rozmiarach załóżmy 200x200, a twarz chcemy rozpoznawać na obrazie przechwytywanym z kamery. Wówczas można posłużyć się opisaną już wcześniej metodą detekcji twarzy i jako obraz testowy podawać do metody predict wycinek obrazu kamery, ograniczony do wykrytej twarzy.

W taki wypadku, wycinek może mieć różne rozmiary w zależności od tego jak daleko od kamery znajduje się osoba. Aby zapewnić poprawne działanie programu i uniknąć błędów powinniśmy więc odpowiednio przeskalować nasz wycinek twarzy oraz dokonać odpowiedniej konwersji kolorów, gdyż obrazy trenujące i testowe muszą być ze sobą zgodne. Konwersji dokonujmy funkcją:

Gdzie parametrami są, obrazek skalowany, obrazek wynikowy, rozmiar obrazka po skalowaniu. Następnie podajemy pewne współczynniki skalowania, na koniec podajemy metodę interpolacji.

Na koniec zamieszczam prosty program, który może okazać się pomocny przy tworzeniu własnej bazy z twarzami.

Działanie programu jest następujące, należy dostarczyć dla niego plik z klasyfikatorem dla twarzy, oraz bazę zdjęć. Zdjęcia mogą mieć dowolne rozmiary. Podobnie jak wcześniej należy utworzyć plik csv przy użyciu tego samego skryptu pythona, postępując analogicznie jak przedtem.

Obrazy każdej z osób powinny być zgrupowane w osobnych folderach. Po wygenerowaniu plik csv powinniśmy umieścić go tam gdzie znajduje się nasz program główny. Po uruchomieniu programu, będą wczytywane kolejne zdjęcia i konwertowane do rozmiarów ustalonych w zmiennych.

Wciskając spację przechodzimy przez kolejne zdjęcia, które będą pokazywać się nam w przeskalowanej formie, w tym samym czasie przeskalowane zdjęcia będą zapisywane w folderze z programem pod takimi samymi nazwami jakie miały oryginały.

Należy więc pamiętać by nie nadawać zdjęciom w różnych folderach takich samych nazw bo potem będą się nawzajem nadpisywać, najlepiej nazywać je zgodnie z regułą nazwiskoosoby_nr.

Podsumowanie - OpenCV i wykrywanie twarzy

Mam nadzieję, że ten artykuł rozjaśnił co nieco w kwestii rozpoznawania i detekcji twarzy. W kolejnych częściach serii zajmiemy się segmentacją skóry, spróbujemy poszukać lepszych metod wykrywanie obiektów po kolorach.

Postaram się też w miarę możliwości przedstawić sposób rozpoznawania pisma przy użyciu OpenCV. Tymczasem odsyłam do dokumentacji: http://opencv.itseez.com/index.html

Gdyby ktoś utkną przy tworzeniu bazy z twarzami albo modyfikacji tej ze strony AT&T to proszę dać znać w komentarzach, postaram się pomóc.

« Poprzedni artykuł z seriiNastępny artykuł z serii »

detekcja, kurs, obraz, OpenCV, rozpoznawanie, twarze

Trwa ładowanie komentarzy...