概要
CoreImageの機能を使うと、画像中の顔のある領域は簡単に調べることができます。
精度とか速度ってOpenCVの顔認識に比べたらどうなのかな?と少し思ったので自分で試してみました。
(既にやりつくされてるネタとは思いつつ…)
条件
OpenCVをカスタムする知識や技術が今のところないので、今回はお手軽な実装同士でどれだけ差が出るかの実験ということにしました。
CoreImageの設定
- (void) useCIDetector:(UIImage *)image {
CIImage *ciImage = [CIImage imageWithCGImage:image.CGImage];
CIDetector *ciDetector = [CIDetector detectorOfType:CIDetectorTypeFace
context:nil
options:@{
CIDetectorAccuracy : CIDetectorAccuracyHigh,
CIDetectorSmile:@YES
}];
NSArray *features = [ciDetector featuresInImage:ciImage];
UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
// UIGraphicsBeginImageContext(self.imageView.image.size);
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
for (CIFaceFeature *feature in features) {
// 顔に枠線
CGContextRef drawContext = UIGraphicsGetCurrentContext();
CGRect faceRect = feature.bounds;
faceRect.origin.y = image.size.height - (faceRect.origin.y + faceRect.size.height);
CGContextSetLineWidth(drawContext, 2.f);
// 顔は青の枠線
CGContextSetStrokeColorWithColor(drawContext, [UIColor blueColor].CGColor);
CGContextStrokeRect(drawContext,faceRect);
// 目は緑の枠線
CGContextSetStrokeColorWithColor(drawContext, [UIColor greenColor].CGColor);
if (feature.hasLeftEyePosition) {
CGPoint leftEyePoint = feature.leftEyePosition;
leftEyePoint.y = image.size.height - leftEyePoint.y;
CGRect leftEyeRect = CGRectMake(leftEyePoint.x - 20, leftEyePoint.y - 20,
40, 40);
CGContextStrokeRect(drawContext,leftEyeRect);
}
if (feature.hasRightEyePosition) {
CGPoint rightEyePoint = feature.rightEyePosition;
rightEyePoint.y = image.size.height - rightEyePoint.y;
CGRect rightEyeRect = CGRectMake(rightEyePoint.x - 20, rightEyePoint.y - 20,
40, 40);
CGContextStrokeRect(drawContext,rightEyeRect);
}
}
UIImage *drawedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
self.imageView.image = drawedImage;
}
OpenCVの設定
こちらを参考にさせて頂きました。(コードは省略します)
内容はcv::circleをcv::rectangleに変更した程度です。以下の2つのcascadeファイルを使って1つの画像に対し処理を行いました。(線色はCIDetectorと同じく 顔:青、目:緑)
- 顔:haarcascade_frontalface_alt.xml
- 目:haarcascade_eye.xml
例その1 正面
顔・目ともにあまり変わらず。
ただopencvの方は耳辺りに目が認識されてしまってますね。
例その2 集合写真
顔の精度はあまり変わらず。
さきほどに比べるとサイズ小さめなのですが、CIDetectorは目の位置まで綺麗に検出しています。
例その3 横顔
どちらも横顔は認識せず。メガネも悪条件かもですね。
opencvはまた目の認識が荒ぶっています。
まとめると
顔検出はあまり精度に差はなさそうです。
OpenCVにおける目の位置検出は、顔の枠内にあるかどうかの判定が必要そうです。
cascadeファイルを色々変えてみるのもアリだったかも知れません。
Instrumentで見てみる
( ˘ω˘)軽く調べただけなので、話半分に…
OpenCVの場合
だいたい7秒ちょい。
スレッドが増えてるのがわかりますね。
CIDetectorの場合
だいたい4秒弱。
やはりというべきなのかも知れませんが、CoreImageの方が速いですね。
やってわかった注意点
OpenCVで画像を処理する際、@2xの画像をOpenCVに引き渡すと、結果として、画像を半分に縮小した状態で計算・出力が行われます。
恐らくサイズ情報が表示サイズになるためで、これをやるとそのため精度は著しく落ちてしまいます。
またCIImageに関しても、@2xの画像がセットされているUIImageViewから取得した場合、今度は検出される顔・目の座標が画面サイズの2倍になってしまうので半分に計算し直す必要があります。
おわりに
単純な実装だとやはりCoreImageは強力ですね。
OpenCVを使うならやはり顔以外のものに対して、ということになりそうです。少しずつ手を出してみたい…
写真は以下のサイトからお借りしています。