[2023-05-02] 1. 캐스케이드 분류기와 얼굴 검출
캐스케이드 분류기와 얼굴 검출
- 비올라-존스(Viola-Jones) 얼굴 검출기(face detector)
- 2001년 CVPR 학회에서 발표된 객체 검출 알고리즘
- Positive 영상(얼굴 영상)과 negative 영상(얼굴 아닌 영상)을 수천~수만장 모아서 학습시켜 빠르고 정확하게 얼굴 영역을 검출하는 방법을 제안
- 기존 얼굴 검출 방법보다 약 15배 빠르게 동작
- 기존 얼굼 검출 방법과의 차별점
- 유사 하르(Haar-like) 특징을 사용
- AdaBoost에 기반한 강한 분류 성능
- 캐스케이드(cascade) 방식을 통한 빠른 동작 속도
유사 하르 특징
- 사각형 형태의 필터 집합을 이용
- 흰색 사각형 영역 픽셀 값의 합에서 검정색 사각형 영역 픽셀 값을 뺀 결과 값을 추출
- 적분 영상(integral image)을 이용하여 빠르게 계산 가능
AdaBoost 알고리즘을 이용하여 얼굴 판별에 유용한 유사 하르 특징을 선별
- 24 x 24 크기의 부분 영상에서 180,000개 이상의 특징 추출 가능
- AdaBoost 알고리즘을 이용하여 효과적인 유사 하르 특징 6천여개를 선별하여 사용
#####
캐스케이드 분류기(Cascade Classifier)
- 일반적인 영상에는 얼굴이 한 두개 있을 뿐 나머지 영역은 대부분 non-face 영역
- Non-face 영역을 빠르게 skip 하도록 다단계 검사 수행
캐스케이드 분류기 얼굴 감청 과정 시각화
https://youtu.be/hPCTwxF0qf4
객체 검출을 위한 CacadeClassifier 클래스
CacadeClassifier 멀티 스케일 객체 검출 멤버 함수
void CascadeClassiier::detectMultiScale(InputArray image, std:: vector<Rect>& objects, double scaleFactor = 1.1, int minNeighbors = 3, int flags = 0, Size minSize = Size(), Size maxSize() = Size());
- image : (입력) 입력 영상(CV_8U)
- objects : (출력) 검출된 객체의 사각형 정보(vector
) - scaleFactor : 영상 축소 비율
- minNeighbors : 얼마나 많은 이웃 사각형이 검출되어야 최종 검출 영역으로 설정할지를 지정
- flags : (현재) 사용되지 않음
- minSize : 최소 객체 크기
- maxSize : 최대 객체 크기
OpenCV 제공 분류기 XML 파일
- C:\opencv\build\etc\haarcascades
얼굴 및 눈 검출 예제 코드
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/core/ocl.hpp"
using namespace std;
using namespace cv;
int main()
{
ocl::setUseOpenCL(false); // 정확하게 시간 측정을 하기 위해 OpenCL을 사용하지 말아라
// OpenCL 관련된 처리 또는 체크를 하는 시간이 100mili 까지 걸리는데 이 작업의 측정 시간을 배제하기 위해
Mat src = imread("lenna.bmp", IMREAD_GRAYSCALE);
if (src.empty()) {
cerr << "Image load failed!" << endl;
return -1;
}
CascadeClassifier face_cascade("haarcascade_frontalface_default.xml");
// haarcascade_frontalface_default.xml 이 파일을 복사해서 코드가 들어있는 폴더에 복사
// 다른 위치에 있는 경우 상대/절대 경로까지 같이 입력해줘야함
if (face_cascade.empty()) { // 정상적으로 xml 파일을 불러왔는지 확인하는 코드
cerr << "Failed to open (face) xml file!" << endl;
return -1;
}
TickMeter tm; // 시간측정
tm.start(); // 시간측정 시작
vector<Rect> faces; // 얼굴 검출 결과를 받을 vector<Rect>타입의 faces 선언
face_cascade.detectMultiScale(src, faces); // src 영상의 검출된 결과인 사각형 정보를 받은 faces
tm.stop(); // 시간측정 끝
cout << "Face detect: " << tm.getTimeMilli() << " ms." << endl; // Milli 단위로 결과 출력
Mat dst;
cvtColor(src, dst, COLOR_GRAY2BGR); // dst 영상을 컬러영상 형태로 입력영상을 변환해서 만듬
for (size_t i = 0; i < faces.size(); i++) { // 0부터 증가시켜가면서 faces의 사이즈까지
rectangle(dst, faces[i], Scalar(255, 0, 255), 2, LINE_AA); // 결과 영상 dst에 사각형 정보를 이용해서 보라색2px 으로 사각형을 그림
}
#if 0
CascadeClassifier eyes_cascade("haarcascade_eye.xml"); // 눈을 검출
if (eyes_cascade.empty()) {
cerr << "Failed to open (eye) xml file!" << endl;
return -1;
}
for (size_t i = 0; i < faces.size(); i++) {
Mat faceROI = src(faces[i]); // 위에서 검출한 얼굴 영역에 대해서 ROI를 설정함
vector<Rect> eyes;
eyes_cascade.detectMultiScale(faceROI, eyes); // 얼굴 영역 안에서만 눈을 찾음
for (size_t j = 0; j < eyes.size(); j++) {
Point eye_center(faces[i].x + eyes[j].x + eyes[j].width / 2, faces[i].y + eyes[j].y + eyes[j].height / 2);
int radius = cvRound((eyes[j].width + eyes[j].height) * 0.25);
circle(dst, eye_center, radius, Scalar(255, 0, 0), 2, LINE_AA); // 결과를 파란색 2px 동그라미로 표시
}
}
#endif
// imshow("src", src);
imshow("dst", dst);
waitKey();
}
- face_cascade.detectMultiScale(src, faces, 1.2)
- face_cascade.detectMultiScale(src, faces, 1.2, 3, 0, Size(100, 100), Size(300, 300))
- 얼굴 영역에서 눈 추가로 검출하기