技術屋卵の足跡

いつか振り返ったときにどれだけ這いずり回ったかを確認したい

OpenCVのCascade分類器を複数のpos画像で学習する

今回もOpenCVの話。これはOpenCVSharpに限った話でもなく、PythonでもC++でも使えるのでまだ需要があるかもしれない。 普通Cascade分類器を使うときは学習済みのものを使うと思うが、大量の電気を使って自作してみたい人向けの情報。

OpenCVの標準のやり方ではopencv_createsamplesを用いて正解の画像を水増ししつつ、opencv_traincascadeで不正解の画像と合成して学習済みのxmlファイルを作成する。

今回紹介するのはこのopencv_createsamplesをちょっとだけ楽に使える方法。

opencv_createsamplesは一枚の画像もしくはinfoファイルと呼ばれるどのファイルのどこを処理するか記述したファイルから、角度や明るさを変更した画像を大量に生成してくれるユーティリティ。

詳しい使い方はmanを参照するとよくわかる。

manpages.ubuntu.com

一枚の画像を渡す分には普通にパスを渡すだけで十分なので簡単だが、複数のファイルを一気に処理しようとする際にはinfoファイルが必要になる。infoファイルは以下のようなフォーマットで、自動生成するのもちょっとめんどくさいようなものなのでこれをどうにかしたい。

./path/to/image1 x1 y1 width1 height1
./path/to/image2 x21 y21 width21 height21 x22 y22 width22 height22 ...
...
./path/to/imageN xN yN widthN heightN ...

これを自動生成するにはcascade分類器などが必要で、卵と鶏問題にもつながりそうな感じもするし、範囲の制限をしないで複数の画像を処理したい場合にはちょっと面倒な気がする。

そこでmergevecというユーティリティをつかって、opencv_createsamplesで一枚の画像から1つのvecファイルを作成し、複数のvecファイルを合成して1つのvecファイルを作成する。こうすると簡単にスクリプトなりバッチファイルを用意するだけで、複数の正解画像から水増ししたvecファイルを作れる。

github.com

使い方はvecファイルを一つのディレクトリにまとめて、python mergevec.py -v <vecファイルのあるdir> -o <出力先>

したがって次のようなファイル構成ではこんな感じでコマンドを実行すればよい。

├── mergevec.py
├── neg
│   ├── 1.png
│            ...
│   └── 100.png
└── pos
     ├── 1.png
             ...
     └── 10.png
# vecファイルの生成
seq 1 10|xargs -I @ opencv_createsamples -img pos/@.png -num 500 -vec pos/@.vec
# mergevecを使用
python mergevec.py mergevec -v pos -o pos.vec
# 出力dirを作成
mkdir output
# 不正解画像のリストを作成
find neg > neg.txt
# 学習
opencv_traincascade -data output -vec pos.vec -bg neg.txt -numPos 4500 -numNeg 100

こうやるだけで簡単に学習できた。

あとがき

確かにこの方法で学習はできるけど、上記のpos*4500,neg*100は30分くらいで処理が終わるが、レベルではまともに使えるレベルではなかった*1。ネットでは16時間回したとか色々出ているので、やっぱり個人レベルで学習しようとするには相当覚悟してファイルを集めて、PCを稼働させなければいけないのかもしれない。

*1:まあ圧倒的に不正解が少ないが