Detekcja twarzy jest obecnie powszechnie wykorzystywana (np. w ustawianiu ostrości aparatów cyfrowych). Gdy dowiemy się gdzie na obrazie znajdują się twarze, możemy wykonać wiele ciekawych operacji. Najpierw jednak musimy je znaleźć :) Za proces ten w OpenCV odpowiadna jedna funkcja... Kod:
Powyższy kod to modyfikacja z jednego z wcześniejszych wipsów. Na uzyskany z kamery obraz dokładane są prostokąty zaznaczające twarze.
Parę słów komentarza do kodu: pierwsza sprawa to plik xml z danymi z treningu. Plik ten zawiera dane do klasyfikatora cech Haara. Same klasyfikatory to dość rozbudowana dziedzina związana ze sztuczną inteligencją. Nas interesuje to, że klasyfikator zbudowany w oparciu o dany plik pozwoli nam wykryć twarze skierowane frontalnie do kamery. Użycie innego pliku pozwoli nam wykryć np. twarze uchwycone z profilu czy ludzką postać. W kolejnych wersjach biblioteki ma pojawić się ich więcej. Można je znaleźć w odpowiednim katalogu OpenCV.
Przygotowanie obrazu przed detekcją. Detekcja twarzy odbywa się w różnej skali, co pozwala znaleźć twarze ludzi zarówno bliżej jak i dalej obiektywu. Sam proces jest dość złożony. Podanie do wykrywania mniejszego obrazu powoduje znaczne przyspieszenie detekcji, przy niewielkim spadku jego skuteczności (jednak z utratą możliwości wykrywania mocno oddalonych twarzy). Podobnie jest z zamianą kolorów na skalę szarości.
Najważniejszym aspektem w detekcji frontalnych twarzy są oczy. Kiedy jedno oko jest przysłonięte, twarz w większości przypadków nie powinna zostać wykryta. Można też pobawić się w drugą stronę i "spreparować" twarz jak na filmiku ;-)
Zachęcam do modyfikacji parametrów. U mnie, niestety, szybkość nie powala, ale nad tym jeszcze popracuję :)
CvCapture* vid = cvCreateCameraCapture(0); cvNamedWindow("detekcja twarzy", CV_WINDOW_AUTOSIZE); cvQueryFrame(vid); double fps = 25; int odstep_miedzy_klatkami = 1000 / fps; // kolory do zaznaczania twarzy static CvScalar kolory[] = { {{19.0,69.0,139.0,0.0}}, {{63.0,133.0,205.0,0.0}}, {{96.0,164.0,244.0,0.0}}, }; // deklarujemy pamiec na obliczenia CvMemStorage * storage = cvCreateMemStorage(0); // tworzymy klasyfikator // jako agrument musimy podac siezke do pliku z efektem treningu klasyfikatora CvHaarClassifierCascade * haar = (CvHaarClassifierCascade*) cvLoad("/usr/local/share/opencv/haarcascades/haarcascade_frontalface_alt.xml"); while (true) { IplImage* ramka = cvQueryFrame(vid); if (ramka == 0) break; // czyscimy bufor cvClearMemStorage(storage); // skala double skala = 1.5; // przygotowujemy obrazy posrednie IplImage *temp = cvCreateImage(cvSize(ramka->width, ramka->height), 8, 1); IplImage *temp2 = cvCreateImage(cvSize(cvRound(ramka->width / skala), cvRound(ramka->height / skala)), 8, 1); // zamieniamy kolory na skale szarosci cvConvertImage(ramka, temp, CV_BGR2GRAY); // zmniejszamy czarno-bialy obraz cvResize(temp, temp2, CV_INTER_LINEAR); // szukamy twarzy w danej ramce CvSeq *wynik = cvHaarDetectObjects(temp2, haar, storage, 1.1, 3, CV_HAAR_DO_CANNY_PRUNING, cvSize(30,30)); // iterujemy po wszystkich wynikach for (int i = 0; i < (wynik ? wynik->total : 0); i++) { // pobieramy prostokat z pozycja wskazujaca twarz CvRect * twarz = (CvRect*) cvGetSeqElem(wynik, i); // ustalamy dwa punkty po przekatnej prostokata CvPoint punkt1 = cvPoint(cvRound(twarz->x * skala),cvRound(twarz->y * skala)); CvPoint punkt2 = cvPoint(cvRound((twarz->x + twarz->width)* skala),cvRound((twarz->y + twarz->height) * skala)); // rysujemy prostokat zaznaczajacy twarz na obrazie cvRectangle(ramka,punkt1,punkt2,kolory[i%3],2); } cvShowImage("detekcja twarzy", ramka); cvReleaseImage(&temp); cvReleaseImage(&temp2); int c = cvWaitKey(odstep_miedzy_klatkami); if (c == 'k') break; } cvReleaseHaarClassifierCascade(&haar); cvDestroyAllWindows(); cvReleaseCapture(&vid);
Powyższy kod to modyfikacja z jednego z wcześniejszych wipsów. Na uzyskany z kamery obraz dokładane są prostokąty zaznaczające twarze.
Parę słów komentarza do kodu: pierwsza sprawa to plik xml z danymi z treningu. Plik ten zawiera dane do klasyfikatora cech Haara. Same klasyfikatory to dość rozbudowana dziedzina związana ze sztuczną inteligencją. Nas interesuje to, że klasyfikator zbudowany w oparciu o dany plik pozwoli nam wykryć twarze skierowane frontalnie do kamery. Użycie innego pliku pozwoli nam wykryć np. twarze uchwycone z profilu czy ludzką postać. W kolejnych wersjach biblioteki ma pojawić się ich więcej. Można je znaleźć w odpowiednim katalogu OpenCV.
Przygotowanie obrazu przed detekcją. Detekcja twarzy odbywa się w różnej skali, co pozwala znaleźć twarze ludzi zarówno bliżej jak i dalej obiektywu. Sam proces jest dość złożony. Podanie do wykrywania mniejszego obrazu powoduje znaczne przyspieszenie detekcji, przy niewielkim spadku jego skuteczności (jednak z utratą możliwości wykrywania mocno oddalonych twarzy). Podobnie jest z zamianą kolorów na skalę szarości.
Najważniejszym aspektem w detekcji frontalnych twarzy są oczy. Kiedy jedno oko jest przysłonięte, twarz w większości przypadków nie powinna zostać wykryta. Można też pobawić się w drugą stronę i "spreparować" twarz jak na filmiku ;-)
Zachęcam do modyfikacji parametrów. U mnie, niestety, szybkość nie powala, ale nad tym jeszcze popracuję :)
13 komentarzy:
Znalazłem chwilę aby napisać pierwszy program z wykorzystaniem OpenCV i Twojego przykładu. Nie było łatwo bo postawiłem sobie ambitne zadanie napisania aplikacji w delphi, a że nikt jeszcze nie napisał wrapper-a dla delphi dla openCV wiec musiałam sam go napisać. Jak sf.net zacznie działać o zapachnę jako nowy projekt, może komuś sie przyda.
W każdym bać razie wykrywanie twarzy mam już rozpracowane ;)
OK, ale jak teraz bym chciał wykrywać trójkąty ? Albo kwadraty na obrazie ? Albo samochody ;)
Wykrywanie innych rzeczy to kwestia klasyfikatora ;-) Można je samemu wytrenować, jak mi się uda to na pewno opiszę :) Samochodzy mają być w następnej wersji OpenCV.
Ostatnio spędziłem sporo czasu na wypróbowaniu bibliotek wizyjnych w Ruby. Niestety, jedyne co udało mi się postawić to... OpenCV :) Projekt jest jeszcze w powijakach, ale może uda mu się rozwinąć.
Teoretycznie jezyk programowania nie powinien mieć znaczenia, jednak przy przenoszeniu kodu z C do Delphi nie jest tak łatwo.
Jaką kamerę najlepiej kupić aby bez problemu współpracowała z openCV?
Każda która działa w windows będzie działać z openCV ?
Teoretycznie powinna. Niestety nie wiem jak na windowsie, ale na linuksie mam 2 kamery: zew. i wbudowana. Na poczatku nie potrafilem jednej uruchomic ( w sensie, nie dzialala na skypie itp) i w OpenCV tez nie dzialala. Gdy juz mi sie udalo to zaczela tez dzialac w OpenCV. Na windowsie powinno byc podobnie. Jak juz ja uruchomisz w jakims programie to powinna zadzialac.
Jak utworzyć w nowy oknie sama twarz? Tzn. to co jest w prostokącie?
Można np. ustawić ROI dla obrazka. Ponizej przyklad (dla jednej twarzy):
...
// szukamy twarzy w danej ramce
CvSeq *wynik = cvHaarDetectObjects(temp2, haar, storage, 1.1, 3, CV_HAAR_DO_CANNY_PRUNING, cvSize(30, 30));
if (wynik->total > 0)
{
CvRect * twarz = (CvRect*) cvGetSeqElem(wynik, 0);
CvRect roiTwarzy = cvRect(cvRound(twarz->x * skala), cvRound(twarz->y * skala), cvRound(twarz->width * skala), cvRound(twarz->height * skala));
cvSetImageROI(ramka, roiTwarzy);
}
cvShowImage("detekcja twarzy", ramka);
cvResetImageROI(ramka);
cvReleaseImage(&temp);
cvReleaseImage(&temp2);
...
Jeżeli chce się wszystkie twarze wyświetlać w kolejno tworzonych oknach, można to zrobić analogicznie kopiując do struktur IplImage (funkcja cvClone) ramkę z ustawianą odpowiednio dla danej twarzy ROI. Należy pamiętać o resetowaniu ROI przed kolejną analizą.
dzieki wielkie :)
Cześć.
Dużo pracy robisz na tym blogu
bardzo dobry pomysł.
Mam pytanie
Czy do utworzenia (wytrenowania) klasyfikatora używa się narzędzi w opencv czy potrzebne są zewnętrzne biblioteki narzędzia ?
Witam,
na blogu zastój jakiego jeszcze wcześniej nie było... Myślałem nawet nad jego usunięciem, ale archiwum postów pewnie się komuś jeszcze przydaje :)
Wracając do pytania, do trenowania używa się aplikacji z OpenCV. Nazywa się ona haartraining. Sam proces nie należy do prostych. Jego dość dokładny przebieg jest opisany tutaj: http://note.sonots.com/SciSoftware/haartraining.html Niestety, sam tego nie testowałem, więc nie wiem na ile jest to poprawna metoda.
Długo nie mogłem znaleść wpisu do komentarza .
dzięki za link . tego właśnie szukałem.
(będę zaglądał na bloga)
griz.
mam problem, moze ktoś zna rozwiązanie libgcc_s_dw2-1.dll missing
nie wiem może coś źle zrobiłem przy instalacji MinGW?
nie moge sobie poradzić :(
prosze o podpowiedź.
mam pytanie, w jaki sposób zaciemnić wszystko poza narysowaną ramką? Dodam, ze ramkę mam okrągłą a nie prostokątną. jest w ogóle taka możliwość?
Prześlij komentarz