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

C++와 OpenCV로 감지된 얼굴 영역을 자르는 방법 완벽 가이드

이 글에서는 OpenCV에서 감지된 얼굴을 잘라내는(crop) 방법을 알아봅니다. 얼굴 영역을 잘라내려면 여러 개의 행렬(Mat)이 필요한데, 가장 효율적인 방법은 이미지 배열을 활용하는 것입니다.

필요한 행렬 선언하기

이 프로그램에서는 다음 두 줄의 코드로 두 개의 이미지 행렬 배열을 선언합니다.

  • Mat cropped_faces[3];
  • Mat faceROI[3];

첫 번째 배열인 cropped_faces는 잘라낸 얼굴 이미지를 저장하는 용도이며, 두 번째 배열인 faceROI는 관심 영역(Region of Interest, ROI)을 정의하는 데 사용됩니다.

얼굴 검출 및 잘라내기 과정

검출 단계에서 프로그램은 먼저 이미지 속 얼굴들의 위치를 찾아 벡터(vector)에 저장합니다. 이 프로그램에서는 해당 벡터의 이름을 faces로 지정했으며, 하나의 벡터에는 여러 개의 검출 결과가 담길 수 있습니다.

다음 두 줄의 코드를 통해 벡터에 담긴 얼굴의 위치를 파악하고, 해당 영역을 잘라내어 faceROI[i] 행렬에 저장합니다.

  • faceROI[i] = image_with_humanface(faces[i]);
  • cropped_faces[i] = faceROI[i];

첫 번째 줄은 image_with_humanface라는 이름의 이미지에서 얼굴 정보를 담고 있는 벡터의 위치를 찾아 해당 영역을 잘라낸 뒤 faceROI[i] 행렬에 저장합니다. 두 번째 줄은 잘라낸 이미지를 또 다른 행렬 배열로 전달하며, 이 배열은 잘라낸 얼굴 이미지를 화면에 표시할 때 사용됩니다.

아래 프로그램은 감지된 얼굴들을 잘라내어 각각의 윈도우에 나누어 보여줍니다.

예제 코드

#include<iostream>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
//'rectangle()' 함수의 정의가 포함된 헤더//
#include<opencv2/objdetect/objdetect.hpp>
//'CascadeClassifier' 클래스의 정의가 포함된 헤더//
#include<string>
using namespace std;
using namespace cv;
int main(int argc, char** argv) {
    Mat image_with_humanface;//사람 얼굴이 있는 이미지를 불러올 행렬 선언//
    Mat cropped_faces[3];//잘라낸 얼굴을 표시하기 위한 행렬 배열 선언//
    Mat faceROI[3];//잘라낸 얼굴을 담기 위한 행렬 배열 선언//
    image_with_humanface = imread("friends3.jpg");//사람 얼굴이 포함된 이미지 로드//
    namedWindow("Face1");//첫 번째 잘라낸 얼굴을 표시할 윈도우 선언//
    namedWindow("Face2");//두 번째 잘라낸 얼굴을 표시할 윈도우 선언//
    namedWindow("Face3");//세 번째 잘라낸 얼굴을 표시할 윈도우 선언//
    string trained_classifier_location = "C:/opencv/sources/data/haarcascades/haarcascade_frontalface_alt.xml";//학습된 XML 분류기의 경로를 문자열로 정의//
    CascadeClassifier faceDetector;//CascadeClassifier 클래스의 객체 'faceDetector' 선언//
    faceDetector.load(trained_classifier_location);//객체에 학습된 XML 분류기 로드//
    vector<Rect>faces;//'faces'라는 이름의 사각형(Rect) 벡터 선언//
    vector<Rect>boundary;//'boundary'라는 이름의 사각형(Rect) 벡터 선언//
    faceDetector.detectMultiScale(image_with_humanface, faces, 1.1, 4, CASCADE_SCALE_IMAGE, Size(20, 20));//'image_with_humanface' 행렬에서 얼굴 검출//
    for (size_t i = 0; i < faces.size(); i++){ //얼굴 주위에 사각형을 그리기 위한 반복문//
        faceROI[i] = image_with_humanface(faces[i]);
        cropped_faces[i] = faceROI[i];
        int x = faces[i].x;//얼굴 사각형 시작점의 x 좌표 가져오기//
        int y = faces[i].y;//얼굴 사각형 시작점의 y 좌표 가져오기//
        int h = y + faces[i].height;//사각형의 높이 계산//
        int w = x + faces[i].width;//사각형의 너비 계산//
        rectangle(image_with_humanface, Point(x, y), Point(w, h), Scalar(255, 0, 255), 2, 8, 0);//얼굴 주위에 사각형 그리기//
    }
    imshow("Face1", cropped_faces[0]);//첫 번째 잘라낸 얼굴 표시//
    imshow("Face2", cropped_faces[1]);//두 번째 잘라낸 얼굴 표시//
    imshow("Face3", cropped_faces[2]);//세 번째 잘라낸 얼굴 표시//
    waitKey(0);//키 입력이 있을 때까지 대기한 후 프로그램 종료//
    return 0;
}

실행 결과

C++와 OpenCV로 감지된 얼굴 영역을 자르는 방법 완벽 가이드

참고 사항

위 예제에서는 최대 3개의 얼굴을 처리하도록 배열 크기를 3으로 선언했습니다. 이미지에 더 많은 얼굴이 포함되어 있다면 배열 크기를 늘리고, 이에 맞게 윈도우 선언과 imshow() 호출을 추가해야 합니다. 또한 haarcascade_frontalface_alt.xml 파일의 경로는各自 OpenCV 설치 환경에 맞게 수정하여 사용하시기 바랍니다.