2018-09-04更新: 很久没有更新文章了,工作之余花时间看了之前写的这篇文章并运行了之前写的配套Demo,通过打印人脸特征CIFaceFeature的属性,发现识别的效果并不是很好,具体说明见文章最底部的更新标题,后续我将分别用OpenCV(跨平台计算机视觉库) 和 Vision (iOS 11新API)两种库实现人脸面部识别,敬请期待~~

OC版下载地址, swift版下载地址

```

CoreImage是Cocoa Touch中一个强大的API,也是iOS SDK中的关键部分,不过它经常被忽视。在本篇教程中,我会带大家一起验证CoreImage的人脸识别特性。在开始之前,我们先要简单了解下CoreImage framework 组成

CoreImage framework组成

Apple 已经帮我们把image的处理分类好,来看看它的结构:

主要分为三个部分:

1.定义部分:CoreImage 和CoreImageDefines。见名思义,代表了CoreImage 这个框架和它的定义。

2.操作部分:

滤镜(CIFliter):CIFilter 产生一个CIImage。典型的,接受一到多的图片作为输入,经过一些过滤操作,产生指定输出的图片。

检测(CIDetector):CIDetector 检测处理图片的特性,如使用来检测图片中人脸的眼睛、嘴巴、等等。

特征(CIFeature):CIFeature 代表由 detector处理后产生的特征。

3.图像部分:

画布(CIContext):画布类可被用与处理Quartz 2D 或者 OpenGL。可以用它来关联CoreImage类。如滤镜、颜色等渲染处理。

颜色(CIColor): 图片的关联与画布、图片像素颜色的处理。

向量(CIVector): 图片的坐标向量等几何方法处理。

图片(CIImage): 代表一个图像,可代表关联后输出的图像。

在了解上述基本知识后,我们开始通过创建一个工程来带大家一步步验证Core Image的人脸识别特性。

将要构建的应用

iOS的人脸识别从iOS 5(2011)就有了,不过一直没怎么被关注过。人脸识别API允许开发者不仅可以检测人脸,也可以检测到面部的一些特殊属性,比如说微笑或眨眼。

首先,为了了解Core Image的人脸识别技术我们会创建一个app来识别照片中的人脸并用一个方框来标记它。在第二个demo中,让用户拍摄一张照片,检测其中的人脸并检索人脸位置。这样一来,就充分掌握了iOS中的人脸识别,并且学会如何利用这个强大却总被忽略的API。

话不多说,开搞!

建立工程(我用的是Xcode8.0)

这里提供了初始工程,当然你也可以自己创建(主要是为了方便大家)点我下载 用Xcode打开下载后的工程,可以看到里面只有一个关联了IBOutlet和imageView的StoryBoard。

使用CoreImage识别人脸

在开始工程中,故事板中的imageView组件与代码中的IBOutlet已关联,接下来要编写实现人脸识别的代码部分。在ViewController.swift文件中写下如下代码:

import UIKit

import CoreImage // 引入CoreImage

class ViewController: UIViewController {

@IBOutlet weak var personPic: UIImageView!

override func viewDidLoad() {

super.viewDidLoad()

personPic.image = UIImage(named: "face-1")

// 调用detect

detect()

}

//MARK: - 识别面部

func detect() {

// 创建personciImage变量保存从故事板中的UIImageView提取图像并将其转换为CIImage,使用Core Image时需要用CIImage

guard let personciImage = CIImage(image: personPic.image!) else {

return

}

// 创建accuracy变量并设为CIDetectorAccuracyHigh,可以在CIDetectorAccuracyHigh(较强的处理能力)与CIDetectorAccuracyLow(较弱的处理能力)中选择,因为想让准确度高一些在这里选择CIDetectorAccuracyHigh

let accuracy = [CIDetectorAccuracy: CIDetectorAccuracyHigh]

// 这里定义了一个属于CIDetector类的faceDetector变量,并输入之前创建的accuracy变量

let faceDetector = CIDetector(ofType: CIDetectorTypeFace, context: nil, options: accuracy)

// 调用faceDetector的featuresInImage方法,识别器会找到所给图像中的人脸,最后返回一个人脸数组

let faces = faceDetector?.features(in: personciImage)

// 循环faces数组里的所有face,并将识别到的人脸强转为CIFaceFeature类型

for face in faces as! [CIFaceFeature] {

print("Found bounds are \(face.bounds)")

// 创建名为faceBox的UIView,frame设为返回的faces.first的frame,绘制一个矩形框来标识识别到的人脸

let faceBox = UIView(frame: face.bounds)

// 设置faceBox的边框宽度为3

faceBox.layer.borderWidth = 3

// 设置边框颜色为红色

faceBox.layer.borderColor = UIColor.red.cgColor

// 将背景色设为clear,意味着这个视图没有可见的背景

faceBox.backgroundColor = UIColor.clear

// 最后,把这个视图添加到personPic imageView上

personPic.addSubview(faceBox)

// API不仅可以帮助你识别人脸,也可识别脸上的左右眼,我们不在图像中标识出眼睛,只是给你展示一下CIFaceFeature的相关属性

if face.hasLeftEyePosition {

print("Left eye bounds are \(face.leftEyePosition)")

}

if face.hasRightEyePosition {

print("Right eye bounds are \(face.rightEyePosition)")

}

}

}

}

编译并运行app,结果应如下图所示:

2.png

根据控制台的输出来看,貌似识别器识别到了人脸:

Found bounds are (314.0, 243.0, 196.0, 196.0)

当前的实现中没有解决的问题:

人脸识别是在原始图像上进行的,由于原始图像的分辨率比image view要高,因此需要设置image view的content mode为aspect fit(保持纵横比的情况下缩放图片)。为了合适的绘制矩形框,需要计算image view中人脸的实际位置与尺寸

还要注意的是,CoreImage与UIView使用两种不同的坐标系统(看下图),因此要实现一个CoreImage坐标到UIView坐标的转换。

UIView坐标系:

CoreImage坐标系:

现在使用下面的代码替换detect()方法:

func detect1() {

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?.features(in: personciImage)

// 转换坐标系

let ciImageSize = personciImage.extent.size

var transform = CGAffineTransform(scaleX: 1, y: -1)

transform = transform.translatedBy(x: 0, y: -ciImageSize.height)

for face in faces as! [CIFaceFeature] {

print("Found bounds are \(face.bounds)")

// 应用变换转换坐标

var faceViewBounds = face.bounds.applying(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 = faceViewBounds.applying(CGAffineTransform(scaleX: scale, y: scale))

faceViewBounds.origin.x += offsetX

faceViewBounds.origin.y += offsetY

let faceBox = UIView(frame: faceViewBounds)

faceBox.layer.borderWidth = 3

faceBox.layer.borderColor = UIColor.red.cgColor

faceBox.backgroundColor = UIColor.clear

personPic.addSubview(faceBox)

if face.hasLeftEyePosition {

print("Left eye bounds are \(face.leftEyePosition)")

}

if face.hasRightEyePosition {

print("Right eye bounds are \(face.rightEyePosition)")

}

}

}

上述代码中,首先使用仿射变换(AffineTransform)将Core Image坐标转换为UIKit坐标,然后编写了计算实际位置与矩形视图尺寸的代码。

再次运行app,应该会看到人的面部周围会有一个框。OK,你已经成功使用Core Image识别出了人脸。

但是有的童鞋在使用了上面的代码运行后可能会出现方框不存在(即没有识别人脸)这种情况,这是由于忘记关闭Auto Layout以及Size Classes了。 选中storyBoard中的ViewController,选中view下的imageView。然后在右边的面板中的第一个选项卡中找到use Auto Layout ,将前面的✔️去掉就可以了

经过上面的设置后我们再次运行App,就会看到图三出现的效果了。

构建一个人脸识别的相机应用

想象一下你有一个用来照相的相机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

present(imagePicker, animated: true, completion: nil)

}

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {

if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {

imageView.contentMode = .scaleAspectFit

imageView.image = pickedImage

}

dismiss(animated: true, completion: nil)

self.detect()

}

func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {

dismiss(animated: true, completion: nil)

}

}

前面几行设置UIImagePicker委托为当前视图类,在didFinishPickingMediaWithInfo方法(UIImagePicker的委托方法)中设置imageView为在方法中所选择的图像,接着返回上一视图调用detect函数。

还没有实现detect函数,插入下面代码并分析一下

func detect() {

let imageOptions = NSDictionary(object: NSNumber(value: 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?.features(in: personciImage, options: imageOptions as? [String : AnyObject])

if let face = faces?.first as? CIFaceFeature {

print("found bounds are \(face.bounds)")

let alert = UIAlertController(title: "提示", message: "检测到了人脸", preferredStyle: UIAlertControllerStyle.alert)

alert.addAction(UIAlertAction(title: "确定", style: UIAlertActionStyle.default, handler: nil))

self.present(alert, animated: true, completion: nil)

if face.hasSmile {

print("face is smiling");

}

if face.hasLeftEyePosition {

print("左眼的位置: \(face.leftEyePosition)")

}

if face.hasRightEyePosition {

print("右眼的位置: \(face.rightEyePosition)")

}

} else {

let alert = UIAlertController(title: "提示", message: "未检测到人脸", preferredStyle: UIAlertControllerStyle.alert)

alert.addAction(UIAlertAction(title: "确定", style: UIAlertActionStyle.default, handler: nil))

self.present(alert, animated: true, completion: nil)

}

}

这个detect()函数与之前实现的detect函数非常像,不过这次只用它来获取图像不做变换。当识别到人脸后显示一个警告信息“检测到了人脸!”,否则显示“未检测到人脸”。运行app测试一下:

我们已经使用到了一些CIFaceFeature的属性与方法,比如,若想检测人物是否微笑,可以调用.hasSmile,它会返回一个布尔值。可以分别使用.hasLeftEyePosition与.hasRightEyePosition检测是否存在左右眼。

同样,可以调用hasMouthPosition来检测是否存在嘴,若存在则可以使用mouthPosition属性,如下所示:

if (face.hasMouthPosition) {

print("mouth detected")

}

如你所见,使用Core Image来检测面部特征是非常简单的。除了检测嘴、笑容、眼睛外,也可以调用leftEyeClosed与rightEyeClosed检测左右眼是否睁开,这里就不在贴出代码了。

总结

在这篇教程中尝试了CoreImage的人脸识别API与如何在一个相机app中应用它,构建了一个简单的UIImagePicker来选取照片并检测图像中是否存在人物。

如你所见,Core Image的人脸识别是个强大的API!希望这篇教程能给你提供一些关于这个鲜为人知的iOS API有用的信息。

点击swift版地址,OC版地址下载最终工程, 如果觉得对您有帮助的话,请帮我点个星星哦,您的星星是对我最大的支持。(__) 嘻嘻……**

更新:

很久没有更新文章了,工作之余花时间回顾了之前写的这篇文章并运行了之前写的配套Demo,通过打印人脸特征CIFaceFeature的属性(如下),发现识别的效果并不是很好,如下图:

人脸特征CIFaceFeature的属性

/** CIDetector发现的脸部特征。

所有的位置都是相对于原始图像. */

NS_CLASS_AVAILABLE(10_7, 5_0)

@interface CIFaceFeature : CIFeature

{

CGRect bounds;

BOOL hasLeftEyePosition;

CGPoint leftEyePosition;

BOOL hasRightEyePosition;

CGPoint rightEyePosition;

BOOL hasMouthPosition;

CGPoint mouthPosition;

BOOL hasTrackingID;

int trackingID;

BOOL hasTrackingFrameCount;

int trackingFrameCount;

BOOL hasFaceAngle;

float faceAngle;

BOOL hasSmile;

BOOL leftEyeClosed;

BOOL rightEyeClosed;

}

/** coordinates of various cardinal points within a face.

脸部各个基点的坐标。

Note that the left eye is the eye on the left side of the face

from the observer's perspective. It is not the left eye from

the subject's perspective.

请注意,左眼是脸左侧的眼睛从观察者的角度来看。 这不是左眼主体的视角.

*/

@property (readonly, assign) CGRect bounds; // 指示图像坐标中的人脸位置和尺寸的矩形。

@property (readonly, assign) BOOL hasLeftEyePosition; // 指示检测器是否找到了人脸的左眼。

@property (readonly, assign) CGPoint leftEyePosition; // 左眼的坐标

@property (readonly, assign) BOOL hasRightEyePosition; // 指示检测器是否找到了人脸的右眼。

@property (readonly, assign) CGPoint rightEyePosition; // 右眼的坐标

@property (readonly, assign) BOOL hasMouthPosition; // 指示检测器是否找到了人脸的嘴部

@property (readonly, assign) CGPoint mouthPosition; // 嘴部的坐标

@property (readonly, assign) BOOL hasTrackingID; // 指示面部对象是否具有跟踪ID。

/**

* 关于trackingID:

* coreImage提供了在视频流中检测到的脸部的跟踪标识符,您可以使用该标识符来识别在一个视频帧中检测到的CIFaceFeature对象是在先前视频帧中检测到的同一个脸部。

* 只有在框架中存在人脸并且不与特定人脸相关联时,该标识符才会一直存在。如果脸部移出视频帧并在稍后返回到帧中,则分配另一个ID。 (核心图像检测面部,但不识别特定的面部。)

* 这个有点抽象

*/

@property (readonly, assign) int trackingID;

@property (readonly, assign) BOOL hasTrackingFrameCount; // 指示面部对象的布尔值具有跟踪帧计数。

@property (readonly, assign) int trackingFrameCount; // 跟踪帧计数

@property (readonly, assign) BOOL hasFaceAngle; // 指示是否有关于脸部旋转的信息可用。

@property (readonly, assign) float faceAngle; // 旋转是以度数逆时针测量的,其中零指示在眼睛之间画出的线相对于图像方向是水平的。

@property (readonly, assign) BOOL hasSmile; // 是否有笑脸

@property (readonly, assign) BOOL leftEyeClosed; // 左眼是否闭上

@property (readonly, assign) BOOL rightEyeClosed; // 右眼是否闭上

问题:那么如何让人脸识别的效果更好呢? 如何让面部识别点更加精确呢?有没有别的方法呢? 答案是肯定的。

现在市面上有很多成熟的面部识别产品:

Face++, 收费

Video++,收费

ArcFace 虹软人脸认知引擎, 收费

百度云人脸识别, 收费

阿里云识别, 收费

等等, 我们看到都是收费的。 当然这些sdk是可以试用的。如果你有折腾精神,想自己尝试人脸识别的实现,我们可以一起交流。 毕竟市面上的这些sdk也不是一开始就有的, 也是通过人们不断研究开发出来的。 而且自己折腾过程中,通过不断地遇坑爬坑,对知识的理解更加深透,自己的技术也会有增进,不是吗? 不好意思,有点扯远了。

Core Image只是简单的图像识别, 并不能对流中的人脸进行识别。 它只适合对图片的处理。比较有名的OpenCV(跨平台计算机视觉库)就可以用来进行面部识别,识别精度自然很高。还有就是iOS 11.0+ 推出的Vision框架(让我们轻松访问苹果的模型,用于面部检测、面部特征点、文字、矩形、条形码和物体)也可以进行面部识别。后面我将会用这两个框架讲解如何进行面部识别。敬请期待!!!

ios人脸照片_基于iOS用CoreImage实现人脸识别相关推荐

  1. charles乱码_基于iOS的Charles抓包实践

    奇技指南 在应用开发过程中,通过抓包调试服务端接口的场景时常出现.Charles和Wireshark是开发过程中最常用的两款软件.那么今天,让我们以iOS为例,聊一聊Charles抓包. 本文来自36 ...

  2. 小米手机nfc能连电脑吗_基于ios平台小米手环5 NFC版体验报告

    2020年6月11日,小米手环5如期问世.作为2代和3代小米手环的用户,对新款小米手环还是十分期待的.从安卓转到ios,全功能NFC的缺失着实给生活带来些许不便.随着ios逐步开放城市公交卡的功能,我 ...

  3. ios 图像翻转_在iOS 14中使用计算机视觉的图像差异

    ios 图像翻转 Human eyes are very receptive to visual representations. Similarly, computer vision enables ...

  4. opencv 训练人脸对比_【项目案例python与人脸识别】基于OpenCV开源计算机视觉库的人脸识别之python实现...

    " 本项目是一个基于OpenCV开源库使用python语言程序实现人脸检测的项目,该项目将从[项目基础知识](即人脸识别的基本原理).[项目实践](人脸识别所需要的具体步骤及其python程 ...

  5. facebook人脸照片_如何在手机上保留Facebook照片的本地副本

    facebook人脸照片 Today's Ask How-To Geek is a bit of a role reversal: most people want an easy way to ge ...

  6. java人脸识别快速搭建_基于Facecognition+Opencv快速搭建人脸识别及跟踪应用

    基于 作为一个图像处理的爱好者,怎能放过人脸识别这一环呢!调研开搞,发现了超实用的 Facecognition人脸识别原理大体可分为: 1.通过hog算子定位人脸,也可以用cnn模型,但本文没试过: ...

  7. python读取视频流做人脸识别_基于OpenCV和Keras实现人脸识别系列——二、使用OpenCV通过摄像头捕获实时视频并探测人脸、准备人脸数据...

    基于OpenCV和Keras实现人脸识别系列手记: 项目完整代码参见Github仓库. 本篇是上面这一系列手记的第二篇. 在Opencv初接触,图片的基本操作这篇手记中,我介绍了一些图片的基本操作,而 ...

  8. facebook人脸照片_为什么您的Facebook照片看起来如此糟糕(以及您可以如何做)...

    facebook人脸照片 Facebook is a popular platform for sharing photos, even though it's not a very good one ...

  9. ios 表情符号 键盘_使用iOS键盘键入时,表情符号在NSAttributedString中不显示,在Android上键入时表示...

    我正在制作一个混合应用程序,当我从 Android端发送表情符号时,它在iOS端显示正常,但iOS方面不能(似乎)显示来自iOS自己键盘的表情符号! 我在显示表情符号的标签使用了属性文本,文本来自HT ...

  10. python人脸深度识别_基于Python的深度学习人脸识别方法

    基于 Python 的深度学习人脸识别方法 薛同来 ; 赵冬晖 ; 张华方 ; 郭玉 ; 刘旭春 [期刊名称] <工业控制计算机> [年 ( 卷 ), 期] 2019(032)002 [摘 ...

最新文章

  1. 网络推广——网络推广专员浅析网站建设中少不了对细节的关注
  2. PHPStrom的快捷键突然失效解决方案
  3. c++ 向量的值逆序输出_C++中vector的常用方法
  4. 软件配置管理(三)软件配置管理核心功能
  5. 做程序员10年了,复制粘贴是我最牛的技能,直到我看到了这几个公众号
  6. 如何用iOS工程生成iOS模拟器包
  7. java实现空心四边形_Java输入数值形成对应的平行四边形,正三角形,棱形,空心棱形...
  8. 使用系统定时器SysTick实现精确延时微秒和毫秒函数
  9. 电脑怎么找到tomcat端口_更换内存条的时候我怎么找到自己电脑配置的详细信息...
  10. Discuz! X3.0/X3.1/X3.2通用 Apache伪静态规则
  11. [乱七八糟]分享今晚瞎逛来的网络东东
  12. 宏碁传奇14 Swift 指纹模块失效解决
  13. 前端入门 02:HTML入门
  14. java作为微信小程序的后端_微信小程序连接java后端
  15. Chinese Segmentation Introduction
  16. iOS开发:兼容适配iPhone X
  17. FineUI大版本升级,外置ExtJS库、去AXD化、表格合计行、表格可编辑单元格的增删改、顶部菜单框架
  18. 整理一些ps4的DNS
  19. 便携式双向无线电设备-市场现状及未来发展趋势
  20. 计算机科学系职业规划,计算机专业的职业生涯规划书

热门文章

  1. 详解YUV420数据格式
  2. 2021年国内好用的可视化工具
  3. cas 计算器 android,GeoGebra CAS计算器
  4. HTML表单颜色选择器
  5. 品质qc工程图_QC工程图-(品管)
  6. 自动驾驶车辆仿真模拟软件盘点
  7. matlab xlswrite函数,matlab打开excel (xlsread、xlswrite)实用方法...
  8. 量子计算机王,王正汉|量子计算机:下一轮工业革命的引擎
  9. 潮流能模型matlab,基于matlab的yalmip最优潮流建模的Infeasible problem
  10. ArcGis-学习笔记1-地图矢量化