dlibを用いた顔検出器と物体検出器とその学習 - Stimulator

Stimulator

機械学習とか好きな技術話とかエンジニア的な話とかを書く

dlibを用いた顔検出器と物体検出器とその学習

- はじめに -

dlibのSimple_Object_Detectorクラスを使った物体検出用カスケードの学習をする記事。

dlibは機械学習ライブラリとして2006年から始まったプロジェクトで、基本的なSVMや線形アルゴリズム、Bayesian Network等に加えて、機械学習関係で用いるような画像処理ツールやグラフツールが付属している。

https://dlib.net

この素敵な図を見たことある人も居ると思う
https://dlib.net/ml_guide.svg


dlibは画像からの物体検出として顔検出を代表としたオブジェクト検出用のクラスが用意されている。
中身はHoG+SVMとシンプルな構成だが、矩形情報と正例画像を与えるだけで、学習用サンプルを生成し、HoGフィルターのパラメータ調整や学習を行ってくれるAPIがある。
C++Pythonをサポートしており、以下からはUbuntu 14.04デフォルトのPython 2.7とdlib v19.0を用いる。


- dlibのインストール -

Ubuntu環境へのインストールならこの記事が分かりやすいらしい。

一応コマンドだけ貼っておくので上から実行してけばUbuntu 14.04ならワンパン。

sudo apt-get update
sudo apt-get upgrade

sudo apt-get install python-setuptools
sudo apt-get install python-pip

sudo pip install numpy
sudo apt-get install liblapack-dev libatlas-base-dev gfortran g++
sudo pip install scipy
sudo pip install matplotlib

sudo wget http://downloads.sourceforge.net/project/opencvlibrary/opencv-unix/3.0.0/opencv-3.0.0.zip
sudo apt-get install unzip
sudo unzip opencv-3.0.0.zip
sudo rm opencv-3.0.0.zip

sudo apt-get install build-essential libgtk2.0-dev libjpeg-dev libtiff5-dev libjasper-dev libopenexr-dev cmake python-dev python-numpy python-tk libtbb-dev libeigen3-dev yasm libfaac-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev libx264-dev libqt4-dev libqt4-opengl-dev sphinx-common texlive-latex-extra libv4l-dev libdc1394-22-dev libavcodec-dev libavformat-dev libswscale-dev default-jdk ant libvtk5-qt4-dev

sudo apt-get install cmake
cd opencv-3.0.0
sudo cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D BUILD_NEW_PYTHON_SUPPORT=ON -D WITH_V4L=ON -D WITH_FFMPEG=OFF -D BUILD_opencv_python2=ON .
// ここでの16はコア数。自分のコア数はnprocコマンド辺りで確認
sudo make -j16
sudo make install

cd ..
sudo cp opencv-3.0.0/lib/cv2.so /usr/local/lib/python2.7/site-packages/

//-----------
下記シンボリックリンクを貼らないとopencvをimportする時エラーが出る
libdc1394 error: Failed to initialize libdc1394
http://stackoverflow.com/questions/29274638/opencv-libdc1394-error-failed-to-initialize-libdc1394
カメラとかのハードウェア用ドライバが邪魔するせいらしく、dlibやopencv使用自体に問題はない。
環境次第で再起動毎にシンボリックリンク貼り直す必要がある。具体的な解決策はまだないっぽい。
//-----------

sudo ln /dev/null /dev/raw1394

//-----------
python
import cv2 
でチェック
//-----------

sudo apt-get install git

sudo pip install cython
sudo pip install scikit-image

sudo apt-get install python-dev python-numpy
sudo apt-get install libboost-dev
sudo apt-get install libboost-python-dev
sudo apt-get install libboost-system-dev

sudo pip install dlib

//-----------
python
import dlib 
でチェック
//-----------


多分これでdlibのインストールは出来ると思う。Permission deniedとかはよしなに。


- 最もシンプルな顔検出機能を使う -

dlibは標準で顔検出用にfrontal_face_detector()を提供している。
こののブログの他記事でも述べているが、OpenCVの標準の顔検出カスケードよりは遥かに性能が良いと思う。

シンプルに顔検出器を使ってテストしたい場合は下のようなスクリプトで簡単にできる。

#! /usr/bin/python
# -*- coding: utf-8 -*-
u"""dlibによる顔画像検出."""
import cv2
import dlib

# 画像ファイルパスを指定
sample_img_path = 'sample.jpg'

def facedetector_dlib(img, image_path):
    try:
        detector = dlib.get_frontal_face_detector()
        # RGB変換 (opencv形式からskimage形式に変換)
        img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        # frontal_face_detectorクラスは矩形, スコア, サブ検出器の結果を返す
        dets, scores, idx = detector.run(img_rgb, 0)
        # 矩形の色
        color = (0, 0, 255)
        s = ''
        if len(dets) > 0:
            # 顔画像ありと判断された場合
            for i, rect in enumerate(dets):
                # detsが矩形, scoreはスコア、idxはサブ検出器の結果(0.0がメインで数が大きい程弱い)
                # print rect, scores[i], idx[i]
                cv2.rectangle(img, (rect.left(), rect.top()), (rect.right(), rect.bottom()), color, thickness=10)
                s += (str(rect.left()) + ' ' + str(rect.top()) + ' ' + str(rect.right()) + ' ' + str(rect.bottom()) + ' ')
            s += image_path
        # 矩形が書き込まれた画像とs = 'x1 y1 x2 y2 x1 y1 x2 y2 file_name'
        # 顔が無ければ s='' が返る
        return img, s
    except:
        # メモリエラーの時など
        return img, ""

if __name__ == '__main__':
    img = cv2.imread(sample_img_path)
    img, s = facedetector_dlib(img, sample_img_path)
    cv2.imwrite('output_' + sample_img_path, img)
    f = open('./rect.txt', 'w')
    f.write(s)
    f.close()

引数には画像とupsample_numの値を与えてやる。upsample_numは多分selective searchで見る枚数か回転拡大縮小で見る枚数を増やしているんだと思う。精度は向上するが、その分探索時間とメモリをめっちゃ使う。
返り値としては顔の矩形位置座標と各スコア、サブ検出器の結果が返ってくる。スコアは割と信用できるので使い勝手は良い。

Google APIの時と同じく例によって、画像をまとめてdlibの顔検出に投げるスクリプトを下記Gitリポジトリにまとめておいた。
いつかGoogleの方とまとめるかも。

https://github.com/vaaaaanquish/dlib_detection_python_script


- 一応検証 -

例のごとく適当にテスト
入力画像は最近コミケでのコスプレが可愛かった河村友歌ちゃん。
なんかもう顔検出系のデモをやる時は毎回お世話になってるナイスフリー素材。

入力
f:id:vaaaaaanquish:20160815033016j:plain

出力
f:id:vaaaaaanquish:20160815033035j:plain


はいかわいい。


- なんかおわりに -

なんかコード貼ったら長くなったので、Simple_Object_Detectorの学習に関する内容は次の記事に書いときます。

なんかごめん。


追記:書きました。
vaaaaaanquish.hatenablog.com