iOS使用 Core Image 的 iOS 人臉識別

jwjro6u51 8年前發布 | 39K 次閱讀 人臉識別 iOS開發 移動開發

Face Detection in iOS Using Core Image

使用Core Image的iOS人臉識別

ore Image是Cocoa Touch中一個強大的API,是iOS SDK中的關鍵部分,不過它經常被忽視。在這篇教程中,會驗證Core Image的人臉識別特性并在你的iOS app中應用這項技術!

注意: 這是一篇中高級的iOS教程,假定你已經使用過UIImagePicker, Core Image等技術。

將要構建的應用

iOS的人臉識別從iOS 5(2011)就有了,不過一直沒怎么被關注過。人臉識別API允許開發者不僅可以檢測人臉,也可以檢測到面部的一些特殊屬性,比如說微笑或眨眼。

首先,為了了解Core Image的人臉識別技術我們會創建一個app來識別照片中的人臉并用一個方框來標記它。在第二個例子中,讓用戶拍攝一張照片,檢測其中的人臉并檢索人臉位置。這樣一來,就充分掌握了iOS中的人臉識別,并且學會如何利用這個強大卻總被忽略的API。

建立工程

下載開始工程在Xcode中打開。如你所見,里面只有一個關聯了IBOutlet和imageView的故事板。

使用Core Image識別人臉

在開始工程中,故事板中的imageView組件與代碼中的IBOutlet已關聯,接下來要實現人臉識別的代碼部分。在swift文件中插入如下代碼,之后進行講解:

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)")
    }
}

}</code></pre>

來探討下發生了什么:

  • 行 #3: 創建personciImage變量保存從故事板中的UIImageView提取圖像并將其轉換為CIImage,使用Core Image時需要用CIImage。
  • 行 #7: 創建accuracy變量并設為CIDetectorAccuracyHigh,可以在CIDetectorAccuracyHigh(較強的處理能力)與CIDetectorAccuracyLow(較弱的處理能力)中選擇,因為想讓準確度高一些在這里選擇CIDetectorAccuracyHigh。
  • 行 #8: 這里定義了一個屬于CIDetector類的faceDetector變量,并輸入之前創建的accuracy變量。
  • 行 #9: 調用faceDetector的featuresInImage方法,識別器會找到所給圖像中的人臉,最后返回一個人臉數組。
  • 行 #11: 循環faces數組里的所有face,并將識別到的人臉強轉為CIFaceFeature類型。
  • 行 #15: 創建名為faceBox的UIView,frame設為返回的faces.first的frame,繪制一個矩形框來標識識別到的人臉。
  • 行 #17: 設置faceBox的邊框寬度為3。
  • 行 #18: 設置邊框顏色為紅色。
  • 行 #19: 將背景色設為clear,意味著這個視圖沒有可見的背景。
  • 行 #20: 最后,把這個視圖添加到personPic imageView上。
  • 行 #22-28: API不僅可以幫助你識別人臉,也可識別臉上的左右眼,我們不在圖像中標識出眼睛,只是給你展示一下CIFaceFeature的相關屬性。

需要在viewDidLoad中調用detect方法,插入如下行:

detect()

編譯并運行app,結果應如下圖所示:

根據控制臺的輸出來看,貌似識別器識別到了人臉:

Found bounds are (177.0, 415.0, 380.0, 380.0)

當前的實現中沒有解決的問題:

  • 人臉識別是在原始圖像上進行的,由于原始圖像的分辨率比image view要高,因此需要設置image view的content mode為aspect fit(保持縱橫比的情況下縮放圖片)。為了合適的繪制矩形框,需要計算image view中人臉的實際位置與尺寸
  • 還要注意的是,Core Image與UIView使用兩種不同的坐標系統(看下表),因此要實現一個CoreImage坐標到UIView坐標的轉換。

現在使用下面的代碼替換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)

// For converting the Core Image Coordinates to UIView Coordinates
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)")

    // Apply the transform to convert the coordinates
    var faceViewBounds = CGRectApplyAffineTransform(face.bounds, transform)

    // Calculate the actual position and size of the rectangle in the image view
    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)")
    }
}

}</code></pre>

上述代碼中,首先使用仿射變換將Core Image坐標轉換為UIKit坐標,然后編寫了計算實際位置與矩形視圖尺寸的代碼。

再次運行app,應該會看到人的面部周圍會有一個框,干得漂亮!你已經成功使用Core Image識別出了人臉。

構建一個人臉識別的相機應用

想象一下你有一個用來照相的相機app,照完相后你想運行一下人臉識別來檢測一下是否存在人臉。若存在一些人臉,你也許想用一些標簽來對這些照片進行分類。我們不會構建一個保存照片后再處理的app,而是一個實時的相機app,因此需要整合一下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)
}

}</code></pre>

前面幾行設置UIImagePicker委托為當前視圖類,在didFinishPickingMediaWithInfo方法(UIImagePicker的委托方法)中設置imageView為在方法中所選擇的圖像,接著返回上一視圖調用detect函數。

還沒有實現detect函數,插入下面代碼并分析一下:

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)
    }
}</code></pre> 

這個detect()函數與之前實現的detect函數非常像,不過這次只用它來獲取圖像不做變換。當識別到人臉后顯示一個警告信息“檢測到了人臉!”,否則顯示“未檢測到”。運行app測試一下

我們已經使用到了一些CIFaceFeature的屬性與方法,比如,若想檢測人物是否在笑,可以調用.hasSmile,它會返回一個布爾值。可以分別使用.hasLeftEyePosition與.hasRightEyePosition檢測是否存在左右眼。

同樣,可以調用hasMouthPosition來檢測是否存在嘴,若存在則可以訪問到mouthPosition屬性,如下所示:

if (face.hasMouthPosition) {
     print("mouth detected")
}

如你所見,使用Core Image來檢測面部特征是非常簡單的。除了檢測嘴、笑容、眼睛外,也可以調用leftEyeClosed與rightEyeClosed檢測左右眼是否睜開。

總結

在這篇教程中嘗試了Core Image的人臉識別API與如何在一個相機app中應用它,構建了一個簡單的UIImagePicker來選取照片并檢測圖像中是否存在人物。

如你所見,Core Image的人臉識別是個強大的API!希望這篇教程能給你提供一些關于這個鮮為人知的iOS API有用的信息。

 

 

來自:https://github.com/yrq110/Some_IOS_Tutorials_With_Swift/blob/master/Face Detection in iOS Using Core Image.md

 

 本文由用戶 jwjro6u51 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!