前回、人の顔を認識するテストに引き続き、今度は人物を特定するための分類器を自作したいと思います。
「この顔が誰か?」が分かれば、開発の可能性が広がります。
人物特定の目標
いきなり高度な特定は難しそうなので、簡単な目標を立てます。
斜め45度を向いている少年の画像を機械学習させ、分類器を作り、似たような角度で写っている少年の画像を認識させようと思います。
分類器自作の流れ
正解画像と不正解画像をあわせて10,000枚くらい用意して、機械にひたすら学習させるようです。
そこまで頑張れないので、1枚の正解画像を変形させ、正解画像を量産する方法を取ります。
具体的な分類器作成の流れは、「OpenCVで物体検出器を作成する⑤ ~createsamples~」を、参考とさせて頂きました。
cleatesamplesが見つからない!?
参考サイトを見ながら、正解画像を量産させる「opencv_createsamples.exe」を実行させようとしたのですが、PC内を検索しても見つかりません。
他にも「opencv_calib3d2411.dll」などが見つからず。
ファイル名からの推測ですが、OpenCV2.4.11環境を用意しないとダメそうです。
Anacondaが活躍
早速、仮想環境を増やすことになりました。
AnacondaでPython2.7+OpenCV2.1.11環境を作ります。
思いのほか、備忘録が役立ちました。
1 |
conda install --channel https://conda.anaconda.org/menpo opencv |
で、opencv: 2.4.11がインストールされます。(2017/8月時点では)
作業ディレクトリを用意
分類器を作成するディレクトリは、下記のような構成になっています。
正解画像を量産
切り抜いた少年の画像をposフォルダに置きました。
これを「cleatesamples」で量産します。やり方は前述の参考サイトをご確認ください。
7,000枚以上が理想らしいですが、とりあえず50枚しか作りません。
私のディレクトリ構成だと、コマンドプロントでC:\traincascadeに移動して、下記の命令を実行します。
1 |
opencv_createsamples.exe -img ./pos/1.jpg -vec ./vec/1.vec -num 50 -bgcolor 255 -maxidev 40 -maxxangle 0.8 -maxyangle 0.8 -maxzangle 0.5 -show |
・・・。
正解画像が変形しながらが量産され、C:\traincascade\vecに「1.vec」という正解特徴データが生成されます。
不正解画像の用意
続いて、negフォルダに不正解画像を用意します。
何でもよいようですが・・・何でもよいと言われると、逆に困ります。
適当に、別人3名と、犬、ライオン、フクロウ、カエル、テントウムシを用意しました。
3,000枚以上が理想らしいですが・・・8枚で許してもらいます。
コマンドプロントで不正解画像一覧を作ります。
1 |
ls neg | xargs -I {} echo neg/{} > nglist.txt |
negフォルダにnglist.txtができました。
分類器の作成
いよいよ分類器の作成です。
分類できる手ごたえが皆無なのですが、このままやってみましょう。
コマンドプロントで
1 |
opencv_traincascade.exe -data ./cascade/trained_data/ -vec ./vec/1.vec -bg ./neg/nglist.txt -numPos 40 -numNeg 20 |
を、実行します。
・・・。
大量の学習データがあると時間がかかるのですが、動き出して26秒で完了しました。
C:\traincascade\cascade\trained_dataに、分類器のxmlが生成されます。
10個できましたが、cascade.xmlしか使わなそうです。
cascade.xmlの容量は5KB。・・・軽い。
自作分類器で顔認識のテスト
それでは少年の顔を特定できるか?自作分類器を試しましょう。
Python 3.6.1+OpenCV 3.3.0の環境に戻し、下記Pythonファイルを実行します。
import cv2 # 自作Haar-like特徴分類器の読み込み face_cascade = cv2.CascadeClassifier('traincascade/cascade.xml') # イメージファイルの読み込み img = cv2.imread('img/test9.jpg') # グレースケール変換 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 顔を検知 faces = face_cascade.detectMultiScale(gray) for (x,y,w,h) in faces: # 検知した顔を矩形で囲む cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) # 顔画像(グレースケール) roi_gray = gray[y:y+h, x:x+w] # 顔画像(カラースケール) roi_color = img[y:y+h, x:x+w] # 画像表示 cv2.imshow('img',img) # 何かキーを押したら終了 cv2.waitKey(0) cv2.destroyAllWindows()
4行目で自作分類器を読み込み、7行目で認識させたい画像を読み込みます。
まずは元画像でテスト
正解画像作成の元ととなった画像を読み込んでみます。
これはさすがに認識できなければおかしいはずです。
良かったです。少年を認識してくれました。
変なところも認識していますが・・・不正解画像の学習が、テントウムシとか8枚だけなので、仕方ないでしょう。
表情が違う画像でテスト
そして今回の目標。
ちょっと表情が違う別の画像を認識できるか試します。
・・・。
何も反応なし。
こんな軽い学習では、やっぱり無理でした!
元画像を変形してテスト
せめて、元画像をちょっと変形させたものくらい、認識してほしいです。
若干の回転と拡大をして、顔認識テスト実行・・・
そっちかよ!
少年は認識されませんでしたが、誤認はされました。
・・・いったいどれだけの精度なんでしょう!?
正解画像を回転・拡大テスト
この分類器は、回転や拡大に弱いのかもしれません。
正解画像の少年を、回転させたり、拡大縮小させてみます。
拡大は余裕で、回転も縮小も、思った以上に認識してくれます。
・・・いや、違和感があるくらい、認識しすぎです。
白背景をやめてみる
少年に、工場見学へ行ってもらいます。
これで顔認識を実行すると・・・
やはり、一気に認識されなくなりました。
少年の変形よりも、画像全体の複雑さが、認識に影響を及ぼすようです。
人物特定の分類器作成には根性と精神衛生が必要
今わかっていることは2つ。
人物特定の分類器を自作するには、大量の画像に向き合える根性が必要です。
数枚の正解画像で、なんとかなるものではありません。
そしてもう一つ、ひたすら同じ人の顔を見ていると、つらくなります。
仮に7,000枚のおじさんの画像を学習させるとしたら、精神的にまいるでしょう。
人の顔に限らず、例えば虫が嫌いな人に、虫分類器を依頼することは酷です。
開発プロデューサーは、分類器作成を依頼するなら、その人の好き嫌いを十分配慮したほうがよいです。本当に。
いろんな意味で、分類器自作は難しい!
“openCVで人物特定の分類器を自作” への1件の返信