![](https://habrastorage.org/files/b41/1e9/1d3/b411e91d3c4e4089b2db63bd0fdb4d1c.jpg)
このチュートリアルでは何をしますか?
iOSの顔認識は、5回目のリリース(2011年頃)からかなり前に登場しましたが、この機能はしばしば見落とされていました。 顔検出APIを使用すると、開発者は顔を認識するだけでなく、笑顔の存在、人が目をまばたきするかどうかなど、特定のプロパティを確認することもできます。
まず、写真内の顔を認識し、それを特別なフレームで囲むアプリケーションを作成することにより、Core Imageフレームワークを使用した顔検出の技術を研究します。 2番目の例では、ユーザーが写真を撮り、顔が存在するかどうかを検出し、ユーザーの顔の座標を取得できるアプリケーションを作成することにより、より詳細な使用方法を検討します。 したがって、iOSでの顔認識と、見過ごされがちな強力なAPIを使用する原則について、できる限り学習します。 さあ、行こう!
プロジェクトのセットアップ
こちらのリンクからスタータープロジェクトをダウンロードし、Xcodeで開きます。 ご覧のとおり、IBOutletをImageViewに接続した非常にシンプルなコントローラー。
![](https://habrastorage.org/files/137/b37/f74/137b37f743334d428e96d3a99f6f423c.jpg)
Core Imageを使用して顔検出を開始するには、Core Imageライブラリをインポートする必要があります。 ViewController.swiftファイルを参照し、上部に次のコードを貼り付けます。
import CoreImage
コア画像を使用した顔検出
スタータープロジェクトでは、IBOutletとしてコードに接続されたImageViewがあります。 次に、顔認識のためのコードを実装する必要があります。 次のコードをプロジェクトに貼り付けて、より詳細に検討します。
func detect() { guard let personciImage = CIImage(image: personPic.image!) else { return } let accuracy = [CIDetectorAccuracy: CIDetectorAccuracyHigh] let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: accuracy) let faces = faceDetector.featuresInImage(personciImage) for face in faces as! [CIFaceFeature] { print("Found bounds are \(face.bounds)") let faceBox = UIView(frame: face.bounds) faceBox.layer.borderWidth = 3 faceBox.layer.borderColor = UIColor.redColor().CGColor faceBox.backgroundColor = UIColor.clearColor() personPic.addSubview(faceBox) if face.hasLeftEyePosition { print("Left eye bounds are \(face.leftEyePosition)") } if face.hasRightEyePosition { print("Right eye bounds are \(face.rightEyePosition)") } } }
ここで何が起こっているのか:
- personciImage変数を作成し、UIImageViewからUIImageを抽出し、CIImageに変換します。 CIImageはCore Imageを使用するために必要です。
- 精度変数を作成し、CIDetectorAccuracyHighを設定します。 CIDetectorAccuracyHigh(高い計算精度を提供)およびCIDetectorAccuracyLow(低い計算精度を使用)から選択できます。 高精度が必要なため、CIDetectorAccuracyHighを選択します。
- 変数faceDetectorを定義し、CIDetectorクラスに設定して、前に作成した精度変数を渡します。
- 次に、featuresInImageメソッドを呼び出すことで、顔の配列を取得します。検出器はこの画像で顔を見つけます。
- 顔の配列をループし、認識された各顔をCIFaceFeatureに変換します。
- faceBoxというUIViewを作成し、そのフレームをfaces.firstから返されたフレームのサイズに設定します。 これは、長方形を描き、認識された顔を強調するために必要です。
- faceBoxの境界線の幅を3に設定します。
- 境界線の色を赤に設定します。
- 背景色は透明に設定され、ビューには背景が表示されません。
- 最後に、faceBoxをpersonPicに追加します。
- APIはあなたの顔を検出できるだけでなく、左目と右目も検出できます。 画像の目をハイライトしません。 ここでは、CIFaceFeatureの関連するプロパティを示します。
viewDidLoadでdetect()メソッドを呼び出します。 そのため、次のコード行をメソッドに貼り付けます。
detect()
アプリケーションを起動します。 次のようなものが表示されます。
![](https://habrastorage.org/files/f53/d80/9b2/f53d809b2e654298a5736b868c7c412a.png)
xCodeコンソールには、検出された顔の座標が表示されます。
Found bounds are (177.0, 415.0, 380.0, 380.0)
現在の例では考慮しなかったいくつかのニュアンスがあります。
- 顔検出は、imageViewよりも高い解像度を持つ元の画像に適用されます。 personPicモードをアスペクトに合わせて設定します(元のアスペクト比を維持しながら画像をスケーリングします)。 長方形を正しく描画するには、画像表現で顔の実際の位置とサイズを計算する必要があります。
- さらに、Core ImageとUIView(またはUIKit)は2つの異なる座標系を使用します(下の画像を参照)。 Core Image座標からUIView座標への変換の実装を提供する必要があります。
![](https://habrastorage.org/files/cc0/f67/202/cc0f6720221c490aa7e499adc727343e.jpg)
次に、detect()メソッドを次のコードに置き換えます。
func detect() { guard let personciImage = CIImage(image: personPic.image!) else { return } let accuracy = [CIDetectorAccuracy: CIDetectorAccuracyHigh] let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: accuracy) let faces = faceDetector.featuresInImage(personciImage) // let ciImageSize = personciImage.extent.size var transform = CGAffineTransformMakeScale(1, -1) transform = CGAffineTransformTranslate(transform, 0, -ciImageSize.height) for face in faces as! [CIFaceFeature] { print("Found bounds are \(face.bounds)") // faceBox var faceViewBounds = CGRectApplyAffineTransform(face.bounds, transform) let viewSize = personPic.bounds.size let scale = min(viewSize.width / ciImageSize.width, viewSize.height / ciImageSize.height) let offsetX = (viewSize.width - ciImageSize.width * scale) / 2 let offsetY = (viewSize.height - ciImageSize.height * scale) / 2 faceViewBounds = CGRectApplyAffineTransform(faceViewBounds, CGAffineTransformMakeScale(scale, scale)) faceViewBounds.origin.x += offsetX faceViewBounds.origin.y += offsetY let faceBox = UIView(frame: faceViewBounds) faceBox.layer.borderWidth = 3 faceBox.layer.borderColor = UIColor.redColor().CGColor faceBox.backgroundColor = UIColor.clearColor() personPic.addSubview(faceBox) if face.hasLeftEyePosition { print("Left eye bounds are \(face.leftEyePosition)") } if face.hasRightEyePosition { print("Right eye bounds are \(face.rightEyePosition)") } } }
上記のコード変更はコメントで強調表示されます。
- まず、アフィン変換を使用して、コアイメージの座標をUIKit座標に変換します。
- 次に、検出された顔のフレームの実際の位置とサイズを計算するコードを追加しました。
アプリケーションを再度起動します。 顔の周りにフレームが表示されます。 おめでとうございます、Core Imageを使用して顔が正常に検出されました。
![](https://habrastorage.org/files/6d9/65c/406/6d965c406774477d9581b65946739fb1.jpg)
顔認識を使用したカメラアプリケーションの作成
写真を撮るカメラアプリケーションがあると想像してみましょう。 写真がキャプチャされるとすぐに、顔認識機能を開始して、写真に顔があるかどうかを判断します。 人がいる場合、この写真をいくつかのタグなどで分類できます。 これを行うには、UIImagePickerクラスと統合し、写真の撮影後に顔認識コードを実行する必要があります。
スタータープロジェクトでは、CameraViewControllerクラスを既に作成しました。 コードを更新してカメラ機能を実装します。
class CameraViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { @IBOutlet var imageView: UIImageView! let imagePicker = UIImagePickerController() override func viewDidLoad() { super.viewDidLoad() imagePicker.delegate = self } @IBAction func takePhoto(sender: AnyObject) { if !UIImagePickerController.isSourceTypeAvailable(.Camera) { return } imagePicker.allowsEditing = false imagePicker.sourceType = .Camera presentViewController(imagePicker, animated: true, completion: nil) } func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) { if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage { imageView.contentMode = .ScaleAspectFit imageView.image = pickedImage } dismissViewControllerAnimated(true, completion: nil) self.detect() } func imagePickerControllerDidCancel(picker: UIImagePickerController) { dismissViewControllerAnimated(true, completion: nil) } }
この関数の最初の数行は、UIImagePickerデリゲートを設定します。 didFinishPickingMediaWithInfoメソッド(これはUIImagePickerデリゲートメソッドです)で、imageViewのメソッドで受け取った画像を設定します。 次に、ピッカーのdismissを呼び出して、検出関数を呼び出します。
検出機能はまだ実装されていません。 次のコードを貼り付けて、よく見てください。
func detect() { let imageOptions = NSDictionary(object: NSNumber(int: 5) as NSNumber, forKey: CIDetectorImageOrientation as NSString) let personciImage = CIImage(CGImage: imageView.image!.CGImage!) let accuracy = [CIDetectorAccuracy: CIDetectorAccuracyHigh] let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: accuracy) let faces = faceDetector.featuresInImage(personciImage, options: imageOptions as? [String : AnyObject]) if let face = faces.first as? CIFaceFeature { print("found bounds are \(face.bounds)") let alert = UIAlertController(title: "Say Cheese!", message: "We detected a face!", preferredStyle: UIAlertControllerStyle.Alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil)) self.presentViewController(alert, animated: true, completion: nil) if face.hasSmile { print("face is smiling"); } if face.hasLeftEyePosition { print("Left eye bounds are \(face.leftEyePosition)") } if face.hasRightEyePosition { print("Right eye bounds are \(face.rightEyePosition)") } } else { let alert = UIAlertController(title: "No Face!", message: "No face was detected", preferredStyle: UIAlertControllerStyle.Alert) alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil)) self.presentViewController(alert, animated: true, completion: nil) } }
detect()関数は、以前の実装と非常によく似ています。 ただし、今回は、キャプチャした画像で使用します。 顔が検出されると、「顔を検出しました!」という警告メッセージが表示されます。そうでない場合は、「顔がありません!」というメッセージが表示されます。 アプリケーションを起動し、作業をテストします。
![](https://habrastorage.org/files/2fe/b6e/430/2feb6e4301dc415f853a92d7a097a2f0.png)
CIFaceFeatureには、既に説明したいくつかのプロパティとメソッドがあります。 たとえば、発見を実行したい場合、人が笑顔になった場合、ブール値を返す.hasSmileを呼び出すことができます。 実験では、.hasLeftEyePositionを呼び出して、左目が存在するかどうかを確認します(そうすることを期待しましょう)。
hasMouthPositionを呼び出して、口が存在するかどうかを確認することもできます。 口が存在する場合、以下に示すように、mouthPositionプロパティを使用して座標にアクセスできます。
if (face.hasMouthPosition) { print("mouth detected") }
ご覧のとおり、顔の特徴の検出はCore Imageを使用すると非常に簡単です。 口、笑顔、目の位置を検出するだけでなく、左目に対してleftEyeClosedを、右目に対してrightEyeClosedを呼び出すことで、目が開いているか閉じているかを確認することもできます。
そして結論として
この記事では、APIを使用した顔検出機能、Core Image APIのコアイメージ、およびカメラアプリケーションでそれらを使用する方法について説明しました。 メインのUIImagePickerを使用して、写真を撮影し、画像に存在する顔を検出します。
ご覧のとおり、コアイメージCore Imageを使用した顔検出は、多くのアプリケーションとともに強力なAPIです! このチュートリアルが、このあまり知られていないiOS用APIの有用で有益なガイドであることが、この記事でわかることを願っています!
»最終的な最終プロジェクトはこちらからダウンロードできます。