라즈베리파이(Raspberry Pi) 카메라 모듈로 눈인식 실시간 출력해보기

김예찬·2023년 10월 19일
1
post-thumbnail

라즈베리파이를 이용한 얼굴, 눈 인식 튜토리얼! ✨🤩
c++코드로 opencv 라이브러리를 이용하여 얼굴에서 눈을 인식하고 눈에 선글라스를 씌워보자.

섹션 1: 라즈베리 파이 소개

라즈베리 파이란 무엇인가?

라즈베리 파이(Raspberry Pi)는 싱글 보드 컴퓨터(Single-Board Computer, SBC)로, 영국의 Raspberry Pi Foundation에서 개발한 저렴한 가격의 컴퓨터라고 생각하면 된다.

라즈베리 파이의 주요 특징:

  • 저렴한 가격: 모델에 따라 다르지만 5달러~90달러정도로 비교적 저렴한 가격대를 가지고 있다.
  • 소형 크기: 작고 휴대하기 쉬운 크기로, 다양한 프로젝트에 적합.
  • 다양한 모델: 다양한 모델과 사양이 존재하며, 성능과 기능에 따라 선택 가능.
  • 풍부한 입출력 포트: HDMI 출력, USB 포트, GPIO (General-Purpose Input/Output) 핀, 이더넷 포트 등 다양한 입출력 옵션을 제공.
  • 다양한 운영체제 지원: 다양한 운영체제를 지원하며, Raspbian OS가 기본적으로 제공.

라즈베리 파이는 프로그래밍, 로봇 공학, 웹 서버, 미디어 스트리밍, 게임 개발, Internet of Things (IoT) 등 다양한 분야에서 활용가능하다.

섹션 2: OpenCV 설치 방법

OpenCV란 무엇인가?

OpenCV(Open Source Computer Vision Library)는 컴퓨터 비전 및 이미지 처리 작업을 위한 오픈 소스 라이브러리. OpenCV는 이미지 및 비디오 처리, 객체 감지, 얼굴 인식, 동작 추적 등 다양한 컴퓨터 비전 작업을 지원해준다. 따라서 OpenCV를 이용하면 간단히 얼굴 인식을 할 수 있다.

OpenCV 설치 방법

라즈베리 파이에서 OpenCV를 설치하는 방법:

라즈베리파이 터미널에 다음 명령어를 입력한다.

  1. 라즈비안 OS 업데이트:
    먼저 라즈베리 파이의 운영체제를 최신 상태로 업데이트한다.
    sudo apt update
    sudo apt upgrade
    
  1. OpenCV 설치를 위한 패키지 및 설정

    이미지 처리를 위한 패키지 설치
    sudo apt install libjpeg-dev libtiff5-dev libjasper-dev libpng12-dev -y
    비디오 처리를 위한 패키지 설치
    sudo apt install libavcodec-dev libavformat-dev libswscale-dev libxvidcore-dev libx264-dev libxine2-dev -y
    비디오 캡처 도구 설치
    sudo apt install libv4l-dev v4l-utils -y
    비디오 스트리밍 패키지 설치
    sudo apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev -y
    OpenCV GUI 관련 패키지 설치
    sudo apt install libgtk2.0-dev libgtk-3-dev -y
    OpenGL 패키지 설치
    sudo apt install mesa-utils libgl1-mesa-dri libgtkgl2.0-dev libgtkglext1-dev -y
    최적화 패키지 설치
    sudo apt install libatlas-base-dev gfortran libeigen3-dev -y
    Python 관련 패키지 설치
    sudo apt install python2.7-dev python3-dev python-numpy python3-numpy -y
  2. OpenCV 및 OpenCV Contrib 소스 코드 다운로드

	mkdir opencv
	cd opencv
	wget -O opencv.zip https://github.com/opencv/opencv/archive/4.1.2.zip
	wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/4.1.2.zip
	unzip opencv.zip
	unzip opencv_contrib.zip
  1. OpenCV 빌드 디렉토리 생성
	cd opencv-4.1.2
	mkdir build
	cd build
  1. CMake를 사용하여 OpenCV 빌드 및 설치
    CMake 설정:
    cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=OFF -D WITH_IPP=OFF -D WITH_1394=OFF -D BUILD_WITH_DEBUG_INFO=OFF -D BUILD_DOCS=OFF -D INSTALL_C_EXAMPLES=ON -D INSTALL_PYTHON_EXAMPLES=ON -D BUILD_EXAMPLES=OFF -D BUILD_TESTS=OFF -D BUILD_PERF_TESTS=OFF -D ENABLE_NEON=ON -D ENABLE_VFPV3=ON -D WITH_QT=OFF -D WITH_GTK=ON -D WITH_OPENGL=ON -D OPENCV_ENABLE_NONFREE=ON -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib-4.1.2/modules -D WITH_V4L=ON -D WITH_FFMPEG=ON -D WITH_XINE=ON -D ENABLE_PRECOMPILED_HEADERS=OFF -D BUILD_NEW_PYTHON_SUPPORT=ON -D OPENCV_GENERATE_PKGCONFIG=ON ../ -D WITH_OPENCL=ON
    Build:
    make
    Installation:
    sudo make install

섹션 3: Eyes detection 코드 작성 💻

얼굴에서 눈을 인식하고 눈부분에 선글라스 이미지를 입혀보자.

라즈베리 파이의 카메라로부터 영상을 받아와서 얼굴과 눈을 인식하고 미리 설정한 sunglasses.png 이미지를 눈부분에 삽입하여 실시간으로 보여주는 코드를 c++로 작성하였다.

