비전 신호 처리II_객체 검출

JuHwan Kim·2022년 4월 8일
0

Vision Signal Processing

목록 보기
5/6

캐스케이드 분류기와 얼굴 검출

OpenCV에서 제공하는 얼굴 검출 기능은 2001년에 비올라(P. Viola)와 존스(M. Jones)가 발표한 부스팅(boosting) 기반의 캐스케이드 분류기(cascade classifier) 알고리즘을 기반으로 만듦

비올라와 존스가 개발한 객체 검출 알고리즘은 기본적으로 다양한 객체를 검출할 수 있지만, 특히 얼굴 검출에 적용되어 속도와 정확도를 인정받은 기술
비올라-존스 얼굴 검출 알고리즘은 기본적으로 영상을 24×24 크기로 정규화
유사-하르 필터(Haar-like filter) 집합으로부터 특징 정보를 추출하여 얼굴 여부를 판별함
사람의 정면 얼굴 형태가 전형적으로 밝은 영역(이마, 미간, 볼 등)과 어두운 영역(눈썹, 입술 등)이 정해져 있다고 가정

24×24 크기에서 다양한 크기의 유사-하르 필터를 대략 18만 개 생성할 수 있음
픽셀 값의 합과 차를 계산하는 것이 복잡하지는 않지만 시간이 오래 걸린다는 점이 문제
다행히 비올라와 존스는 에이다부스트(adaboost) 알고리즘과 적분 영상(integral image)을 이용하여 이 문제를 해결함

에이다부스트 알고리즘은 수많은 유사-하르 필터 중에서 얼굴 검출에 효과적인 필터를 선별하는 역할을 수행함

실제 논문에서는 약 6000개의 유사-하르 필터를 선별함

에이다부스트 알고리즘에 의해 24×24 부분 영상에서 검사할 특징 개수가 약 6000개로 감소

에이다부스트 (adaboost) : Adaptive + boostring

간단한 약분류기들이 상호보완 하도록 단계적(순차적)으로 학습, 이들을 조합하여 최종 강분류기의 성능을 증폭
최종 강분류기는 개별 약분류기들에 각각 가중치를 적용, 조합하여 얻을 수 있음

입력 영상 전체에서 부분 영상을 추출하여 검사해야 하기 때문에 여전히 연산량이 부담될 수 있음
나타날 수 있는 얼굴 크기가 다양하기 때문에 보통 입력 영상의 크기를 줄여 가면서 전체 영역에 대한 검사를 다시 수행해야 함
비올라와 존스는 대부분의 영상에 얼굴이 한두 개 있을 뿐이고 나머지 대부분의 영역은 얼굴이 아니라는 점에 주목함
비올라-존스 알고리즘에서는 캐스케이드(cascade) 구조라는 새로운 방식을 도입하여 얼굴이 아닌 영역을 빠르게 걸러 내는 방식을 사용함 -> 약 15배 상승

OpenCV는 비올라-존스 알고리즘을 구현하여 객체를 분류할 수 있는 CascadeClassifier 클래스를 제공함
CascadeClassifier 클래스는 미리 훈련된 객체 검출 분류기 XML 파일을 불러오는 기능과 주어진 영상에서 객체를 검출하는 기능으로 이루어져 있음

Load : 분류기 xml 파일을 불러옴
Empty : 분류기 검사
detectMultiScale : 객체 검출

OpenCV는 미리 훈련된 얼굴 검출, 눈 검출 등을 위한 분류기 XML 파일을 제공함
미리 훈련된 분류기 XML 파일은 %OPENCV_DIR%\etc\haarcascades 폴더에서 찾을 수 있음
하나의 검출 대상에 대해 서로 다른 방법으로 훈련된 여러 개의 XML 파일이 제공됨

예제1_캐스케이드 분류기와 얼굴 검출

detect_face() 함수는 OpenCV에서 제공하는
haarcascade_frontalface_default.xml 파일을 이용하여 kids.png 영상에서 얼굴을 검출함
검출된 얼굴 영역을 화면에 표시함
OpenCV에서 제공하는 얼굴 검출 분류기 Haarcascade_frontalface_default.xml 사용
원본 영상에서 얼굴을 검출, 검출된 사각형 정보를 faces에 저장

void detect_face()
{
	Mat src = imread("kids.png");

	if (src.empty())
	{
		cerr << "Image load failed!" << endl;
		return;
	}

	CascadeClassifier classifier("haarcascade_frontalface_default.xml");

	if (classifier.empty())
	{
		cerr << "XML load failed!" << endl;
		return;
	}

	vector<Rect> faces;
	classifier.detectMultiScale(src, faces);

	for (Rect rc : faces)
	{
		rectangle(src, rc, Scalar(255, 0, 255), 2);
	}

	imshow("src", src);

	waitKey(0);
	destroyAllWindows();
}

int main()
{
	detect_face();
	return 0;
}

src 출력창은 detect_face() 함수를 실행한 결과
입력 영상으로 사용한 kids.png 파일은 두 명의 아이 얼굴이 들어 있는 영상
검출 결과 아이들의 얼굴이 검출됨을 확인 가능

예제2_캐스케이드 분류기와 얼굴 검출 + 눈 검출

눈을 검출하기 위해서는 먼저 얼굴을 검출하고, 얼굴 영역 안에서만 눈을 검출하는 것이 효율적임
눈 검출을 위해 OpenCV가 제공하는 XML 파일 중 haarcascade_eye.xml 파일을 사용할 것이며, 이 파일을 미리 프로젝트 폴더에 복사해야 함
입력 영상에서 검출한 사각형 얼굴 영역의 부분 영상을 추출
사각형 얼굴 영역 부분에서 눈을 검출하여 원으로 표시

