이 글은 OpenCV를 사용하여 얼굴 인식 프로그램을 만든 뒤 그 내용에 대한 정리 글입니다.
얼굴 인식을 하는 프로그램을 만들고 싶어 자료 조사 중 FaceMark API에 대해 알게 되었습니다.
Facial Landmark Detection라고도 불리며 얼굴 인식을 하는 기능을 제공하며, 예시로 아래와 같이 인식이 가능합니다.
FaceMark API를 사용하기 위해서는 아래 툴이 설치되어 있어야합니다.
- Visual Studio 2019: https://visualstudio.microsoft.com/ko/vs/older-downloads/
- CMake: https://cmake.org/
개발 환경은 Windows 10 x64이며 Visual Studio 2019, cmake-3.23.2 버전으로 다운 받았습니다.
각 프로그램을 설치하는 것은 구글에 검색하면 잘 나옵니다.
OpenCV
FaceMark를 사용하기 위해서는 OpenCV를 우선 설치해야 합니다.
OpenCV 홈페이지에 접속하여 다운로드를 합니다.
아래와 같이 다운로드가 됩니다.
더블클릭하여 실행한 다음 아래와 같은 경로 C:\FaceMark 에 추출합니다
진행이 되며 설정한 경로에 OpenCV가 추출됩니다
dlib
FaceMark는 dlib를 이용하여 구현합니다. dlib 홈페이지에 접속하여 아래와 같이 github에 접속합니다.
링크: dlib 홈페이지, dlib github
그 다음 zip을 다운받습니다
아래와 같이 zip파일이 다운 되면 압축을 해제 합니다.
그러면 dlib-master폴더 안에 동일한 이름으로 dlib-maskter폴더가 또 생기는데 이것을 dlib로 바꿔줍니다.
이름을 수정한 dlib 폴더 내부에 build와 source폴더를 생성 해준 뒤 두 개 폴더를 제외한 나머지 파일들은 source 폴더 안으로 이동합니다.
이제 dlib 폴더를 아까 opencv를 추출한 경로(C:\FaceMark)로 이동합니다
CMake
이제 CMake를 실행하여 아래와 같이 경로를 입력한 뒤, Configure 버튼을 클릭합니다.
아래와 같이 Visual Studio 16 2019와 x64를 선택한 뒤 Finish 버튼을 클릭합니다.
진행이 완료되면 아래와 같이 붉은색으로 표시되는데 신경쓰지 말고 Generate 버튼을 클릭합니다
그러면 C:\FaceMark\dlib\build 폴더에 파일들이 생겼을 것입니다. 이 중 dlib_project.sln을 더블클릭하여 실행합니다
그리고 Release와 x64로 바꾼 뒤 ALL_BUILD를 우클릭하여 다시 빌드를 선택합니다
그럼 C:\FaceMark\dlib\build\dlib\Release경로에 dlib19.24.99_release_64bit_msvc1929.lib파일이 하나 생성 됩니다.
이 파일 이름이 너무 길으니 dlib.lib로 변경해줍니다
include, lib 폴더 생성
include할 파일과 링크할 lib파일은 모두 준비가 됐습니다.
visual로 링크하기 전, 정리를 위해 C:\FaceMark경로에 include와 lib 폴더를 각각 생성합니다.
include 폴더에는 아래 항목을 복사해 넣습니다
- C:\FaceMark\opencv\build\include\opencv2 폴더
- C:\FaceMark\dlib\source\dlib 폴더
lib 폴더에는 아래 항목을 복사해 넣습니다
- C:\FaceMark\opencv\build\x64\vc15\lib\opencv_world455.lib
- C:\FaceMark\dlib\build\dlib\Release\dlib.lib
코드 작성
Visual 2019를 실행하여 빈 프로젝트를 하나 생성하여 main.cpp를 생성해줍니다. 프로젝트명은 편한대로 생성합니다.
프로젝트를 우클릭 하여 속성을 선택합니다
구성과 플랫폼을 Release, x64로 변경합니다.
그 다음 C/C++ – 추가 포함 디렉터리에 C:\FaceMark\include를 입력합니다.
링커 – 일반 – 추가 라이브러리 디렉터리에 C:\FaceMark\lib를 입력합니다.
링커 – 입력 – 추가 종속성에 dlib.lib와 opencv_world455.lib를 입력합니다. 이 두개는 C:\FaceMark\lib경로에 있는 파일입니다
그 다음으로 C:\FaceMark\include\dlib\all\source.cpp파일을 프로젝트에 추가해줍니다.
그 다음 아래와 같이 코드를 입력합니다.
#include <iostream>
#include <dlib/opencv.h>
#include <dlib/image_processing.h>
#include <dlib/image_processing/frontal_face_detector.h>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace std;
using namespace cv;
using namespace dlib;
#define COLOR_DETECT Scalar(0, 255, 0)
// connect line
void connectLine(cv::Mat & img, full_object_detection landmarks, int iStart, int iEnd, bool isClosed = false)
{
std::vector<cv::Point> points;
for (int i = iStart ; i < iEnd ; i++)
{
points.push_back(cv::Point(landmarks.part(i).x(), landmarks.part(i).y()));
}
cv::polylines(img, points, isClosed, COLOR_DETECT, 2, 16);
}
// draw polygon
void drawPolygon(cv::Mat & img, full_object_detection landmarks)
{
// shape_predictor_68_face_landmarks
// facial landmark number: face.png
connectLine(img, landmarks, 0, 16); // 턱
connectLine(img, landmarks, 17, 21); // 왼쪽 눈썹
connectLine(img, landmarks, 22, 26); // 오른쪽 눈썹
connectLine(img, landmarks, 27, 30); // 콧대
connectLine(img, landmarks, 30, 35, true); // 낮은 코
connectLine(img, landmarks, 36, 41, true); // 왼쪽 눈
connectLine(img, landmarks, 42, 47, true); // 오른쪽 눈
connectLine(img, landmarks, 48, 59, true); // 입술 바깥쪽
connectLine(img, landmarks, 60, 67, true); // 입술 안쪽 부분
}
// dlib rectangle to opencv rect
cv::Rect dlibRectToOpencv(dlib::rectangle r)
{
return cv::Rect(cv::Point2i(r.left(), r.top()), cv::Point2i(r.right(), r.bottom()));
}
int main()
{
Mat img = imread("lenna.bmp", IMREAD_COLOR);
if (img.empty())
{
cerr << "img open fail" << endl;
return -1;
}
frontal_face_detector detector = get_frontal_face_detector();
shape_predictor landmarkDetector;
deserialize(".\\shape_predictor_68_face_landmarks.dat") >> landmarkDetector;
cv_image<bgr_pixel> dlib_img(img);
std::vector<dlib::rectangle> faceRects = detector(dlib_img);
int iFaceCount = faceRects.size();
// draw
for (int i = 0 ; i < iFaceCount ; i++)
{
full_object_detection faceLandmark = landmarkDetector(dlib_img, faceRects[i]);
drawPolygon(img, faceLandmark);
}
imshow("img", img);
waitKey();
destroyAllWindows();
return 0;
}
상단에 빌드 환경을 Release, x64로 맞춘 뒤 솔루션을 빌드합니다.
여기까지 정상적으로 따라왔다면 아래와 같이 출력창에 빌드 성공 메시지가 출력합니다.
실행 파일과 같은 위치에 파일 위치
아마 Ctrl + F5를 누르거나(F5가 아닙니다.) .exe 파일을 실행하면 opencv_world455.dll이 없다고 하거나, 프로그램이 정상적으로 실행되지 않을 수 있습니다.
[솔루션 폴더 경로]\x64\Release에 프로그램 실행을 위한 파일들이 없어서 그런 것입니다.
- lenna.bmp는 인터넷에서 찾아서 넣어준다.
- C:\FaceMark\opencv\build\x64\vc15\bin\opencv_world455.dll을 위 경로에 넣어준다
- shape_predictor_68_face_landmarks.dat파일은 얼굴 모델이 학습된 dat 파일인데 구글에 dlib model이라고 검색 한뒤 github에서 다운받을 수 있다.
– github: https://github.com/davisking/dlib-models
– bz2: http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2
그 다음 실행해서 확인합니다.
각 점에 대한 정보는 아래와 같습니다
조금만 활용하면 아래와 같이 동영상에서 얼굴 인식도 가능합니다
추가적으로 찾아보니 구글에서 얼굴 인식과 관련하여 MediaPipe라는것도 있습니다.
MediaPipe는 얼굴 인식 뿐만 아니라 손 인식, 몸 인식 등 3D로 제공해줍니다.