상세 컨텐츠

본문 제목

#OpenCV 4로 배우는 컴퓨터 비전과 머신 러닝 - 18

Programing/OpenCV

by CouqueD'asse 2022. 7. 27. 15:19

본문

13장 객체 검출

 

13.1 템플릿 매칭

입력 영상에서 작은 크기의 부분 영상 위치를 찾아내고 싶은 경우 사용함

템플릿 : 찾고자 하는 대상이 되는 작은 크기의 영상

템플링 매칭 : 작은 크기의 템플릿 영상을 입력 영상 전체 영역에 대해 이동하면서 가장 비슷한 위치를 수직적으로 찾아내는 방식

// 템플릿 매칭
void template_matching()
{
	Mat img = imread("circuit.bmp", IMREAD_COLOR);
	Mat templ = imread("crystal.bmp", IMREAD_COLOR);

	if (img.empty() || templ.empty())
	{
		return;
	}

	img = img + Scalar(50, 50, 50);

	Mat noise(img.size(), CV_32SC3);
	randn(noise, 0, 10);
	add(img, noise, img, Mat(), CV_8UC3);

	Mat res, res_norm;
	matchTemplate(img, templ, res, TM_CCOEFF_NORMED);
	normalize(res, res_norm, 0, 255, NORM_MINMAX, CV_8U);

	double maxv;
	Point maxloc;
	minMaxLoc(res, 0, &maxv, 0, &maxloc);
	cout << "maxv: " << maxv << endl;

	rectangle(img, Rect(maxloc.x, maxloc.y, templ.cols, templ.rows), Scalar(0, 0, 255), 2);

	imshow("templ", templ);
	imshow("res_norm", res_norm);
	imshow("img", img);

	waitKey();
	destroyAllWindows();
}

 

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

비올라-존스 얼굴 검추 알고리즘 : 영상을 24x24 크기로 정규화한 후, 유사-하르 필터 집합으로부터 특징 정보를 추출하여 얼굴 여부를 반별

유사-하르 필터 : 흑백 사각형이 서로 붙어 있는 형태로 구성된 필터

흰색 영역 픽셀 값은 모두 더하고, 검은색 영역 픽셀 값은 모두 빼서 하나의 특징 값을 얻을 수 있음.

(사람의 정면 얼굴 형태가 전형적으로 밝은 영역(이마, 볼, 미간 등)과 어두운 영역(눈썹, 입술 등)이 정해져 있음.)

그러나 다양한 크기의 유사-하르 필터를 대략 18만 개 생성할 수 있고, 픽셀 갓의 합과 차를 계산하는 것이 복잡하지는 않지만 시간이 오래 걸리는 것이 문제됨

이에 대해 에이다부스트 알고리즘과 적분 영상을 이용하여 해결함

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

캐스케이드 구조라는 새로운 방식을 도입하여 얼굴이 아닌 영역을 빠르게 걸러 내는 방식을 사용함

캐스케이드 구조 1단계에서 얼굴 검출에 가장 유용한 유사-하르 필터 하나를 사용하여, 얼굴이 아니라고 판단되면 이후의 유사-하르 필터 계산은 수행하지 않음

2단계에서 유사=하르 필터 다섯 개를 사용하여 얼굴이 아닌지를 검사하고, 얼굴이 아니라고 판단되면 이후 단계의 검사는 수행하지 않음. 이러한 방식으로 얼굴이 아닌 영역을 빠르게 제거함으로써 약 15배 빠르게 동작하는 성능을 보여줌

// 얼굴 검출
void detect_face()
{
	Mat src = imread("kids.png");

	if (src.empty())
	{
		return;
	}

	CascadeClassifier classifier("haarcascade_frontalface_default.xml");

	if (classifier.empty())
	{
		return;
	}

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

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

	imshow("src", src);

	waitKey();
	destroyAllWindows();
}
// 눈 검출
void detect_eyes()
{
	Mat src = imread("kids.png");

	if (src.empty())
	{
		return;
	}
	CascadeClassifier face_classifier("haarcascade_frontalface_default.xml");
	CascadeClassifier eye_classifier("haarcascade_eye.xml");

	if (face_classifier.empty() || eye_classifier.empty())
	{
		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();
	destroyAllWindows();
}

 

13.3 HOG 알고리즘과 보행자 검출

HOG : 그래디언트 방향 히스토그램

사람이 서 있는 영상에서 그래디언트를 구하고, 그래디언트의 크기와 방향 성분을 이용하여 사람이 서 있는 형태에 대한 특징 벡터를 정의함

머신 러닝의 일종인 SVM(서포트 벡터 머신) 알고리즘을 이용하여 입력 영상에서 보행자 위치를 검출하는 방법

HOG는 일반적으로 64x128 크기의 영상에서 계산

그래디언트 : 크기와 방향 성분으로 계산하며, 방향 성분은 0도부터 180도까지로 설정함

HOG 알고리즘 : 입력 영상으로부터 그래디언트를 계산

그다음은 입력 영상을 8x8 크기 단위로 분할하는데, 각각의 8x8 부분 영상을 셀이라고 부름

각각의 셀로부터 그래디언트 방향 성분에 대한 히스토그램을 구하며, 이때 방향 성분이 20도 단위로 구분하면 총 아홉 개의 빈으로 구성된 방향 히스토그램이 만들어짐 그리고 인접한 네 개의 셀을 합쳐서 블록이라고 정의함

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

SVM은 두 개의 클래스를 효과적으로 분리하는 능력을 가진 머신 러닝 알고리즘

// 보행자 검출
int main()
{
	VideoCapture cap("vtest.avi");

	if (!cap.isOpened())
	{
		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(10) == 27)
			break;
	}

	return 0;
}

 

13.4 QR 코드 검출

QR 코드 : 흑백 격자 무늬 모양의 2차원 바코드 일종으로 숫자, 영문자, 8비트 문자, 한자 등의 정보를 저장

입력 영상에서 QR 코드를 인식하려면 먼저 QR 코드 세 모서리에 포함된 흑백 정사각형 패턴을 찾아 QR 코드 전체 영역 위치를 알아내야 함

검출된 QR 코드를 정사각형 형태로 투시 변환한 후, QR 코드 내부에 포함된 흑백 격자 무늬를 해석하여 문자열을 추출해야 함

QR 코드를 검출하고 해석하는 기능은 QRCodeDetector 클래스에 구현

// QR 코드 검출 및 해석
void decode_qrcode()
{
	VideoCapture cap(0);

	if(!cap.isOpened())
	{
		return;
	}

	QRCodeDetector detector;

	Mat frame;
	while (true)
	{
		cap >> frame;

		if (frame.empty())
		{
			break;
		}

		vector<Point> points;
		String info = detector.detectAndDecode(frame, points);

		if (!info.empty())
		{
			polylines(frame, points, true, Scalar(0, 0, 255), 2);
			putText(frame, info, Point(10, 30), FONT_HERSHEY_DUPLEX, 1, Scalar(0, 0, 255));
		}

		imshow("frame", frame);

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

관련글 더보기