void detect_eyes()
{
	Mat src = imread("kids.png");
	
	if (src.empty())
	{
		cerr << "Image load failed!" << endl;
		return;
	}
	
	CascadeClassifier face_classifier("haarcascade_frontalface_default.xml");
	CascadeClassifier eye_classifier("haarcascade_eye.xml");

	if (face_classifier.empty() || eye_classifier.empty())
	{
		cerr << "XML load failed!" << endl;
		return;
	}
	
	vector<Rect> faces;
	face_classifier.detectMultiScale(src, faces);
	
	for (Rect face : faces)
	{
		rectangle(src, face, Scalar(255, 0, 255), 2);

		Mat faceROI = src(face);
		vector<Rect> eyes;
		eye_classifier.detectMultiScale(faceROI, eyes);

		for (Rect eye : eyes)
		{
			Point center(eye.x + eye.width / 2, eye.y + eye.height / 2);
			circle(faceROI, center, eye.width / 2, Scalar(255, 0, 0), 2, LINE_AA);
		}
	}
	
	imshow("src", src);
	
	waitKey(0);
	destroyAllWindows();
}

int main()
{
	detect_eyes();
	return 0;
}

앞서 detect_face() 함수에서 검출한 얼굴 영역 안에서 눈을 검출하여 파란색 원으로 나타낸 것을 확인할 수 있음

HOG 알고리즘과 보행자 검출

HOG(Histograms of Oriented Gradients)는 그래디언트 방향 히스토그램을 의미
다랄과 트릭스는 사람이 서 있는 영상에서 그래디언트를 구함
그래디언트의 크기와 방향 성분을 이용하여 사람이 서 있는 형태에 대한 특징 벡터를 정의함

머신 러닝의 일종인 서포트 벡터 머신(SVM, Support Vector Machine) 알고리즘을 이용하여 입력 영상에서 보행자 위치를 검출하는 방법을 제안함
보행자 검출을 위한 HOG는 기본적으로 64×128 크기의 영상에서 계산

HOG 알고리즘은 먼저 입력 영상으로부터 그래디언트를 계산
그래디언트는 크기와 방향 성분으로 계산하며, 방향 성분은 0°부터 180°까지로 설정
입력 영상을 8×8 크기 단위로 분할하는데, 각각의 8×8 부분 영상을 셀(cell)이라고 부름 (노란 박스)
각각의 셀로부터 그래디언트 방향 성분에 대한 히스토그램을 구함 (20° 단위로 9개의 빈으로 구성)
인접한 네 개의 셀을 합쳐서 블록(block)이라고 정의 (빨간 박스)

다랄과 트릭스는 수천 장의 보행자 영상과 보행자가 아닌 영상에서 HOG 특징 벡터를 추출함
두 특징 벡터를 구분하기 위해 SVM 알고리즘을 사용함

SVM은 두 개의 클래스를 효과적으로 분리하는 능력을 가진 머신 러닝 알고리즘
다랄과 트릭스는 수천 개의 보행자 특징 벡터와 보행자가 아닌 특징 벡터를 이용하여 SVM을 훈련시킴

효과적인 보행자 검출 방법을 제안함
OpenCV는 HOG 알고리즘을 구현한 HOGDescriptor 클래스를 제공

HOGDescriptor 클래스
특정 객체의 HOG 기술자를 쉽게 구할 수 있음
보행자 검출을 위한 용도로 미리 계산된 HOG 기술자 정보를 제공
기본 생성자는 검색 윈도우 크기를 64×128로 설정함
셀 크기는 8×8, 블록 크기는 16×16, 그래디언트 방향 히스토그램 빈 개수는 9로 설정함
기본 생성자에 의해 만들어지는 HOG 기술자 하나는 3780개의 float 실수로 구성됨

HOGDescriptor::getDefaultPeopleDetector()
미리 계산된 보행자 검출을 위한 HOG 기술자 정보를 반환하는 정적 멤버 함수
보행자 검출을 위해 훈련된 분류기 계수 반환

HOGDescriptor::setSVMDetector()
객체를 검출하기 위한 SVM 검출기
검출할 객체에 대해 훈련된 SVM 계수 등록 필요

예제3_HOG 알고리즘

HOGDescriptor 클래스가 제공하는 보행자 검출 HOG 정보를 이용하여 동영상 매 프레임에서 보행자를 검출하고, 그 결과를 화면에 표시
보행자 검출을 위한 용도로 훈련된 SVM 분류기 계수 이용
바운딩박스 생성 시 랜덤 색상 적용

int main()
{
	VideoCapture cap("vtest.avi");

	if (!cap.isOpened())
	{
		cerr << "Video open failed!" << endl;
		return -1;
	}

	HOGDescriptor hog;
	hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());

	Mat frame;
	while (true)
	{
		cap >> frame;
		if (frame.empty())
			break;

		vector<Rect> detected;
		hog.detectMultiScale(frame, detected);

		for (Rect r : detected)
		{
			Scalar c = Scalar(rand() % 256, rand() % 256, rand() % 256);
			rectangle(frame, r, c, 3);
		}

		imshow("frame", frame);

		if (waitKey(1) == 27)
			break;
	}

	return 0;
}

거리에 지나다니는 사람마다 각기 다른 색상의 사각형이 그려짐
HOG 알고리즘에 의한 보행자 검출은 많은 연산량을 필요로 하기 때문에 속도가 느림 (Debug)
Release 모드 실행 시 보다 빠른 검출 결과를 확인할 수 있음

profile
소소한 개발자

0개의 댓글