kivantium活動日記

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

OpenCVでの物体検出器作成

OpenCVのオブジェクト検出器作成方法についての解説です。

学習データの作成

まず最初にオブジェクト検出器の学習に使う教師データを用意する必要があります。そのためにまずGUIでオブジェクトの位置を指定するGUIツールを作りました。
PythonOpenCVを使います。

#!/usr/bin/env python
#! -*- coding: utf-8 -*-

import cv2
import numpy as np
import sys

drawing = False
sx, sy = 0, 0 
gx, gy = 0, 0
rectangles = []
ok = False

def draw_circle(event,x,y,flags,param):
    global sx, sy, gx, gy, drawing

    if event == cv2.EVENT_LBUTTONDOWN:
        drawing = True
        sx,sy = x,y

    elif event == cv2.EVENT_MOUSEMOVE:
        if x > 0 and x < img.shape[1]:
            gx = x
        if y > 0 and y < img.shape[0]:
            gy = y

    elif event == cv2.EVENT_LBUTTONUP:
        drawing = False
        w = abs(sx-x)
        h = abs(sy-y)
        if w < h * 1.1 and h < w * 1.1:
            rectangles.append([(sx, sy), (x, y)])

img = np.zeros((512, 512, 3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image',draw_circle)

i = 0
while i < len(sys.argv):
    rectangles = []
    while True:
        img = cv2.imread(sys.argv[i])
        for r in rectangles:
            cv2.rectangle(img, r[0], r[1], (255,255,255), 2)
        if drawing:
            w = abs(sx-gx)
            h = abs(sy-gy)
            if w < h*1.1 and h < w*1.1:
                color = (0, 255, 0)
            else:
                color = (0, 0, 255)
            cv2.rectangle(img, (sx,sy), (gx,gy), color, 2)
        cv2.imshow('image', img)
        
        k = cv2.waitKey(1) & 0xFF
        if k == ord('d'):
            if rectangles:
                rectangles.pop()
        elif k == ord('n'):
            if len(rectangles) > 0:
                print sys.argv[i], len(rectangles), 
                for r in rectangles:
                    x = min(r[0][0], r[1][0])
                    y = min(r[0][1], r[1][1])
                    w = abs(r[0][0] - r[1][0])
                    h = abs(r[0][1] - r[1][1])
                    print x, y, w, h,
                print
            i += 1
            break
        elif k == ord('b'):
            print 'delete previous line!'
            if i > 1:
                i -= 2
                break
        elif k == ord('q'):
            sys.exit()

f:id:kivantium:20150513151347p:plain:w400


引数にオブジェクトの写ったファイル一覧を与えて起動します。
マウスで左上から右下にドラッグすると範囲が選択されます。縦横比が正方形に近い時は枠が緑になりこの状態でボタンを離すと選択が確定します。dボタンを押すと一つ前の選択が消去されます。
nボタンで次の画像へ移動し、bボタンで戻ります。この時出力にdelete previous lineと出るので後で削除してください。(手抜き実装です……)qボタンで終了します。
結果を標準出力に吐くので、これをtrain.txtという名前で保存します。

コメントアウト部を元にもどすと既存の顔検出器での結果を使って多少ラクができます。実行ファイルを同じディレクトリにlbpcascade_frontalface.xmlを置くようにしてください。

オブジェクト検出器の学習(OpenCV)

OpenCV 2.4.2で分類器を作るを参考にしました。

opencv_createsamples -info train.dat -vec train.vec -num 1000
opencv_traincascade -data cascade/ -vec train.vec -bg bg.dat -numPos 900 -numNeg 1000 -featureType LBP -mode ALL

opencv_createsamplesの-numオプションには訓練画像の個数を指定します。
opencv_traincascadeの-bgオプションにはオブジェクトの写っていない背景画像の名前をリストにしたbg.datを与えています。
実行する前にcascade/ディレクトリを作っておく必要があります。

こうするとcascade/以下にcascade.xmlが出来上がるのでOpenCVでアニメ顔検出をやってみた - kivantium活動日記と同じ要領で物体を検出します。

出来たもの
f:id:kivantium:20150521234542p:plain:w400

オブジェクト検出器の学習(dlib)

ここで説明していたC++実装は精度が低いので削除しました。
Python実装を説明した
kivantium.hateblo.jp
を参照してください。