작년 4월인가에 라즈베리파이3B 모델을 사고, 라즈베리파이 전용 카메라 모듈도 구입을 했습니다. 이때만해도 8M 카메라 모듈이 나오기 전이라 5M 모듈만 있을 때였죠. 이거 사자마자 거의 같은 가격으로 8M 모듈이 발표되서 슬펐던 기억이 있는데.. 암튼 그때만해도 라즈베리파이에 카메라를 붙이고 OpenCV를 깔아서 뭐라도 해볼 요량이었지만, 어쩌다 보니 카메라를 사놓고 별것 해보지도 못하고 구석에 쳐박아 두었었네요.


이번에 다시 라즈비안 OS를 새로 깔고 새마음으로 라즈베리파이에 카메라를 붙였습니다. OpenCV는 이미 깔아놨고, 이번에는 라즈베리파이 카메라를 사용해보려고 합니다. 라즈베리파이카메라를 사용하기 위해 raspicam라는 이름의 라이브러리를 사용할 것입니다. raspicam 라이브러리에 대한 설명은 아래 링크를 참고합니다.

http://www.uco.es/investiga/grupos/ava/node/40


위 사이트에 쓰여있듯이 raspicam은 BSD 라이센스를 따르기 때문에 자유롭게 이용이 가능하고, 일반 C++ 인터페이스뿐만 아니라 OpenCV 인터페이스도 지원합니다. raspicam 라이브러리도 소스 코드를 다운받아서 직접 빌드를 진행해야 라이브러리 파일이 생성됩니다. 설치와 관련되어서는 아래 블로그 설명이 잘 되어 있네요.

http://webnautes.tistory.com/956


소스 코드 다운로드부터 빌드까지 명령어를 백업을 위해 아래에 정리해두겠습니다.

pi@GoPiGo:~ $ wget https://downloads.sourceforge.net/project/raspicam/raspicam-0.1.6.zip
pi@GoPiGo:~ $ unzip raspicam-0.1.6.zip
pi@GoPiGo:~ $ cd raspicam-0.1.6
pi@GoPiGo:~/raspicam-0.1.6 $ mkdir build && cd build
pi@GoPiGo:~/raspicam-0.1.6/build $ cmake .. 2>&1 | tee cmake_messages.txt


위와 같은 cmake 설정을 하고나면 화면에 출력되는 메시지가 cmake_messages.txt 파일에도 함께 저장됩니다. 이때 CREATE OPENCV MODULE=1 이라는 메시지가 출력이 되어야 raspicam 라이브러리가 OpenCV를 인식하고, OpenCV에서 함께 사용할 수 있도록 라이브러리를 생성합니다. cmake_messages.txt 파일의 전체 내용을 아래 [더보기]에 나타내었습니다.


cmake가 정상적으로 동작하였으면 이제 실제 빌드 작업을 수행합니다. 기본적으로 make -j2 명령을 입력하면 되고, 혹시나 하는 마음에 빌드 메시지도 함께 기록합니다. 빌드가 완료되면 sudo make install 명령으로 실제 라이브러리를 시스템 폴더에 복사합니다.

pi@GoPiGo:~/raspicam-0.1.6/build $ make -j2 2>&1 | tee build_messages.txt
pi@
GoPiGo:~/raspicam-0.1.6/build $ sudo make install
pi@GoPiGo:~/raspicam-0.1.6/build $ sudo ldconfig


위 사진은 sudo make install 명령을 입력했을 때의 모습입니다. 일단 raspicam 라이브러리 설치가 완료되었습니다. 참 쉽죠? :-)


그러면 이제 raspicam 라이브러리와 OpecCV 라이브러리를 이용하여 카메라 입력을 받고 간단한 얼굴 검출 프로그램을 만들어보겠습니다. 홈디렉토리 아래에 coding/opencv/facedetect 디렉토리를 만들고, 여기에 main.cpp 파일을 생성합니다. main.cpp 파일은 아래와 같이 작성합니다.

#include <opencv2/opencv.hpp>
#include <iostream>
#include <raspicam/raspicam_cv.h>

using namespace cv;
using namespace std;
 
