koogawa blog

iOS、Android、foursquareに関する話題

【Tips】iOSの顔検出機能を使ってみる

2016.4.29 追記:Swift版の記事を書きました

blog.koogawa.com


iOS 5から追加された CIDetector を使って、顔検出機能を使う方法をメモしておきます。

実装方法

まずは「CoreImage.framework」を追加します。

f:id:koogawa:20131122152458p:plain

インスタンスを生成します。

NSDictionary *options = [NSDictionary dictionaryWithObject:CIDetectorAccuracyHigh
                                                    forKey:CIDetectorAccuracy];
CIDetector *detector = [CIDetector detectorOfType:CIDetectorTypeFace
                                          context:nil
                                          options:options];

detectorOfType には検出タイプを指定します。今回は顔検出なので、CIDetectorTypeFace を指定します。*1

options には検出精度 CIDetectorAccuracy 等を指定できます。

  • CIDetectorAccuracyLow - 精度は低いが、パフォーマンスは良い
  • CIDetectorAccuracyHigh - 精度は高いが、パフォーマンスは悪い

次に、顔検出を実行します。

CIImage *ciImage = [[CIImage alloc] initWithCGImage:originalImage.CGImage];
NSDictionary *imageOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:1]
    forKey:CIDetectorImageOrientation];

NSArray *array = [detector featuresInImage:ciImage options:imageOptions];

featuresInImage には、顔検出したい画像を CIImage クラスで指定します。

options には画像の向きなどを指定します。カメラの画像を利用する場合には、デバイスの方向を正しく指定しないと顔検出ができないので注意してください。この辺りはAppleのサンプルコードがとても参考になります。

UIDeviceOrientation curDeviceOrientation = [[UIDevice currentDevice] orientation];
switch (curDeviceOrientation) {
    case UIDeviceOrientationPortraitUpsideDown:  // Device oriented vertically, home button on the top
        exifOrientation = PHOTOS_EXIF_0ROW_LEFT_0COL_BOTTOM;
        break;
    case UIDeviceOrientationLandscapeLeft:       // Device oriented horizontally, home button on the right
        exifOrientation = PHOTOS_EXIF_0ROW_TOP_0COL_LEFT;
        break;
    case UIDeviceOrientationLandscapeRight:      // Device oriented horizontally, home button on the left
        exifOrientation = PHOTOS_EXIF_0ROW_BOTTOM_0COL_RIGHT;
        break;
    case UIDeviceOrientationPortrait:            // Device oriented vertically, home button on the bottom
    default:
        exifOrientation = PHOTOS_EXIF_0ROW_RIGHT_0COL_TOP;
        break;
}
imageOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:exifOrientation] 
    forKey:CIDetectorImageOrientation];
NSArray *features = [faceDetector featuresInImage:ciImage
    options:imageOptions];

正常に顔が検出されると、検出結果が CIFaceFeature オブジェクトで返ってきます。このオブジェクトには、検出された顔の範囲や、目と口の位置などが含まれます。

  • bounds - 顔の範囲
  • hasLeftEyePosition - 左目の位置を検出できたか
  • hasMouthPosition - 口の位置を検出できたか
  • hasRightEyePosition - 右目の位置を検出できたか
  • leftEyePosition - 左目の位置
  • mouthPosition - 口の位置
  • rightEyePosition - 右目の位置

ここで注意したいのは、CoreImage は、左下の座標が (0,0) となる点です。よって、検出元画像の上に部品を載せたい場合は、座標をUIKitの座標系に変換する必要があります。

CGAffineTransform transform = CGAffineTransformMakeScale(1, -1);
transform = CGAffineTransformTranslate(transform, 0, -self.imageView.bounds.size.height);
// UIKit座標系に変換
const CGRect faceRect = CGRectApplyAffineTransform(faceFeature.bounds, transform);

これで顔検出ができました。

顔検出というと難しそうなイメージが有りますが、座標系のところ以外は、意外と簡単に使用できますね。

サンプル

https://github.com/koogawa/iSensor/blob/master/iSensor/FaceDetectionViewController.m

f:id:koogawa:20131130175727p:plain

補足

参考にさせて頂いたリンク

*1:今のところ CIDetectorTypeFace しか設定できないようです