Computer >> 컴퓨터 >  >> 프로그래밍 >> C++

C++와 OpenCV로 눈 추적하기: 실시간 눈 좌표 추적 완벽 가이드


이 글에서는 OpenCV를 활용해 눈을 추적하는 방법을 알아봅니다. Haar Cascade 분류기로 눈을 먼저 검출했다면, 그 이후의 추적 작업은 생각보다 훨씬 간단합니다. 이 예제에서는 검출된 눈을 원(circle)으로 감싸서 표시하며, 원의 중심 좌표를 추적하는 것이 곧 눈의 중심을 추적하는 것과 같습니다.

눈 추적의 핵심 원리

원의 중심을 추적하려면 두 개의 정수형 변수가 필요합니다. 아래 코드에서는 main() 함수의 첫 두 줄(9번째, 10번째 줄)에서 'x_axis'와 'y_axis'라는 이름의 변수를 선언하여 이를 준비합니다.

코드의 42번째와 43번째 줄에서는 원의 중심에 해당하는 수평(x)·수직(y) 좌표 값을 각각 'x_axis'와 'y_axis' 변수에 복사합니다. 이어서 44번째 줄에서 'cout' 문을 사용해 중심 좌표 값을 콘솔에 출력함으로써, 눈의 위치를 실시간으로 확인하고 추적할 수 있습니다.

C++로 구현한 전체 예제 코드

다음은 C++와 OpenCV를 사용해 카메라 영상 속 눈의 위치를 추적하는 전체 코드입니다.

#include<iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/objdetect/objdetect.hpp>
using namespace cv;
using namespace std;
int main() {
    int x_axis;//좌표 값을 저장할 정수형 변수 선언//
    int y_axis;//좌표 값을 저장할 정수형 변수 선언//
    Mat frame;//비디오 프레임을 담을 행렬 선언//
    namedWindow("Detect");//작업 결과를 보여줄 윈도우 생성//
    VideoCapture image(0);//기본 카메라로부터 비디오 캡처//
    if (!image.isOpened()){ //비디오 소스를 찾지 못한 경우 오류 메시지 출력//
        cout << "Couldn't load video from the source.Make sure your camera is working properly." << endl;
        system("pause");
        return 0;
    }
    double height = image.set(CAP_PROP_FRAME_HEIGHT, 480);//각 프레임의 높이 설정//
    double width = image.set(CAP_PROP_FRAME_WIDTH, 640);//각 프레임의 너비 설정//
    CascadeClassifier face_cascade, eyes_cascade;//CascadeClassifier 객체 선언//
    face_cascade.load("C:/opencv/sources/data/haarcascades/haarcascade_frontalface_alt.xml");//얼굴 검출용 캐스케이드 분류기 로드//
    eyes_cascade.load("C:/opencv/sources/data/haarcascades/haarcascade_eye.xml");//눈 검출용 캐스케이드 분류기 로드//
    while (true) {
        bool temp = image.read(frame);//카메라에서 읽어온 프레임을 frame 행렬에 저장//
        std::vector<Rect>faces;//faces라는 이름의 벡터 선언//
        face_cascade.detectMultiScale(frame, faces, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(100, 100));//영상에서 얼굴 검출//
        for (int i = 0; i < faces.size(); i++){ //검출된 얼굴 위치 확인//
            Point center(faces[i].x + faces[i].width * 0.5, faces[i].y + faces[i].height * 0.5);//얼굴의 중심 좌표 계산//
            ellipse(frame, center, Size(faces[i].width * 0.5, faces[i].height * 0.5), 0, 0, 360, Scalar(255, 0, 255), 4, 8, 0);//얼굴 위에 타원 그리기//
            Mat faceROI = frame(faces[i]);//눈 검출을 위해 얼굴 영역을 ROI(관심 영역)로 지정//
            std::vector<Rect>eyes;//eyes라는 이름의 벡터 선언//
            eyes_cascade.detectMultiScale(faceROI, eyes, 1.1, 2, 0 | CASCADE_SCALE_IMAGE, Size(5, 5));//각 얼굴 영역에서 눈 검출//
            for (size_t j = 0; j < eyes.size(); j++){ //검출된 눈 위치 확인//
                Point center(faces[i].x + eyes[j].x + eyes[j].width * 0.5, faces[i].y + eyes[j].y + eyes[j].height * 0.5);//양쪽 눈의 중심 좌표 계산//
                int radius = cvRound((eyes[j].width + eyes[j].height) * 0.25);//눈을 감싸는 원의 반지름 계산//
                circle(frame, center, radius, Scalar(255, 0, 0), 4, 8, 0);//양쪽 눈 주위에 원 그리기//
                x_axis = eyes[j].x;//눈의 x축 좌표를 x_axis에 저장//
                y_axis = eyes[j].y;//눈의 y축 좌표를 y_axis에 저장//
                cout << "Position of the eyes is:" << "(" << x_axis << "," << y_axis << ")" << endl;//눈의 좌표 값 출력//
            }
        }
        imshow("Detect", frame);//'Detect' 윈도우에 결과 표시//
        if (waitKey(30) == 27){ //프레임당 대기 시간은 30밀리초, ESC 입력 시 종료//
            break;
        }
    }
    return 0;
}

실행 결과

코드를 실행하면 카메라 영상에서 얼굴은 자홍색(magenta) 타원으로 표시되고, 검출된 각 눈은 파란색 원으로 둘러싸입니다. 동시에 콘솔 창에는 아래와 같은 형식으로 눈의 좌표가 실시간으로 출력됩니다.

Position of the eyes is:(x,y)

C++와 OpenCV로 눈 추적하기: 실시간 눈 좌표 추적 완벽 가이드


C++와 OpenCV로 눈 추적하기: 실시간 눈 좌표 추적 완벽 가이드

정리

이 예제는 haarcascade_frontalface_alt.xml로 얼굴을 먼저 찾은 뒤, 해당 얼굴 영역을 ROI(관심 영역)로 지정하고 그 안에서 haarcascade_eye.xml로 눈을 검출하는 2단계 구조입니다. 이런 방식을 사용하면 배경에 있는 유사한 패턴으로 인한 오탐(false positive)을 줄이고 검출 정확도를 높일 수 있습니다. 마지막으로 waitKey(30)은 프레임당 30밀리초의 대기 시간을 두어 영상이 자연스럽게 재생되도록 하며, ESC 키(아스키 코드 27)를 누르면 루프가 종료되고 프로그램이 끝납니다.