int main(int argc, char* argv[]) {
	raspicam::RaspiCam_Cv cam;

	cam.set(CV_CAP_PROP_FORMAT, CV_8UC3);
	cam.set(CV_CAP_PROP_FRAME_WIDTH, 640);
	cam.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
	
	if (!cam.open()) {
		cerr << "Camera open failed!" << endl;
		return -1;
	}

	CascadeClassifier cascade("haarcascade_frontalface_default.xml");

	if (cascade.empty()) {
		cerr << "Failed to open xml file!" << endl;
		return -1;
	}

	Mat frame, gray, reduced;
	int64 t1, t2;
	bool do_flip = false;
	
	while (1) {
		cam.grab();
		cam.retrieve(frame);
		
		if (do_flip)
			flip(frame, frame, -1);

		t1 = getTickCount();
		
		cvtColor(frame, gray, cv::COLOR_BGR2GRAY);
		resize(gray, reduced, Size(0, 0), 0.5, 0.5);
		
		vector<Rect> faces;
		cascade.detectMultiScale(reduced, faces, 1.1, 3, 0, Size(40, 40));
		
		for (size_t i = 0; i < faces.size(); i++) {
			Rect rc;
			rc.x = faces[i].x << 1;
			rc.y = faces[i].y << 1;
			rc.width = faces[i].width << 1;
			rc.height = faces[i].height << 1;
			
			rectangle(frame, rc, Scalar(0, 0, 255), 3);
		}
		
		t2 = getTickCount();
		cout << "It took " << (t2 - t1) * 1000 / getTickFrequency() << " ms." << endl;

		imshow("frame", frame);
		
		int k = waitKey(1);
		if (k == 27)
			break;
		else if (k == 'f' || k == 'F')
			do_flip = !do_flip;
	}

	cam.release();
	destroyAllWindows();
}


소스 코드가 그리 길지는 않죠? 일단 raspicam::RaspiCam_Cv 객체를 생성해서 카메라를 열고, 매 프레임마다 Haar Cascade Classifier로 얼굴을 검출합니다. 속도 향상을 위해서 매 프레임을 가로, 세로 1/2 크기로 줄인 다음에 얼굴을 검출하고, 검출된 얼굴 영역을 화면에 보여줄 때 다시 좌표를 2배 확대합니다. 제가 라즈베리파이에 카메라를 거꾸로 달아놔서 'f' 키를 누르면 영상을 flip 하여 얼굴 검출을 수행합니다.


Makefile은 아래와 같이 수정합니다.

CC = g++
CFLAGS = -g -Wall
SRCS = main.cpp
PROG = $(notdir $(CURDIR))

OPENCV = `pkg-config opencv --cflags --libs`
LASPICAM = -lraspicam -lraspicam_cv
LIBS = $(OPENCV) $(LASPICAM)

.PHONY: all clean

$(PROG):$(SRCS)
    $(CC) $(CFLAGS) -o $(PROG) $(SRCS) $(LIBS)

all: $(PROG)

clean:
    rm -f $(OBJS) $(PROG)


이제 터미널 창에서 make 명령을 입력하면 프로그램을 빌드하여 facedetect라는 실행 파일을 생성합니다.

위에서 haarcascade_frontalface_default.xml 파일은 OpenCV를 설치할 때 /usr/local/share/OpenCV/haarcascades 디렉토리에 만들어집니다. 그러므로 cp /usr/local/share/OpenCV/haarcascades/haarcascade_frontalface_default.xml . 명령으로 현재 폴더로 복사하면 됩니다.


이제 터미널 창에서 ./facedetect 명령으로 프로그램을 실행하면 아래처럼 얼굴을 검출합니다.


왼쪽 상단에 나타난 창은 htop 프로그램인데요, 4개의 코어가 다 동작하는 것을 확인할 수가 있구요... 한 프레임에서 얼굴을 찾는데 대략 130~200 ms 정도의 시간이 걸리는 것을 확인할 수 있습니다.


약간의 속도 향상을 위해서 소스 코드에서 cascade.detectMultiScale(reduced, faces, 1.1, 3, 0, Size(40, 40)); 부분을 cascade.detectMultiScale(reduced, faces, 1.2, 3, 0, Size(60, 60), Size(240, 240)); 형태로 수정하고 프로그램을 다시 돌려보니 조금 빨라졌네요. :-)


Posted by kkokkal
: