Programming/Qt

[도서 실습] Qt 5 and OpenCV 4 Computer Vision (얼굴 랜드마크(특정부위-눈, 코 등) 감지하기)

변화의 물결1 2024. 5. 10. 00:04

 

 

안녕하세요.

 

 이전 내용에서 얼굴을 감지하는 것을 해보았습니다. 그리고 얼굴의 특징점을 찾기 위해서 OpenCV의 contrib 라이브러리 소스를 컴파일하고 라이브러리 파일을 만들어 보았습니다.

 이번에는 그중에 face 라이브러리를 사용해서 얼굴에 있는 눈, 눈썹, 코, 입을 감지해 보도록 하겠습니다.


 

1. 라이브러리 확인

 

  이번에 사용할 libopencv_face 라이브러리를 이용할 것입니다. 참고로 이 라이브러리에 어떤 함수들이 확인해 볼 수 있는 링크를 걸어 두었습니다.

https://docs.opencv.org/4.5.3/d4/d48/namespacecv_1_1face.html

 

  얼굴의 특징을 잡아낼 수 있는 FacemarkKazemi, FacemarkAAM과 FacemarkLBF classes 등이 있는 것을 확인할 수 있습니다. 그리고 이 알고리즘은 머신 러닝 기반으로 데이터 모델을 필요로 하는데, 모델을 학습시키기 위해서 필요지식이 많이 필요하기 때문에 여기서는 트레이닝된 모델(pretrained model)을 불러와서 사용할 것입니다.

 

 

 

 

 - FacemarkKazemi: This implementation is based on a paper titled “One Millisecond Face Alignment with an Ensemble of Regression Trees” by V.Kazemi and J. Sullivan published in CVPR 2014. An alternative implementation of this algorithm can be found in DLIB

 

 - FacemarkAAM: This implementation uses an Active Appearance Model (AAM) and is based on an the paper titled “Optimization problems for fast AAM fitting in-the-wild” by G. Tzimiropoulos and M. Pantic, published in ICCV 2013.

 

 - FacemarkLBF: This implementation is based a paper titled “Face alignment at 3000 fps via regressing local binary features” by S. Ren published in CVPR 2014.

 

 - 위의 알고리즘들이 CVPR(Computer Vision and Pattern Recognition)의 어떤 논문을 기반으로 만들어졌다는 내용이 적혀 있습니다.

 

 

2. 사전 준비

 

 curl 명령어로 사용해서 트레이닝된 모델을 다운로드할 것입니다. 만약 윈도우 커멘드 창에서 파일이 없다고 나오면 아래 링크를 클릭해서 프로그램 다운로드한 후 설치합니다.

https://curl.se/download.html

 

 curl 명령어로 트레이닝된 파일을 다운로드합니다. 현재 폴더에 저장되는데, 어디로 복사해야 되는지 아래 내용에 설명하겠습니다. 

 

curl -O https://raw.githubusercontent.com/kurnianggoro/GSOC2017/master/data/lbfmodel.yaml

 

 

 사전 준비가 되었다면 프로그램 소스를 수정합니다.

 

 

3. capture_thread.h  수정

 

 mark_detector는 특징을 정확하게 감지하는 감지기로 사용되는 변수입니다.

 

	// ...
    #include "opencv2/face/facemark.hpp"
    // ...
    class CaptureThread : public QThread
    {
        // ...
    private:
        // ...
        cv::Ptr<cv::face::Facemark> mark_detector;
    };

 

 

 

4. capture_thread.cpp 수정

 

 while 구문 위에 코드를 작성합니다. 얼굴을 감지하기 위한 분류기(classifier)를 생성 후에 createFacemarkLBF() 함수로 인스턴스화시켜 mark_detector에게 할당해 줍니다. 그리고 트레이닝된 모델을 불러옵니다. 그러면 mark_detector 사용할 준비가 된 것입니다.

 

 QApplication이 없다고 경고가 나타날 경우 맨 위 줄에 #include <QApplication>를 추가해 줍니다.

 

 QApplication::instance()->applicationDirPath() 코드에서 경로를 확인하면, 현재 Qt가 debug 모드이므로,

