본문 바로가기
코딩/OpenCV

[c++ opencv] haarcascades를 이용하여 얼굴인식하고 얼굴만 모자이크 처리하는 방법

by DIYver 2021. 3. 15.

본문 목표

머신러닝과 같이 영상인식의 사용이 부쩍 많아진 요즘 얼굴인식은 정말 흔하게 사용하는 기술이 되었다.

B612 같은 카메라 보정 어플도 그렇고,

코로나 시국에 발열체크 하는 기계에서도 그렇고 정말 많이 사용하는 기술이다.

 

이러한 얼굴인식을 사용해보고, 모자이크 처리를 해보도록 한다.

 

 

키워드 : 얼굴인식, faceface_classifier, 모자이크처리

 

 

 

 

 

알아볼 함수 원형

- 함수 기능 ( Function Name )

face_classifier.detectMultiScale(grayframe, faces,

                    1.1, // increase search scale by 10% each pass

                    3,   // merge groups of three detections

                    CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_SCALE_IMAGE,

                    Size(30, 30)

                );

 

functionface_classifierface_classifier.detectMultiScale( src, object, scaleFactor, minNeighbors, flags, minSizemaxSize

src - 얼굴을 찾을 원본 이미지

object - 이미지에서 찾은 얼굴에 대한 정보를 담을 vector

  얼굴 좌표와 얼굴 크기에 대한 정보를 저장함

scaleFactor - 얼굴 찾는 연산에 쓰임, 1.1이 제일 잘 되는듯?

minNeighbors - 얼굴 찾는 연산에 인근 픽셀 계산에 쓰이는듯? 3이 가장 무난한 결과를 보여줌flags - 찾고자 하는 옵션을 선택해 주면 됨, 위에 코드에서 사용한 옵션이 무난함  다른 옵션은 굳이 사용할 필요 없을듯?minSize - 최소 얼굴 사이즈, 노이즈 안 잡히게 최소 사이즈 조절해주면 됨maxSize - 최대 얼굴 사이즈, 노이즈 안 잡히게 최대 사이즈 조절해주면 됨

 

 

 

 

 

일단 함수 기능의 원리를 이해하는 것이 필요하다.

 

haarcascades 라는 단어를 쪼개서 볼 필요가 있다.

haar + cascades  = haarcascades

 

Haar

- 하르 특징을 뜻한다.

왼쪽을 보면 픽셀 연산을 통해서 특정 밝기값을 기준으로 thresholding을 한 이미지에서

규칙을 찾는 것이다.

 

오른쪽을 보면 사람의 경우 이마와 눈에서 음영의 규칙이 발생하는데

이 규칙을 이용하는 것이 하르 특징이다.

 

cascades 는 풍성하게 늘어진 것이라는 의미로

여기서는 규칙이 풍성하게 늘어진? 이라고 이해하고 넘어가면 되겠다.

 

아무튼 opencv에서 기본적으로 제공하는 얼굴인식 알고리즘은

이미지에서 규칙을 찾아서 얼굴인 것 같은 부분을 찾아주는 것이다.

 

다만 단점이 있다면, 꼭 얼굴 뿐만이 아니라 이미지 전역에서 해당 규칙과 같은 부분도 얼굴이라고 하기 때문에 정확성이 떨어지기도 한다.

그리고 모든 픽셀을 연산처리하고 규칙을 찾는 것이기 때문에 속도가 느린편이다.

따라서 빠르고 정확하게 얼굴을 찾으려면 개발자가 엄청 고생을 해야한다.

 

 

 

 

 

 

 

코드 테스트 결과

- CODE

#include <stdio.h>
#include <iostream>


#include <opencv2/opencv.hpp>
#include <stdlib.h>



using namespace std;
using namespace cv;



int main()
{
    char buffer;

    Mat img;

    VideoCapture capture(0);

    CascadeClassifier face_classifier;

    //face_classifier.load("C:/opencv348/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml");

    face_classifier.load("C:/opencv348/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml");

    Mat frame;



    if (!capture.isOpened()) {

        std::cerr << "Could not open camera" << std::endl;

        return -1;

    }



    while (1) { //오픈에 성공한 경우 sendCommand()를 통해 계속적으로 데이터를 전송한다. 전송에 실패 할 경우 failed 메시지를 출력한다.


        bool frame_valid = true;

        capture >> frame;
        try {


            // get a new frame from webcam

            capture >> frame;


        }
        catch (Exception& e) {


            cerr << "Exception occurred. Ignoring frame... " << e.err << std::endl;

            frame_valid = false;


        }

        if (frame_valid) {

            try {

                Mat grayframe;

                cvtColor(frame, grayframe, CV_BGR2GRAY);

                equalizeHist(grayframe, grayframe);

                vector<Rect> faces;


                face_classifier.detectMultiScale(grayframe, faces,

                    1.1, // increase search scale by 10% each pass

                    3,   // merge groups of three detections

                    CV_HAAR_FIND_BIGGEST_OBJECT | CV_HAAR_SCALE_IMAGE,

                    Size(30, 30)

                );
               

                Mat img_mosaic;
                Mat frame_original;
                frame.copyTo(frame_original);

                for (int i = 0; i < faces.size(); i++) {

                    Point lb(faces[i].x + faces[i].width, faces[i].y + faces[i].height);

                    Point tr(faces[i].x, faces[i].y);

                    img_mosaic = frame(Rect(lb, tr));
                    Mat img_temp;

                    resize(img_mosaic, img_temp, Size(img_mosaic.rows / 8, img_mosaic.cols / 8));
                    resize(img_temp, img_mosaic,Size(img_mosaic.rows, img_mosaic.cols));
                    rectangle(frame, lb, tr, Scalar(100 * (i - 2), 255, 255 * i), 3, 4, 0);
                    rectangle(frame_original, lb, tr, Scalar(100 * (i - 2), 255, 255 * i), 3, 4, 0);

                }

                imshow("mosaic",frame);
                imshow("webcam", frame_original);

            }

            catch (Exception& e) {

                cerr << "Exception occurred. Ignoring frame... " << e.err << std::endl;

            }

        }

        if (waitKey(30) == 27) break;

    }

    return 0;

}


 

일반적으로 OpenCV 3.4.8 버전을 사용한다면 문제없이 작동한다.

다만 한가지 주의해야할 것이 자신의 컴퓨터에 OpenCV가 설치된 폴더를 알아야 한다.

 

이 부분에서 각자 OpenCV가 설치된 폴더로 경로를 바꿔줘야 한다.

이 파일에 얼굴의 패턴이 저장되어 있기 때문에 꼭 필요하다.

 

 

 

 

 

 

 

 

 

 

 

- RESULT

youtu.be/V63BACrb9Ug

결과는 유튜브에 동영상으로 올려놨다.

왼쪽에는 얼굴을 모자이크하였고, 오른쪽은 얼굴을 찾아 표시만 하게 하였다.

 

얼굴 찾는 함수를 통해서

vector에 얼굴에 대한 정보들이 담기게 되기때문에

모자이크를 하기 위한 정보들로 잘 사용해주면 된다.

 

이 코드에서 얼굴의 좌상단 point와 우하단 point를 얻어낼 수 있고,

이 정보로 사각형을 그려넣을 수도 있다.

그리고 RoI 로 설정하여 해당부분만 모자이크를 할 수도 있다.

 

모자이크 방법은 간단하다.

resize() 를 이용해서 축소시키고 다시 강제로 키우면 된다.

그러면 화질 저하가 일어나서 블러가 되는 효과를 가져다 준다.

 

모자이크에 대한 코드는 위와 같다.

현재는 원본 크기에서 8배 만큼 축소시켰는데,

더 강한 모자이크를 원하는 경우 축소비율을 더 크게 하면 된다.

16으로 나누면 더 확실해 진다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

도움이 되었거나, 문제가 있는 경우 댓글로 알려주세요~!

감사의 댓글은 작성자에게 큰 힘이 됩니다 ^^

댓글