iOS SDK では Core Image の CIDetector クラスで簡単に顔認識をおこなうことができます。iOS 7 からは、笑顔やまばたきの検出も可能に なりました。
が、CIDetector は detectorOfType:context:options:
というメソッドの第1引数で Detector Type を指定できる設計になっているものの、
public let CIDetectorTypeFace: String
public let CIDetectorTypeRectangle: String
public let CIDetectorTypeQRCode: String
public let CIDetectorTypeText: String
Detector Types - CIDetector Class Reference
と、4つしか定義されてないので、結局のところ 顔・矩形・QRコード・文字領域しか認識できません。
##車やロゴや犬やネコを認識する
OpenCV には顔検出用の手法として、 Haar分類器 というものが実装されています。
この手法の詳細はここでは省略しますが、この手法は、 顔検出だけでなく、車やペット等、さまざまな対象を検出 するのに広く使用されています。
で、このHaar分類器は、オブジェクトを検出するために、 あらかじめその対象の特徴を学習させて作成した特徴量データ (正しくは識別器をカスケードさせたもの)の入っているxmlファイル(この記事ではカスケードファイルと呼ぶことにします)を使用します。
###OpenCVに同梱されているカスケードファイル
OpenCV を git clone (参考:OpenCV for iOSの使い方)すると、data/haarcascades ディレクトリに、下記のカスケードファイルが入っています(2013年12月2日現在)。
- 顔
- haarcascade_frontalface_default.xml
- haarcascade_frontalface_alt.xml
- haarcascade_frontalface_alt2.xml
- haarcascade_frontalface_alt_tree.xml
- haarcascade_profileface.xml
- 目
- haarcascade_eye.xml
- haarcascade_eye_tree_eyeglasses.xml
- haarcascade_mcs_lefteye.xml
- haarcascade_mcs_righteye.xml
- haarcascade_lefteye_2splits.xml
- haarcascade_righteye_2splits.xml
- haarcascade_mcs_eyepair_big.xml
- haarcascade_mcs_eyepair_small.xml
- 耳
- haarcascade_mcs_leftear.xml
- haarcascade_mcs_rightear.xml
- 口
- haarcascade_mcs_mouth.xml
- 鼻
- haarcascade_mcs_nose.xml
- 胴体
- haarcascade_fullbody.xml
- haarcascade_mcs_upperbody.xml
- haarcascade_lowerbody.xml
- haarcascade_upperbody.xml
結構いろいろありますが、Core Image の CIDetector では検出できない、耳・鼻・胴体 といったオブジェクトを検出するためのカスケードファイルもあらかじめ入っていることがわかります。
ちなみに haarcascade_eye_tree_eyeglasses.xml は、 メガネ着用時の目 を検出するものです。
###カスケードファイルを自作する
OpenCVにあらかじめ入っているものだけでも、Core Image よりも多くの対象を検出できることがわかりましたが、 人間以外のもの 、たとえば車やバイク、犬やネコを検出するためのカスケードファイルは入っていません。
その場合には、OpenCVに入っている、 haartraining というツールを使用して、カスケードファイルを自作する必要があります。
手順は以下の通り。
- 学習したいオブジェクトの例からなるデータセット(対象物が入っている画像)を集める
- createsamples ユーティリティを使用して、陽性サンプル(対象物が入っているサンプル)のベクトル出力ファイルを構築する
- 同様に、陰性サンプルのベクトル出力ファイルを構築する
- haartraining で学習を実行する
・・・とこう書くとわりとシンプルですが、手順 1 の データセット収集のハードルが半端なく高い です。
ある程度の精度を求めるなら、 1,000〜10,000枚 もの画像を集める必要があり、さらに、それらすべてについて いくつの対象物がどこにあるか(オブジェクト数, 左上隅の x座標, y座標, 幅, 高さ) を指定する必要があります。
現実的には、そういった画像を自動収集するツール、対象物の位置特定を補助するようなツールを自作する、といった努力が必要になると思います。
###Webに落ちているカスケードファイルを探す
前述したハードルにより、カスケードファイルを自作することはあきらめ、偉大な先人達が公開してくれているものを探すことにします。
まず、カスケードファイルのデータベースみたいなものがあるのではないか、と探してみましたが、どうやらないようでした(あったらぜひ教えていただけると幸いです)。
というわけで 人間以外の剛体を検出するためのカスケードファイル を、個別にキーワードをちまちま入れて探してみました。以下、見つけたものを列挙していきます。
##車
Vehicle Detection, Tracking and Counting on Behance
- 記事内に、カスケードファイルを含むソース一式が含まれています。
###Computer Vision: OpenCV support for DARPA Autonomous Vehicle
- "The trained Haar cascades can be found here." という記述のところに貼ってあるリンクからカスケードファイルをDLできます
##犬・ネコ
Visual Geometry Group: Oxford-IIIT Pet Dataset
- "Oxford-IIIT-Pet dataset" というペットの特徴量学習用データ を使用
- 学習用データはダウンロードできたものの、カスケードファイルは公開してないっぽい
- 同ページから "Cats and Dogs" という詳細が書かれた論文をダウンロードできます
###Cat Head Detection (PDF)
- 論文のみ
###TRACKING ANIMALS IN WILDLIFE VIDEOS USING FACE DETECTION
- 論文のみ
##標識
Computer Vision: OpenCV support for DARPA Autonomous Vehicle
- 一時停止の標識, 停止信号
- "The trained Haar cascades can be found here." という記述のところに貼ってあるリンクからカスケードファイルをDLできます
- stop signs, stop lights, and pedestrians とあるのですが、実際にどういう画像を学習させたかが不明
##ロゴ
###Haar cascade logo detection
- コカコーラのロゴを検出
- カスケードファイルは公開されてない。100枚の画像で学習させたとのこと。
##人間の部位
OpenCVにデフォルトで入っているhaarでは検出できない人間の部位 を検出するカスケードファイル。
###肩
- Need Haar Casscades for Nose, Eyes & Lips(Mouth)
- "Try this one: mozart.dis.ulpgc.es/pub/Software/HaarClassifiers/… It's a set of haar cascades for face features." とあるコメントから、DLできるzipに、肩と頭 (Head and shoulders) を検出するカスケードファイルが入っている
###Oppai
- Oppai-Detect 2 @ CodereposCon#1
- 記事内に "cascade_oppai.xml" というカスケードファイルへのリンクあり
- ただしリンクをから飛べなかったので、今は公開されていないのかもしれません
###笑顔
- SMILEsmileD
- これは iOS7 から Core Image でできる
- 学習用データセットもリポジトリに入っている
###手/ジェスチャー
- EHCI 6 degrees of freedom hand tracker
- ソース一式がDLできて、aGest.xml というカスケードファイルが入っている
##ペン
###All about openCV: Creating a haar cascade classifier aka haar training
- Pen detector という ペンを検出 するカスケードファイルをダウンロードできます
##その他
見つけ次第随時追加していきます。ご存知の方はぜひコメント欄などでご連絡ください!
##実装サンプル:画像から車を検出する
まず、 OpenCV for iOS の導入方法 等、基本的なところは下記をご覧ください。
上記記事で使っている OpenCVHelper.mm に、次のようなメソッドを追加します。
+ (UIImage *)detect:(UIImage *)srcImage cascade:(NSString *)cascadeFilename {
cv::Mat srcMat = [OpenCVHelper cvMatFromUIImage:srcImage];
// グレースケール画像に変換
cv::Mat grayMat;
cv::cvtColor(srcMat, grayMat, CV_BGR2GRAY);
// 分類器の読み込み
NSString *path = [[NSBundle mainBundle] pathForResource:cascadeFilename
ofType:nil];
std::string cascade_path = (char *)[path UTF8String];
cv::CascadeClassifier cascade;
if (!cascade.load(cascade_path)) {
NSLog(@"Couldn't load haar cascade file.");
return nil;
}
// 探索
std::vector<cv::Rect> objects;
cascade.detectMultiScale(grayMat, objects, // 画像,出力矩形
1.1, 1, // 縮小スケール,最低矩形数
CV_HAAR_SCALE_IMAGE, // (フラグ)
cv::Size(40, 40)); // 最小矩形
// 結果の描画
std::vector<cv::Rect>::const_iterator r = objects.begin();
for(; r != objects.end(); ++r) {
cv::Point center;
int radius;
center.x = cv::saturate_cast<int>((r->x + r->width*0.5));
center.y = cv::saturate_cast<int>((r->y + r->height*0.5));
radius = cv::saturate_cast<int>((r->width + r->height)*0.25);
cv::circle(srcMat, center, radius, cv::Scalar(80,80,255), 3, 8, 0 );
}
return [OpenCVHelper UIImageFromCVMat:srcMat];
}
前述した "Vehicle Detection" のページからカスケードファイル"haarcascade_car_1.xml" をダウンロードしてきて(リンクはよく探してみてください)、 プロジェクトに追加します。
そして、先ほど実装した detect:cascade:
メソッドを使用して、
self.imageView.image = [OpenCVHelper detect:self.imageView.image
cascade:@"haarcascade_car_1.xml"];
とやると、次のように車を検出できるようになります。
##サンプルダウンロード
基本的に上記の手順通りに実装すればOKです。でも自分でつくるの面倒なのですぐにビルドできるものが欲しい!という方向けに、サンプルをgumroadよりダウンロードできるようにしました。
gumroadなので、 有料 (102円)になります。サンプルはいらないけど記事が少しは役に立ったから寄付してやるか、というお気持ちもありがたく頂戴いたします。値段が中途半端なのは、gumroadの仕様のためです、スイマセン。繰り返しになりますが、 上記手順通りにやればOK(サンプルのダウンロードは不要) です。
###注意点
- iOS 7.0 でのみ動作確認しております。
- コードのみの販売です。サポート等はご容赦ください。
##参考書籍
Haar分類器の詳細や、OpenCVの各種学習ツールを使ったカスケードファイルの生成方法は、以下の書籍に詳しいです。
広範囲な内容が640ページにわたってわかりやすく解説されていて、訳文もものすごく読みやすいので、超オススメです。
また、拙著でも、 画像処理関係のレシピ を多く取り上げております。下記記事にて内容をご確認いただき、もしよろしければ!