Розпізнавання осіб на iOS з допомогою Core Image

Core Image являє собою потужний API, вбудований в Cocoa Touch. Це важлива частина IOS SDK. Тим не менше її часто випускають з уваги. У цій статті ми будемо розглядати можливість виявлення особи і те, як використовувати дану технологію в своїх IOS додатках!



Що ми будемо робити в цьому туториале?
Розпізнавання осіб в iOS з'явилася давно, ще з 5-го релізу (приблизно у 2011 році), але цю особливість часто упускали з вигляду. API виявлення особи дозволяє розробникам не тільки розпізнавати обличчя, але і перевіряти їх на певні властивості, такі як, наявність усмішки, заплющує людина ока тощо

По-перше, ми будемо вивчати технологію виявлення особи з використанням фреймворку Core Image, створивши програму, яка розпізнає обличчя на фотографії і обводить його спеціальною рамкою. У другому прикладі, ми будемо розглядати більш детальний спосіб використання, шляхом створення програми, яка дозволить вам зробити знімок, виявити, чи присутня особа, та отримати координати особи користувача. Таким чином, ми збираємося дізнатися як можна більше про розпізнавання осіб в iOS, а також принцип використання потужного API, який так часто упускають з виду. Отже, поїхали!

Налаштування проекту
Завантажте стартовий проект за цим посиланням тут і відкрийте його в Xcode. Як бачите, дуже простий контролер з підключеним IBOutlet до ImageView.



Для того, щоб почати виявлення осіб використавши Core Image, вам необхідно імпортувати бібліотеки Core Image. Перейдіть до файлу ViewController.swift і вставте наступний код у верхній частині:

import CoreImage

Виявлення осіб, використовуючи Core Image
У стартовому проекті ми маємо ImageView підключений до коду в якості IBOutlet. Далі нам потрібно реалізувати код для розпізнавання осіб. Вставте наступний код у проект і розглянемо його більш детально:

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 faces in 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, витягаємо UIImage з UIImageView і перетворимо в CIImage. CIImage необхідний для роботи з Core Image;

  • Створюємо змінну accuracy і встановлюємо CIDetectorAccuracyHigh. Ви можете вибрати з CIDetectorAccuracyHigh (забезпечує високу обчислювальну точність) і CIDetectorAccuracyLow (використовує низьку обчислювальну точність). Ми вибираємо CIDetectorAccuracyHigh, оскільки нам необхідна висока точність;

  • Визначаємо змінну faceDetector і встановлюємо до класу CIDetector і передаємо змінну точності, яку ми створили раніше;

  • Далі отримуємо масив осіб, за допомогою виклику методу featuresInImage, детектор знаходить особи в даному зображенні;

  • Виконуємо цикл по масиву осіб і перетворимо кожне розпізнане особа CIFaceFeature;

  • Створюємо UIView під назвою faceBox і встановлюємо його frame до розмірів рамки повертається з faces.first. Це необхідно для того, щоб намалювати прямокутник, для виділення розпізнаного особи;

  • Встановлюємо ширину border в faceBox до 3;

  • Встановлюємо колір кордону в червоний;

  • Колір фону встановлюється прозорим, view не буде мати видимого фону;

  • І нарешті, ми додамо наш faceBox до personPic;

  • Мало того, що API може визначити особу, детектор так само може виявити лівий і правий очей. Ми не будемо виділяти очі на зображенні. Тут я просто хочу показати вам відповідні властивості CIFaceFeature.
Викличемо метод detect() у viewDidLoad. Так вставте код метод:

detect()

Запустимо програму. Ви побачите щось на зразок цього:



В консолі xCode ми бачимо координати виявленого особи:

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

Є кілька нюансів, які ми не розглядали в поточному прикладі:

  • Виявлення обличчя наноситься на початкове зображення, яке має більш високий дозвіл, ніж imageView. Ми встановили для personPic режим to aspect fit(масштабування зображення зі збереженням вихідних пропорцій). Щоб намалювати правильно прямокутник, ми повинні розрахувати фактичне положення і розмір особи у поданні зображення;

  • Крім того, Core Image і UIView (або UIKit) використовують дві різні системи координат (дивись малюнок нижче). Ми повинні забезпечити реалізацію перетворення координат Core Image координати 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)

// Додали конвертацію координат
let ciImageSize = personciImage.extent.size
var transform = CGAffineTransformMakeScale(1, -1)
transform = CGAffineTransformTranslate(transform, 0, -ciImageSize.height)

for face faces in 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)")
}
}
}

Зміни коду вище виділені коментарями.

  • По-перше, ми використовуємо афінне перетворення для конвертації координат Core Image координати UIKit;

  • По-друге, ми додали код, щоб обчислити фактичне положення і розмір рамки нашої виявленого особи.

    Запустіть програму ще раз. Ви повинні побачити рамку навколо особи. Вітаю, ми успішно виявили особа з допомогою Core Image.


Створення програми «камера з функцією розпізнавання осіб»
Давайте уявимо, що у нас є додаток камера, яка робить фотографії. Як тільки буде відзнято фотографія ми хочемо запустити функцію розпізнавання осіб, щоб визначити, чи є на фотографії особа чи ні. Якщо особа присутня, ми можемо класифікувати цю фотографію з деякими тегами або що то в цьому роді. Для цього нам потрібна інтеграція з класом 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 для пикера і викликаємо функцію 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)
}
}

Наша функція detect() дуже схожа на її попередню реалізацію. Але на цей раз, ми використовуємо її на захопленому зображенні. При виявленні особи, ми виводимо попередження «We detected a face!» В іншому випадку, ми відображаємо повідомлення «No Face!». Запустіть програму і протестуйте роботу.



CIFaceFeature має кілька властивостей і методів, які я вже згадував. Наприклад, якщо ви хочете виконати виявлення, якщо людина посміхається, ви можете викликати .hasSmile, яке повертає boolean. Для експерименту ви можете викликати .hasLeftEyePosition, щоб перевірити, чи ліве око (будемо сподіватися, що це так) або .hasRightEyePosition для правого ока, відповідно.

Ми також можемо викликати hasMouthPosition, щоб перевірити чи є рот. Якщо рот присутня, ми можемо отримати доступ до координат з властивістю mouthPosition, як показано нижче:

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

Як ви бачите, виявляти риси обличчя дуже просто за допомогою Core Image. Крім виявлення рота, посмішки, або положення очі, ми можемо перевірити, відкритий очей або закритий шляхом виклику leftEyeClosed для лівого ока і rightEyeClosed для правого відповідно.

І в ув'язненні
У цій статті ми дослідили функції виявлення осіб з допомогою API, основного зображення Core Image API і як їх використовувати в додатку з камерою. Ми встановили скористалися основний UIImagePicker, щоб відзняти фотографію і виявити особа, присутня на зображенні.

Як ви бачите, виявлення особи з використанням основного зображення Core Image є потужним API поряд з багатьма додатками! Я сподіваюся, що ця стаття буде ви знайшли це підручник корисним та інформативним керівництвом до цього маловідомого API для iOS!

» Ви можете завантажити остаточний фінальний проект тут.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.