< 10-1. Face Detection using Haar Cascades >
튜토리얼의 마지막에서는,
- Haar Feature 기반의 Cascade Classifiers를 사용하여 얼굴 탐지의 기본에 대해서 알아보고
- 이를 확장해서 눈 탐지에 대해서 알아볼 것이다.
Basics
Haar feature를 기반으로한 cascade classifiers를 사용한 객체 탐지는 매우 효과적인 방법이다. 이는 머신러닝 기반의 방법으로, cascade는 대량의 postive(대상이 있는) 이미지와 negative(대상이 없는) 이미지로 부터 학습한다. 이는 다른 이미지 내에서 객체를 탐지하는데 사용 된다.
여기서는 얼굴 탐지를 위해서 사용해 볼 것이다. 초기에, 알고리즘은 분류기를 학습시키기 위해 대량의 positive 이미지(얼굴 사진)과 negative 이미지(얼굴이 없는 이미지)를 필요로 한다. 그리고 이로부터 특성을 추출 해야한다. 이 특성 추출을 위해, 아래 이미지에서 보이는 haar 특성들이 사용되는 것이다. 이들은 convolutional 커널처럼 보인다. 각 특성들은 검정색 직사각형의 픽셀 합에서 흰색 직사각형의 픽셀 합을 빼서 얻어진 단일값이다.
이제 이미지에서 특성들을 검출하기 위해 모든 가능한 크기의 커널에 대해 이미지 모든 부분에 적용되어야 한다. 24x24 크기의 이미지의 경우 160,000개의 특성에 대해 계산해야한다. 이 모든 특성들에 대해 검정색, 흰색 직사각형의 픽셀 합을 구해야한다니 매우 비효율적인 것이다. 이를 해결하기 위해서 통합된 이미지를 제안한다. 이는 픽셀들의 합을 계산하는 것을 간단하게 한다. 결국에는 속도도 향상시키게 된다.
하지만 계산된 모든 특성들의 대부분은 부적절하다. 예를 들어, 아래의 이미지를 보자. 윗줄은 두 개의 좋은 특성을 보여준다. 첫 번째 선택된 특성은 눈 부위가 코나 뺨 부위보다는 어둡다는 속성에 초점을 맞춘 것 같다. 두 번째 선택된 특성은 눈이 콧대보다 어둡다는 특성에 의존했다. 하지만 같은 특성(창)들을 뺨이나 다른 곳에 적용하는 것은 부적절하다. Adaboost를 통해 최적의 특성들을 선택할 수 있다.
모든 학습 이미지에 대해 우리는 각각 그리고 모든 특성들을 적용시킨다. 각 특성에 대해, 이는 얼굴을 positive와 negative로 분류할 수 있는 최상의 임계값을 찾는다. 하지만 이렇게 함에도 불구하고 오분류나 에러가 발생한다. 그래서 얼굴과 얼굴이 아닌 것을 제일 잘 분류하여 에러율이 가장 낮도록 하는 특성을 선택하는 것이다. (과정이 그리 간단하지는 않다.
- 각 이미지는 초기에 동인한 가중치를 부여받는다.
- 분류 후, 잘못 분류된 이미지에 대한 가중치가 증가한다.
- 위와 같은 과정이 반복된다.
- 새로운 에러율과 가중치가 계산된다.
- 이 모든 과정은 정해진 정확도나, 에러율, 특성의 수에 다다를 때 까지 반복된다.)
최종 분류기는 이러한 성능이 좋지 않은(약한) 분류기들의 가중치 합이다. 혼자 분류하면 이미지를 제대로 분류 못해서 약하다고 하지만, 다른 분류기와 함께하면 강한 분류기로서의 역할을 한다.
먼저 이미지를 봐보자. 다음으로 24x24크기의 창을 선택해보자. 그 다음 6000개의 특성을 적용시켜보자. 마지막으로 얼굴인지 아닌지 확인을 해보자. 이 방법은 너무 비효율적이고 시간이 많이 걸린다. 이에 대해서 좋은 해결책이 존재한다.
이미지에서, 대다수의 영역은 얼굴이 아닌 부분이다. 그래서 간단한 생각으로, 얼굴이 아닌 부분을 체크하는 것이 더 낫다. 얼굴이 아니라면, 한 방에 버리는 것이다. 다시 처리를 하지 않는 것이다. 대신 얼굴일 수 있는 지역에 집중한다. 이 방법을 사용하면, 얼굴일 가능성이 있는 부위를 확인하는데 시간을 더 사용할 수 있다.
이를 위해 Cascade of Classifiers 개념을 소개한다. 6,000개의 모든 특성을 창에 적용시키는 것 대신에, 특성들을 분류기의 다른 단계로 묶고 하나하나 적용시킨다. (일반적으로 처음 몇 스테이지에서는 특성의 수가 적을 것이다.) 만약 창이 첫 번째 단계에서 실패하면 바로 버린다. 남아있는 특징들을 고려하지도 않는다. 통과된 특징들의 경우 두 번째 단계를 적용하고 프로세스를 계속 진행한다. 모든 단계를 지나는 창은 얼굴 지역을 가리키게 되는 것이다.
Haar-cascade Detection in OpenCV
OpenCV는 탐지 뿐만 아니라, 학습기의 역할도 한다. 커스텀된 분류자를 학습시키고 싶다면 OpenCV를 사용하여 만들 수 있다. (참고 : Cascade Classifier Training.)
여기서는 탐지에 대해서만 다뤄볼 것이다. OpenCV는 이미 얼굴,눈,웃음등에 대해 사전학습된 분류기들을 가지고 있다. XML파일을 받아서 사용하면 된다. (OpenCV Github)
얼굴과 눈을 탐지하는 탐지기를 만들어보자!
먼저 XML 분류기를 불러와야 한다. 그리고 입력 이미지나 영상을 흑백으로 불러온다.
import numpy as np
import cv2
face_cas = cv2.CascadeClassifier('./haarcascade_frontface.xml')
eye_cas = cv2.CascadeClassifier('./haarcascade_eye.xml')
img = cv2.imread('./images/her.jpg')
imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
원본사진을 먼저 보자. 영화 “Her”의 포스터이다.
이제 이미지에서 얼굴을 찾는다. 만약 얼굴을 찾았다면 탐지된 얼굴의 Rect(x,y,w,h) 위치를 반환할 것이다. 이 위치를 받았다면, 얼굴에 대한 ROI를 생성할 수 있고, 눈 탐지를 이 ROI 안에서 할 수 있다. (눈은 항상 얼굴안에 있기 때문이다!)
face = face_cas.detectMultiScale(imgray,1.2,5)
for (x,y,w,h) in face:
img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
roi_gray = imgray[y:y+h, x:x+w]
roi_col = img[y:y+h,x:x+w]
eyes = eye_cas.detectMultiScale(roi_gray)
for (ex,ey,ew,eh) in eyes:
cv2.rectangle(roi_col,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)
cv2.imshow('img',img)
cv2.imwrite('res_her.jpg',img)
cv2.waitKey(0)
cv2.destroyAllWindows(0)
결과는 아래와 같다!
파란색으로 얼굴을 탐지하고, 초록색으로 눈 부분을 탐지한 모습을 볼 수 있다.
---------
이렇게 OpenCV Tutorial 리뷰는 끝이났다! 생각보다 오래걸린 것 같지만,,,, 이제 실전 적용을 위한 프로젝트를 진행하면서 복습해보고 더 배워보는 시간을 가져보도록 할 것이다~!~!