ios识别人脸自动拍照_【iOS】自定义相机(七)人脸检测

人脸检测

自定义相机中我们可以进行聚焦操作,我们也能检测人脸之后对目标人脸进行聚焦,这样看上去会更加智能。在 iOS 中,我们可以通过 Core Image 中的CIDetector和CIFaceFeature进行人脸检测功能。但是,在拍照软件中,人间检测对帧率有较高的要求,刚才提到的基于静态图片人脸检测的类似乎不太够用。幸运的是,除了他们可以检测人脸,在 AVFoundation 中的AVCaptureMetadataOutput也支持人脸检测,并且他直接在捕捉会话中工作,使用起来也十分方便。本文主要介绍AVCaptureMetadataOutput在人脸检测上的应用。

AVCaptureMetadataOutput 使用

AVCaptureMetadataOutput的使用和其他AVCaptureOutput很相似,主要分为下面:

创建AVCaptureMetadataOutput对象

将该输出类添加到捕捉会话中

开启AVCaptureMetadataOutput的人脸检测功能

[self.metaOutput setMetadataObjectTypes:@[AVMetadataObjectTypeFace]];

设置AVCaptureMetadataOutputObjectsDelegate代理

[self.metaOutput setMetadataObjectsDelegate:self queue:self.metaQueue];

PS: 必须在添加进捕捉会话后再设置metadataObjectTypes,否则程序将会因为该输出类暂时不支持人脸检测而崩溃。

AVCaptureMetadataOutputObjectsDelegate

在AVCaptureMetadataOutput中其实最重要的就是AVCaptureMetadataOutputObjectsDelegate代理,我们也是通过一下代理方法来获取识别结果的:

- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof avmetadataobject> *)metadataObjects fromConnection:(AVCaptureConnection *)connection;

在这个方法中,我们最需要关注的就是metadataObjects数组,在这个数组中,我们能能拿到当前帧识别出来的所有对象。他的数组元素类型是AVMetadataObject,也是我们最终需要的AVMetadataFaceObject类的父类。在AVMetadataFaceObject中,我们可以获取以下信息:

time:识别到人脸的时间

duration:该人脸的维持时间

bounds:人脸在镜头中的位置(基于设备坐标)

需要使用AVCaptureVideoPreviewLayer中的坐标转换

faceID:人脸ID

rollAngle:倾斜角

表示人的头部向肩膀方向的侧斜角度

yawAngle:偏转角

人脸绕 y 轴旋转的角度

PS:浮点数在运算的时候会出现精度丢失的问题,这些细小的误差在视频处理中会无限放大,因此 AVFoundation 中时间的表示不用NSTimeInterval(double),而是使用CMTime。

CMTime其实就是使用分数来表示时间,即

。比如CMTimeMake(1,2)表示0.5秒

检测显示

因为有帧率和性能的要求,我们不能使用UIView显示。为了方便,本文使用CALayer进行显示:

人脸检测结果AVMetadataFaceObject中有faceID,我们需要将使用faceID区分不同人脸的人脸框显示CALayer,因此,需要下面的这个NSMutableDictionary进行存储:

@property (nonatomic, strong) NSMutableDictionary *faceLayers;

为了方便管理,我们统一将人脸框的CALayer添加到指定的CALayer(overlayLayer)上。在初始化的时候,需要注意以下细节:

overlayLayer的frame需要和预览视图一致

overlayLayer需要设置相应的sublayerTransform

为了显示yawAngle的效果,需要让子层绕 Y 轴旋转

self.overlayLayer.sublayerTransform = CATransform3DMakePerspective(1000);

CATransform3DMakePerspective

static CATransform3D CATransform3DMakePerspective(CGFloat eyePosition) {

CATransform3D transform = CATransform3DIdentity;

transform.m34 = -1.0 / eyePosition;

return transform;

}

人脸框显示前操作

上文说到,我们拿到的AVMetadataFaceObject中的bounds是基于设备坐标系的,但是显示的时候我们需要是普通视图坐标系中的。因此,需要先做下列的转换操作:

AVMetadataObject *transfromedFace = [self.videoPreviewLayer transformedMetadataObjectForMetadataObject:face]

人脸框显示操作

// 记录离开镜头的人脸框

NSMutableArray *lostFaces = [self.faceLayers.allKeys mutableCopy];

// 遍历识别到的所有人脸数据

for (AVMetadataFaceObject *face in transformedFaces) {

NSNumber *faceID = @(face.faceID);

[lostFaces removeObject:faceID];

// 获取人脸框

CALayer *layer = self.faceLayers[faceID];

if (!layer) {

layer = [self makeFaceLayer];

[self.overlayLayer addSublayer:layer];

self.faceLayers[faceID] = layer;

}

// 重置 transform

layer.transform = CATransform3DIdentity;

// 显示位置

layer.frame = face.bounds;

// 显示倾斜角

if (face.hasRollAngle) {

CATransform3D t = [face transformFromRollAngle];

layer.transform = CATransform3DConcat(layer.transform, t);

}

// 显示偏转角

if (face.hasYawAngle) {

CATransform3D t = [face transformFromYawAngle];

layer.transform = CATransform3DConcat(layer.transform, t);

}

}

// 移除已经离开镜头的人脸框

for (NSNumber *faceID in lostFaces) {

CALayer *layer = self.faceLayers[faceID];

[layer removeFromSuperlayer];

[self.faceLayers removeObjectForKey:faceID];

}

关于代码中transformFromRollAngle和transformFromYawAngle方法可以参考AVMetadataFaceObject+Transform.m

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值