Core Imageの顔認識をOS Xで - その8 [献立]
とりあえずひとつのアプリに仕上げた。こんなの。
これでOpenCVとCore Imageの顔認識を比較してみたい。
アプリ全体としてはマルチスレッドには書いていない。
変更できるパラメータとしては
ということでこんなアプリになった。 検出した顔と目と口にそれぞれ色の違う丸を置くようにした。
まだパラメータの切り替えのときにリークが起こってる。まあ1フレームごとに実メモリ領域が増えていくよりはマシ。
ところでFaceTimeカメラはAVMediaTypeVideoのデフォルトデバイスとして選択されると(Referenceにはないけど)ヘッダに書いてあるので、決めうちになっている。
もちろん、認識精度や実行効率はOpenCVとCIDetectorのアルゴリズムや実装よりは、haar学習データのほうに依存するので、学習データ次第で結果は逆転する。
OpenCV用のhaar学習データは、顔はOpenCVに昔から付属しているhaarcascade_frontalface_alt2.xmlで、目と口はここにある、ojoI.xml、ojoD.xml、Mouth.xmlを使っている。
最近なかなかオープンソースの学習データがみあたらない。0から学習データを叩き上げるのはやっぱり大変だし。それやるぐらいなら「尻検出」(画像にある尻を検出してそのしりたぶの上に「しり」と書く別名「田村信検出」)やりたいし。
OpenCVは1/4のピクセル数(320x180)で平均150%ぐらいのCPU負荷がある。100%を超えるということはcvHaarDetectObjects()の中でマルチスレッドに展開しているということになる。顔を近寄せて大きくすると遅くなる。これは目や口の検出の負荷が探索面積が増えることで上がってるということだろう。遅くなるだけで負荷そのものはあまり変化はない。Instrumentsで見るとcvHaarDetectObjects()は平均でアプリ全体の30%ちょっとの時間を費やしている。かなり重い。
いっぽうCIDetectorはだいたいCPUの負荷が70%台でOpenCVの半分ぐらい。
やっぱりマルチプラットフォームは不利ということだろう。CIDetectorはiOSに載せるためにパフォーマンスのチューニングはされているだろうからできることは精一杯やってるだろう。
目や口の検出はCIDetectorのほうがOpenCVより高い。OpenCVでは顔検出のCvRectの中でまったく新しく目や口を検出し直しているが、CIDetectorのほうはどうやってるのかよくわからない。おそらく顔検出のカスケードの結果を利用してるんだろう。ひょっとするともっとズルしてるかもしれない。
これは案外正解で、かなり検出が安定になる。ただしAccuracyがHighでないと誤検出が多くてTracking IDがどんどんインクリメントされてしまう。
また予想できるように、動きが速いとついて来れない。
そう言う違いとは別に、CIDetectorのTrackingの機能はOpenCVにはなくて便利である。OpenCVを使う場合、以前のフレームを覚えておいてKalmanフィルタで予測しながら追跡するか、あるいは最初に検出した顔をSURFなどの特徴検出であとのフレームから探し出す、などという方法が考えられる。これ自身はプログラミングの面白い問題だと思える。ちなみに、CIDetectorはTrackingをONにしたとき、顔の追跡がKalmanフィルタっぽい動きをしているようにも思える。
急いで実装したいときはやはりCIDetectorを使うのがバカチョンでいいだろう。でもちょっと違うことをさせたい、と考えてもほとんどパラメータもないしアルゴリズムも定かではない。じっくり新しいことをやりたいならOpenCVか、あるいは独自実装(「車輪の再発明」と多くの人は言うけど、車輪の再発明も僕は無駄ではないと思っている)ということもいいだろう。
とはいうものの、僕のようにマルチプラットフォームに興味のないプログラマはCIDetectorを使う方が簡単で便利である。
iOSとの比較というのも面白いかもしれない。iOSとOS Xでどのくらいパフォーマンスの差があるのかはしらないけど、CIDetectorを動画で使うのはけっこうつらいのではないか。しかしまあ、iOSはたくさんの人がやってるので、僕がやることではないだろう。
これでOpenCVとCore Imageの顔認識を比較してみたい。
5.6 残りの作業
あとは普通のアプリと同じようにAppDelegateに全部をまとめて、ユーザインターフェイスを作っててきとうにKey ValueコーディングやIBActionで動くようにしてやればいい。このへんはいつもと同じなので省略。アプリ全体としてはマルチスレッドには書いていない。
変更できるパラメータとしては
- CIDetectorとOpenCVの切り替え
- CIDetectorはAccuracyとTrackingのオンオフ
- OpenCVには画像のダウンサンプル比(スケーリング)
- OpenCVで目と口も検出するかどうか
ということでこんなアプリになった。 検出した顔と目と口にそれぞれ色の違う丸を置くようにした。
まだパラメータの切り替えのときにリークが起こってる。まあ1フレームごとに実メモリ領域が増えていくよりはマシ。
ところでFaceTimeカメラはAVMediaTypeVideoのデフォルトデバイスとして選択されると(Referenceにはないけど)ヘッダに書いてあるので、決めうちになっている。
6 顔認識の違い
結果をどうまとめるか、というのはなかなか難しい。6.1 条件
まずどういう条件で比較したか、を示しておく。 ハードはiMac21.5-inch Late2012 Core i5 2.7GHz メモリ8GBで、ビルトインのFaceTimeカメラを入力にした。FaceTimeカメラは1280x960という中途半端に高いピクセル数を持っている。CIDetectorにはこのまま渡して、OpenCVにはピクセル数をスケーリングして渡すことにした。もちろん、認識精度や実行効率はOpenCVとCIDetectorのアルゴリズムや実装よりは、haar学習データのほうに依存するので、学習データ次第で結果は逆転する。
OpenCV用のhaar学習データは、顔はOpenCVに昔から付属しているhaarcascade_frontalface_alt2.xmlで、目と口はここにある、ojoI.xml、ojoD.xml、Mouth.xmlを使っている。
最近なかなかオープンソースの学習データがみあたらない。0から学習データを叩き上げるのはやっぱり大変だし。それやるぐらいなら「尻検出」(画像にある尻を検出してそのしりたぶの上に「しり」と書く別名「田村信検出」)やりたいし。
6.2 負荷
6.2.1 顔が画面に一つの場合
FaceTimeカメラで自分撮りしてみたが、iMacが壁を背にしていて照明の条件が良くない。適当な写真をカメラで写して比較した。OpenCVは1/4のピクセル数(320x180)で平均150%ぐらいのCPU負荷がある。100%を超えるということはcvHaarDetectObjects()の中でマルチスレッドに展開しているということになる。顔を近寄せて大きくすると遅くなる。これは目や口の検出の負荷が探索面積が増えることで上がってるということだろう。遅くなるだけで負荷そのものはあまり変化はない。Instrumentsで見るとcvHaarDetectObjects()は平均でアプリ全体の30%ちょっとの時間を費やしている。かなり重い。
いっぽうCIDetectorはだいたいCPUの負荷が70%台でOpenCVの半分ぐらい。
やっぱりマルチプラットフォームは不利ということだろう。CIDetectorはiOSに載せるためにパフォーマンスのチューニングはされているだろうからできることは精一杯やってるだろう。
6.3 検出精度
CIDetectorのTrackingをオフにするとOpenCVととんとん。斜めの顔はCIDetectorのほうが、横顔はOpenCVのほうが強そう。CIDetectorのAccuracyをHighにすると、大きな顔のときフレーム落ちがはげしい。Lowにするとフレーム落ちはなくなるけど、やはりその通り精度が落ちてフレームごとに感出される顔の位置や大きさのバラツキがかなり増える。目や口の検出はCIDetectorのほうがOpenCVより高い。OpenCVでは顔検出のCvRectの中でまったく新しく目や口を検出し直しているが、CIDetectorのほうはどうやってるのかよくわからない。おそらく顔検出のカスケードの結果を利用してるんだろう。ひょっとするともっとズルしてるかもしれない。
6.4 CIDetectorのTracking
CIDetectorにはTrackingというパラメータがあって同じ顔を追いかけ続けることができる。これはフレーム間でそれほど位置や大きさの変化は大きくないと仮定して、それまでのフレームでの検出結果を利用していると思われる。これは案外正解で、かなり検出が安定になる。ただしAccuracyがHighでないと誤検出が多くてTracking IDがどんどんインクリメントされてしまう。
また予想できるように、動きが速いとついて来れない。
6.5 顔の数による違い
CIDetectorもOpenCVも検出可能な顔がたくさんあると遅くなる。またメモリの要求量も一気に増える。CIDetectorの方が顔の数に対して動作の変化が大きいような気がする。7 結論
非常に当たり前だけど、やっぱりプラットフォーム依存型のCIDetectorのほうが効率の観点からは有利である。また、OpenCVは十分叩き上げた学習データではないし、Appleが金にあかせてデータを作り込むことができるのでプロプライエタリなCIDetectorのほうが有利である。単純比較ではどうしてもOpenCVは不利になってしまう。そう言う違いとは別に、CIDetectorのTrackingの機能はOpenCVにはなくて便利である。OpenCVを使う場合、以前のフレームを覚えておいてKalmanフィルタで予測しながら追跡するか、あるいは最初に検出した顔をSURFなどの特徴検出であとのフレームから探し出す、などという方法が考えられる。これ自身はプログラミングの面白い問題だと思える。ちなみに、CIDetectorはTrackingをONにしたとき、顔の追跡がKalmanフィルタっぽい動きをしているようにも思える。
急いで実装したいときはやはりCIDetectorを使うのがバカチョンでいいだろう。でもちょっと違うことをさせたい、と考えてもほとんどパラメータもないしアルゴリズムも定かではない。じっくり新しいことをやりたいならOpenCVか、あるいは独自実装(「車輪の再発明」と多くの人は言うけど、車輪の再発明も僕は無駄ではないと思っている)ということもいいだろう。
とはいうものの、僕のようにマルチプラットフォームに興味のないプログラマはCIDetectorを使う方が簡単で便利である。
iOSとの比較というのも面白いかもしれない。iOSとOS Xでどのくらいパフォーマンスの差があるのかはしらないけど、CIDetectorを動画で使うのはけっこうつらいのではないか。しかしまあ、iOSはたくさんの人がやってるので、僕がやることではないだろう。
2013-08-03 22:57
nice!(0)
コメント(0)
トラックバック(0)
コメント 0