Help us understand the problem. What is going on with this article?

Xcode で dlib を使用して顔認識を行う

More than 3 years have passed since last update.

概要

C++ のすごいライブラリ dlib のデモ webcam_face_pose_ex.cpp を参考に、Xcode で作った既存のプロジェクトに dlib を組み込んで顔認識を行います。

背景

OpenCV の CascadeClassifier を使った場合は顔のパーツの位置を認識することはできますが、顔の輪郭や眉の位置などの特徴点を取ることができません。

dlib の get_frontal_face_detector を使うことによってかなり詳細なパーツの特徴点を取得することができます。

環境

  • OSX El Capitan (10.11.2)
  • Xcode 7.2
  • MacBook Air (13-inch, Mid 2013)

準備

OpenCV

OpenCV をインストールします。

brew tap homebrew/science
brew install opencv

/usr/local/Cellar/opencv/2.4.12/lib から必要なライブラリのファイルを Link Binary With Libraries に追加します。

スクリーンショット 2015-12-18 14.04.23.png
必要なライブラリ

プロジェクトの設定

OpenCVのヘッダファイルを Header Search Paths に追加します。

スクリーンショット 2015-12-18 14.00.01.png

追記 (2016/3/1)

X11 は追加しなくて大丈夫です

dlib

dlib はソースコードをまるごとプロジェクトのディレクトリにコピーして、 dlib/all/source.cpp だけプロジェクトに追加します。

Header Search Paths に dlib のディレクトリを追加したり、source.cpp をプロジェクトに追加しなかったりすると "_USER_ERROR__missing_dlib_all_source_cpp_file__OR__inconsistent_use_of_DEBUG_or_ENABLE_ASSERTS_preprocessor_directives_" というエラーが出ます。
私はここで詰まってしばらくわからなかったので、Qiita で共有することで解決の助けになれば幸いです。

追記 (2016/3/1)

dlib を X11 なしで使うため、フラグ DLIB_NO_GUI_SUPPORT を設定します。

下記のように source.cpp の先頭に書き込むとか、

source.cpp
#define DLIB_NO_GUI_SUPPORT
...

コード

//
//  main.cpp
//  FaceTracker
//
//  Created by ryohey on 2015/12/11.
//

#include <iostream>
#include <cv.h>
#include <highgui.h>
#include <ctype.h>

#include "dlib/opencv.h"
#include "dlib/image_processing/frontal_face_detector.h"
#include "dlib/image_processing.h"

void drawObjects(cv::Mat& image, std::vector<cv::Rect>& objects, cv::Scalar color, CvPoint offset = cvPoint(0, 0)) {

    for (auto r : objects) {
        cv::rectangle(image,
                      cvPoint(r.x + offset.x,           r.y + offset.y),
                      cvPoint(r.x + offset.x + r.width, r.y + offset.y + r.height),
                      color);
    }
}

int main(int argc, char **argv) {
    std::string path(argv[0]);
    const std::string RESOURCE_DIR = path.substr(0, path.find_last_of("\\/") + 1);
    const std::string FACE_LANDMARK_MODEL = "shape_predictor_68_face_landmarks.dat";

    dlib::frontal_face_detector detector = dlib::get_frontal_face_detector();
    dlib::shape_predictor pose_model;
    dlib::deserialize(RESOURCE_DIR + FACE_LANDMARK_MODEL) >> pose_model;

    const double w = 720, h = 480;

    cv::VideoCapture capture(0);
    capture.set(CV_CAP_PROP_FRAME_WIDTH, w);
    capture.set(CV_CAP_PROP_FRAME_HEIGHT, h);

    cvNamedWindow("Capture", CV_WINDOW_AUTOSIZE);

    while (1)
    {
        cv::Mat frame;
        capture.read(frame);

        // dlib
        {
            dlib::cv_image<dlib::bgr_pixel> cimg(frame);

            // Detect faces
            std::vector<dlib::rectangle> faces = detector(cimg);

            // Find the pose of each face.
            std::vector<dlib::full_object_detection> shapes;

            for (auto face: faces) {
                shapes.push_back(pose_model(cimg, face));
            }

            std::vector<cv::Rect> objects;

            // 点のサイズ
            const int s = 2;

            for (auto shape: shapes) {
                auto rect = shape.get_rect();
                objects.push_back((cv::Rect){
                    (int)rect.left(), (int)rect.top(),
                    (int)rect.width(), (int)rect.height()
                });

                for (auto i = 0; i < shape.num_parts(); i++) {
                    auto part = shape.part(i);

                    objects.push_back((cv::Rect){
                        (int)part.x(), (int)part.y(),
                        s, s
                    });
                }
            }

            if (objects.size() > 0) {
                drawObjects(frame, objects, cv::Scalar(255, 255, 0));
            }
        }

        IplImage frame_ = frame;
        cvShowImage("Capture", &frame_);

        auto c = cvWaitKey(2);
        if (c == '\x1b') {
            break;
        }
    }

    cvDestroyWindow("Capture");

    return 0;
}

結果

https://gyazo.com/86f0058c2345be238aaac9e0be496176

Debug ビルドだとかなり遅かったので Release ビルドにしたらすごい速くなりました。Macbook Air ですが解像度 720x480 でスムーズに動きました。

最小の認識サイズがあるのか、320x240 の時は顔をカメラに近づけないと認識しませんでしたが、720x480 の場合だと後ろの方の人もちゃんと認識されました。
横顔は多少弱いようですが、OpenCV の Haar-Like 特徴を使った場合よりもちゃんと追従し、パーツもかなり詳細に取得できています。

ryohey
covelline
もっと楽しい明日をつくる
http://covelline.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away