D:\prj_qt\build-FacetiousW-Desktop_Qt_5_12_6_MinGW_64_bit-Debug\debug로 나타납니다. 그래서 위에서 다운로드한 yaml 파일을 debug폴더 내에 data 폴더를 만들어 복사해 오면 됩니다. 실제 release 버전에서는 최종 실행 파일이 실행되는 폴더에 data 폴더를 만들어 넣어 주면 됩니다.

 

 opencv 경로들은 각자의 환경에 맞게 다를 수 있습니다. 

 

	classifier = new cv::CascadeClassifier("D:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_default.xml");
    mark_detector = cv::face::createFacemarkLBF();
    QString model_data = QApplication::instance()->applicationDirPath() + "/data/lbfmodel.yaml";
    mark_detector->loadModel(model_data.toStdString());

 

  yaml경로를 잘못 넣게 되면 아래와 같이 에러가 발생합니다.

 

 detectFaces() 함수 내에 감지하는 코드를 추가합니다. 한 얼굴의 얼굴 랜드마크(특징점)는 vector<vector<cv::Point2f>> 타입으로 표현되는 일련의 점이며 단일 프레임에서 두 개 이상의 얼굴이 감지될 수 있으므로 이러한 복잡한 데이터 타입을 사용하여 표현해야 합니다.

 

  얼굴 랜드마크를 감지하기 위해 mark_detector의 fit함수(이미지로부터 랜드마크를 감지하는 함수)를 호출합니다. 함수 인자는 입력 프레임, 분류기로 감지한 얼굴 영역, 검색된 랜드마크를 저장하기 위한 변수를 전달합니다. fit 함수가가 0이 아닌 값을 반환하면 랜드마크를 성공적 검색한 것으로 인식합니다.

 

 얼굴 랜드마크를 얻은 후 감지된 얼굴 수만큼 반복하면서 랜드마크 각 포인트에 대해 2픽셀 원을 그리는 작업을 합니다.

 

void CaptureThread::detectFaces(cv::Mat &frame)
{
//...
 
	vector< vector<cv::Point2f> > shapes;
    if (mark_detector->fit(frame, faces, shapes)) {
        // draw facial land marks
        for (unsigned long i=0; i<faces.size(); i++) {
            for(unsigned long k=0; k<shapes[i].size(); k++) {
                // Display Circle
                cv::circle(frame, shapes[i][k], 2, color, cv::FILLED);
            }
        }
    }

 

 

 

 

 추가로 원으로 표현하는 것이 아니라 인덱스 번호로 표시하면 얼굴에 고정된 위치를 가지므로 인덱스로 얼굴 특징에 접근해서 다른 처리를 할 수 있습니다.

 

 예로 턱 윤곽선은 [0,16]이고 코는 [27,35]로 나타납니다. 그런데 모든 번호가 동일하지는 않은 것으로 보입니다. 그렇기 때문에 테스트한 후 적용해야 할 것으로 보입니다.  

//cv::circle(frame, shapes[i][k], 2, color, cv::FILLED);
// Display Point Number
QString index = QString("%1").arg(k);
cv::putText(frame, index.toStdString(), shapes[i][k], cv::FONT_HERSHEY_SIMPLEX, 0.4, color, 2);

  

 

 

 

5. FacetiousW.pro 수정

 

 우리가 사용할 face 라이브러리를 추가해 줍니다. 

 

win32 {
    INCLUDEPATH += D:/opencv/release/install/include
    LIBS += -Ld:/opencv/release/install/x64/mingw/bin \
     # ...
     -lopencv_objdetect453 \
     -lopencv_face453
}

 

 

감사합니다.

 

 

<참고 사이트>

1. Facemark : Facial Landmark Detection using OpenCV

https://learnopencv.com/facemark-facial-landmark-detection-using-opencv/

2. curl / Download

https://curl.se/download.html

3. cv::face Namespace Reference

https://docs.opencv.org/4.5.3/d4/d48/namespacecv_1_1face.html    

 

Facetious_day3.zip
0.13MB

 

반응형