LoginSignup
15
14

More than 5 years have passed since last update.

[iOS]顔検出をCoreImageとOpenCVでいまさらやってみる

Posted at

概要

CoreImageの機能を使うと、画像中の顔のある領域は簡単に調べることができます。
精度とか速度ってOpenCVの顔認識に比べたらどうなのかな?と少し思ったので自分で試してみました。
(既にやりつくされてるネタとは思いつつ…)

条件

OpenCVをカスタムする知識や技術が今のところないので、今回はお手軽な実装同士でどれだけ差が出るかの実験ということにしました。

CoreImageの設定

CIDetectorの設定
- (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 下:CIDetector)
syoumen.png

顔・目ともにあまり変わらず。
ただopencvの方は耳辺りに目が認識されてしまってますね。

例その2 集合写真

(上:OpenCV 下:CIDetector)
Simulator Screen Shot 2015.12.17 19.01.19.png

顔の精度はあまり変わらず。
さきほどに比べるとサイズ小さめなのですが、CIDetectorは目の位置まで綺麗に検出しています。

例その3 横顔

(上:OpenCV 下:CIDetector)
yokogao.png

どちらも横顔は認識せず。メガネも悪条件かもですね。
opencvはまた目の認識が荒ぶっています。

まとめると

顔検出はあまり精度に差はなさそうです。
OpenCVにおける目の位置検出は、顔の枠内にあるかどうかの判定が必要そうです。
cascadeファイルを色々変えてみるのもアリだったかも知れません。

Instrumentで見てみる

( ˘ω˘)軽く調べただけなので、話半分に…

OpenCVの場合

cv_result01.png
cv_result02.png

だいたい7秒ちょい。
スレッドが増えてるのがわかりますね。

CIDetectorの場合

ci_result01.png
ci_result02.png

だいたい4秒弱。
やはりというべきなのかも知れませんが、CoreImageの方が速いですね。

やってわかった注意点

OpenCVで画像を処理する際、@2xの画像をOpenCVに引き渡すと、結果として、画像を半分に縮小した状態で計算・出力が行われます。
恐らくサイズ情報が表示サイズになるためで、これをやるとそのため精度は著しく落ちてしまいます。

またCIImageに関しても、@2xの画像がセットされているUIImageViewから取得した場合、今度は検出される顔・目の座標が画面サイズの2倍になってしまうので半分に計算し直す必要があります。

おわりに

単純な実装だとやはりCoreImageは強力ですね。
OpenCVを使うならやはり顔以外のものに対して、ということになりそうです。少しずつ手を出してみたい…

写真は以下のサイトからお借りしています。

15
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
14