kivantium活動日記

プログラムを使っていろいろやります

dlibによるHOG特徴を用いた物体検出がすごい

dlibを用いたselective searchで紹介したSegmentation as Selective Search for Object Recognitionを読んだところ、selective searchした候補領域に対してHOG特徴量を取ってSVMで物体かどうかの判定を行っていたのでHOG+SVMによる物体検出器を使ってみます。

ここではdlibの実装を使います。
dlibのPythonラッパーのインストールはdlibを用いたselective searchを参照してください。

教師データの作成

ラベリング用プログラムはOpenCVでの物体検出器作成にあるものを使います。

出力をこのプログラムでxmlに変換します。

#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(){
    ifstream ifs("train.txt");
    string filename;
    int num;
    cout << "<?xml version='1.0' encoding='ISO-8859-1'?>" << endl
        << "<?xml-stylesheet type='text/xsl' href='image_metadata_stylesheet.xsl'?>" << endl
        << "<dataset>" << endl
        << "<name>imglab dataset</name>" << endl
        << "<images>" << endl;
    while(ifs >> filename >> num && num){
        cout << "<image file=\'" << filename << "\'>" << endl;
        for(int i=0; i<num ; ++i){
           int x, y, width, height;
            ifs >> x >> y >> width >> height;
            cout << "<box top=\'" << y << "\' left=\'" << x
                << "\' width=\'" << width << "\' height=\'" << height << "\'/>" << endl;
        }
        cout << "</image>" << endl;
    }
    cout << "</images>" << endl;
    cout << "</dataset>" << endl;
    return 0;
}

100枚くらいで十分な精度が出るようです。(逆にデータが多すぎるとコアダンプします)

検出器の作成

公式のサンプル を見れば分かります。
コードをコピーして、画像を入れたディレクトリにtraining.xmlとtesting.xmlを入れる必要があります。
精度が高くなるCを頑張って探しましょう。

比較動画の作成

いつものlbpcascade_animeface.xmlとの比較動画を作るスクリプトです。detector.svmは上のサンプルを実行して得られるファイルです。

#!/usr/bin/python

import os
import sys

import dlib
from skimage import io

import cv2

cascade = cv2.CascadeClassifier("lbpcascade_animeface.xml")
if cascade.empty():
    raise Exception, 'cascade not found'

detector = dlib.simple_object_detector("detector.svm")
cap = cv2.VideoCapture(sys.argv[1])
if not cap.isOpened():
    raise Exception, 'video not found'
fourcc = cv2.cv.CV_FOURCC(*'DIVX')
out = cv2.VideoWriter('output.avi', fourcc,
    20,
    (int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)),
     int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT))))

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret == True:
        img = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
        dets = detector(img)
        faces = cascade.detectMultiScale(frame, 
                                         scaleFactor = 1.1,
                                         minNeighbors = 4,
                                         minSize = (24, 24))
        for (x, y, w, h) in faces:
            cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 255, 255), 2)
        for d in dets:
            cv2.rectangle(frame, (d.left(), d.top()), (d.right(), d.bottom()), (0, 0, 255), 2)
        out.write(frame)
    else:
        break
out.release()

結果
f:id:kivantium:20150801233427p:plain:w400

白がlbpcascade_animeface.xmlを用いた検出結果、赤が今回の手法を用いた検出結果です。
この一枚だけ貼っても何の証拠にもならないですが、完成した動画を見るとLBP特徴を使った結果よりも優れた検出結果を示しているフレームがかなりありました。訓練データの枚数が少なくていいというのも時間短縮につながります。

というわけでdlibのHOG特徴を使った物体検出器がかなり良さそうだという感触を持ちました。