#include </opencv2/opencv.hpp>
#include </opencv2/highgui.hpp>
#include </opencv2/objdetect.hpp>
#include <iostream>

using namespace std;
using namespace cv;

// 한 프레임에서 얼굴과 눈 추출을 위한 함수
void detectAndDisplay(Mat frame);
// 얼굴 인식 학습데이터 저장 파일 이름
String face_cascade_name;
// 눈 인식 학습데이터 저장 파일 이름
String eyes_cascade_name;
// Cascade 분류를 통한 얼굴 인식 객체
CascadeClassifier face_cascade;
// Cascade 분류를 통한 눈 인식 객체
CascadeClassifier eyes_cascade;
// 결과를 보여줄 창의 이름
String window_name = "Face and eyes detection";

int main(int argc, char **argv)
{
    int CAM_ID = -1;
    Mat frame1;
    // Cascade 기법을 통해 얼굴 인식을 위한 학습 결과 데이터 파일 (해당 경로에 xml 파일이 있어야함)
    face_cascade_name = "/usr/local/share/opencv4/haarcascades/haarcascade_frontalface_alt.xml";
    if (!face_cascade.load(face_cascade_name))
    {
        printf("Error! loading face cascade\n");
        return -1;
    }
    // Cascade 기법을 통해 눈 인식을 위한 학습 결과 데이터 파일 (해당 경로에 xml 파일이 있어야함)
    eyes_cascade_name = "/usr/local/share/opencv4/haarcascades/haarcascade_eye.xml";
    if (!eyes_cascade.load(eyes_cascade_name))
    {
        printf("Error! loading eyes cascade \n");
        return -1;
    }
    VideoCapture cap(CAM_ID); //
    if (!cap.isOpened())
    {
        // 카메라 열렸는지 확인
        printf("Can't open the CAM (%d)\n", CAM_ID);
        return -1;
    }

    while (1)
    {
        // 카메라에서 이미지 얻어오기
        cap >> frame1;
        // 이미지의 정상 여부를 확인
        if (frame1.empty())
        {
            printf(" Read frame error!");
            break;
        }
            // 얼굴과 눈 검출 함수 호출
            detectAndDisplay(frame1);
            // 10ms 동안 키입력 대기
            if (waitKey(10) >= 0)
                break;
    } // end while()
    // 윈도우 증료
    destroyWindow(window_name);
    return 0;
}// end main()

void detectAndDisplay(Mat frame)
{
    vector<Rect> faces;
    vector<Rect> eyes;
    Mat frame_gray;
    Mat roi_gray;
    cvtColor(frame, frame_gray, COLOR_BGR2GRAY);
    equalizeHist(frame_gray, frame_gray);
    face_cascade.detectMultiScale(frame_gray, faces, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));
    for (size_t i = 0; i < faces.size(); i++)
    {
        rectangle(frame, faces[i], Scalar(0, 0, 255), 1, 8, 0);
        roi_gray = frame_gray(faces[i]);
        eyes_cascade.detectMultiScale(roi_gray, eyes, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(30, 30));

        if (eyes.size() == 2)
        {
            int x, y, width, height;
            if (eyes[0].x < eyes[1].x)
            {
                x = eyes[0].x;
                y = eyes[0].y;
                width = (eyes[1].x - eyes[0].x) * 2;
            }
            else
            {
                x = eyes[1].x;
                y = eyes[1].y;
                width = (eyes[0].x - eyes[1].x) * 2;
            }
            eyes[0].height > eyes[1].height ? height = eyes[0].height : height = eyes[1].height;
        
        Mat sunclasses = imread("sunglasses.png");
        Mat re_sunclasses;
        resize(sunclasses, re_sunclasses, Size(width, height), 0, 0, INTER_LINEAR);
        Mat re_sunclasses_gray;
        cvtColor(re_sunclasses, re_sunclasses_gray, COLOR_BGR2GRAY);
        Mat mask;
        threshold(re_sunclasses_gray, mask, 50, 255, THRESH_BINARY_INV);
        Mat roi(frame, Rect(faces[i].x + x, faces[i].y + y, width, height));
        re_sunclasses.copyTo(roi, mask);
    }
}
imshow(window_name, frame);
}

OpenCV의 CascadeClassifier를 사용하여 얼굴과 눈을 쉽게 인식할 수 있다.

1. 얼굴을 인식하고 인식된 얼굴 주변에 빨간색 사각형을 그린다.
2. 각 얼굴 영역에서 눈을 인식하고 두 개의 눈이 감지되면, 그 두 눈 사이에 선글라스 이미지를 삽입하여 실시간으로 출력한다.

구글에서 간단히 선글라스 이미지를 검색해 다운받아 sunglasses.png로 저장 후 소스코드가 위치한 폴더에 위치시켰다.

섹션 4: 컴파일 및 실행


g++ main.cpp -o a.out $(pkg-configopencv4--libs--cflags)
./a.out

실행하면 카메라 모듈의 입력을 보여주는 창이 뜬다.
카메라에 얼굴을 가져다 대자 빨간색박스로 얼굴이 인식되며 눈이 인식되면 선글라스가 덮어 씌워진다.😎

일론 머스크 형님에게도 멋진 선글라스를 씌워보았다.

일론 형님에게는 선글라스가 살짝 작아보였다...ㅎㅎ

마무리 ✔

이 튜토리얼을 통해 라즈베리 파이를 사용하여 얼굴 인식을 구현하는 기초를 익힐 수 있었다. 작고 저렴한 라즈베리 파이를 이용해 이렇게 다양한 기능을 사용해보며 작지만 강한 친구라는 걸 알 수 있었고 왜 많은 사람들에게 각광받는지 이해가 갔다.👍

0개의 댓글