媒体捕捉-iOS中的人脸识别

引言

在如今的移动应用和直播场景中,我们常常能体验到一种颇具趣味与互动性的功能:无论是美颜相机中的萌趣贴纸精准附着于人脸关键点上,还是主播们在直播时实时戴上可爱的虚拟动物耳朵或动态装饰物,这些令人眼前一亮的效果背后,都离不开人脸识别技术的支持。自iOS 6起,苹果引入了对AV Foundation框架中的人脸检测功能,这一突破性更新使得应用程序能够实时捕捉并精确定位多达10张人脸的特征信息。

介绍

方案:

人脸识别的整体实现方案与其它媒体捕捉的实现方案并没有很大区别,或者说所有媒体捕捉的实现都是这个步骤:

  1. 配置会话:配置AVCaptureSession,添加AVCaptureDeviceInput,添加AVCaptureOutput
  2. 启动会话:AVCaptureSession startRunning
  3. 停止会话(如果需要)AVCaptureSession stopRunning。

具体实现在这里就贴代码了,有需要可以查看这篇文章媒体捕捉-iOS自定义二维码扫描功能-CSDN博客

重点类

AVCaptureMetadataOutput

通过运用AVCaptureOutput家族中的特定类型AVCaptureMetadataOutput,开发者得以获取设备摄像头实时捕获的视频流,并从中提取出有价值的人脸元数据。这种输出并非普通的图像数据,而是封装在AVMetadataObject抽象类内的结构化信息,该类提供了一个通用接口来处理包括但不限于人脸在内的多种类型的元数据对象。

AVMetadataFaceObject

当开启人脸检测模式时,系统会智能识别出人脸区域,并以具体的子类AVMetadataFaceObject的形式输出详细的面部信息。这一技术层面的革新不仅丰富了用户在社交、娱乐等领域的交互体验,更为广泛应用如AR增强现实、虚拟妆容、表情识别等领域奠定了坚实的基础。

实现

因为实现的步骤和其它媒体捕捉的实现步骤几乎相同,所以我们把重点集中到添加会话输出和元数据处理这两个上面。

会话输出:

实现setupSessionOutputs:方法,创建一个新的AVCaptureMetaDataOutput实例并把它添加为捕捉会话的输出。

设置metadataobjectTypes属性指定对象输出的元数据类型为AVMetaObjectTypeFace。AV Foundation支持多种元数据类型的识别,所以当我们只对人脸元数据感兴趣时,需要明确指出。

objectivec 复制代码
//MARK:配置会话输出方法
- (BOOL)setupSessionOutputs:(NSError *__autoreleasing  _Nullable *)error{
    self.metadataOutput = [[AVCaptureMetadataOutput alloc] init];
    if ([self.captureSession canAddOutput:self.metadataOutput]) {
        [self.captureSession addOutput:self.metadataOutput];
        NSArray * metadataObjectTypes = @[AVMetadataObjectTypeFace];
        self.metadataOutput.metadataObjectTypes = metadataObjectTypes;
        dispatch_queue_t mainQueue = dispatch_get_main_queue();
        [self.metadataOutput setMetadataObjectsDelegate:self queue:mainQueue];
        return YES;
    }else{
        return NO;
    }
}
数据处理:

当有新的人脸元数据被检测到之后,AVCaptureMetadataOutput会回调它代理的captureOutput:didOutputMetadataObjects:fromConection方法。

objectivec 复制代码
//MARK:检测到指定兴趣点的代理
- (void)captureOutput:(AVCaptureOutput *)output didOutputMetadataObjects:(NSArray<__kindof AVMetadataObject *> *)metadataObjects fromConnection:(AVCaptureConnection *)connection{
    for (AVMetadataFaceObject * face in metadataObjects) {
        NSLog(@"Face detected with ID:%li",(long)face.faceID);
        NSLog(@"Face bounds:%@",NSStringFromCGRect(face.bounds));
    }
    [self.faceDetectionDelegate didDetectFaces:metadataObjects];
}

我们将获取到的人脸元数据传递到预览视图previewView来进行处理,在预览视图中首先调用了一个transformedCodesFromCodes:方法,只是我们自己定义的方法,在里面我们只是调用了AVCaptureVideoPreviewLayer提供的坐标转发方法将设备坐标空间元数据对象转换为视图坐标空间对象。

objectivec 复制代码
//MARK:代理 检测到人脸数组
- (void)didDetectFaces:(nonnull NSArray *)faces {
    NSArray * transformedFaces = [self transformedFacesFromFaces:faces];
    
}
//MARK:坐标转换
- (NSArray *)transformedFacesFromFaces:(NSArray *)faces{
    NSMutableArray * transformedFaces = [NSMutableArray array];
    for (AVMetadataObject * face in faces) {
        AVMetadataObject * transformedFace = [self.previewLayer transformedMetadataObjectForMetadataObject:face];
        [transformedFaces addObject:face];
    }
    return transformedFaces;
}

接下来从一个全局的人脸图层存储字典中获取所有的key组成一个待丢弃的人脸id数组。然后遍历数组将已经获取到的人脸id从带丢弃的人脸id数组中移除。然后获取或者创建新的人脸layer并设置frame及transform参数。此处代码主要实现的功能是让人脸layer追踪人脸移动,并标记已经消失的人脸layer。

objectivec 复制代码
- (void)didDetectFaces:(nonnull NSArray *)faces {
    NSArray * transformedFaces = [self transformedFacesFromFaces:faces];
    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;
        }
        layer.transform = CATransform3DIdentity;
        layer.frame = face.bounds;
    }
    
    for (NSNumber * faceID in lostFaces) {
        CALayer * layer = self.faceLayers[faceID];
        [layer removeFromSuperlayer];
        [self.faceLayers removeObjectForKey:faceID];
    }
}
//MARK:创建标记人脸layer
- (CALayer *)makeFaceLayer{
    CALayer * layer = [CALayer layer];
    layer.borderWidth = 5.0;
    layer.borderColor = [UIColor colorWithRed:0.188 green:0.517 blue:0.877 alpha:1.00].CGColor;
    return layer;
}

此时我们就已经可以绘制出人脸在预览视图中的frame了,但距离精确跟踪还差一点小步骤。

要实现这个功能,我们需要读取AVMetadataFaceObject中的rollAngle(滚动角-绕z轴)和yawAngle(偏转角-绕y轴),并将人脸图层layer进行相应的仿射变化。

objectivec 复制代码
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;
        }
        layer.transform = CATransform3DIdentity;
        layer.frame = face.bounds;
        if (face.hasRollAngle) {
            CATransform3D t = [self transformForRollAngle:face.rollAngle];
            layer.transform = CATransform3DConcat(layer.transform, t);
        }
        if (face.hasYawAngle) {
            CATransform3D t = [self transformForYawAngle:face.yawAngle];
            layer.transform = CATransform3DConcat(layer.transform, t);
        }
    }

仿射变化的代码如下:

objectivec 复制代码
//MARK:绕z轴旋转
- (CATransform3D)transformForRollAngle:(CGFloat)rollAngleInDegress{
    CGFloat rollAngleInRadians = THDegreesToRadians(rollAngleInDegress);
    return CATransform3DMakeRotation(rollAngleInRadians, 0.0, 0.0, 1.0);
}
//MARK:绕y轴旋转
- (CATransform3D)transformForYawAngle:(CGFloat)yawAngleInDegress{
    CGFloat yawAngleInRadians = THDegreesToRadians(yawAngleInDegress);
    CATransform3D yawTransform = CATransform3DMakeRotation(yawAngleInRadians, 0.0, -1.0, 0.0);
    return CATransform3DConcat(yawTransform, [self orientationTransform]);
}
//MARK:角度转弧度
static CGFloat THDegreesToRadians(CGFloat degress){
    return degress * M_PI / 180;
}
- (CATransform3D)orientationTransform{
    CGFloat angle = 0.0;
    switch ([UIDevice currentDevice].orientation) {
        case UIDeviceOrientationPortraitUpsideDown:
            angle = M_PI;
            break;
        case UIDeviceOrientationLandscapeRight:
            angle = -M_PI / 2.0;
            break;
        case UIDeviceOrientationLandscapeLeft:
            angle = M_PI / 2.0;
            break;
            
        default:
            angle = 0.0;
            break;
    }
    return CATransform3DMakeRotation(angle, 0.0, 0.0, 1.0);
}

结语

以上就是使用AV Foundation进行人脸检测的所有关键步骤,已经实现了一个比较粗糙的人脸识别的用户界面。要真正实现将帽子,贴纸等显示在人脸上并且拍照或者直播,还需要与其它框架的技术相结合,比如Quartz框架,或者OpenGL等。

相关推荐
璀璨星輝1 天前
安全删除硬件并弹出媒体(弹出显卡)问题处理
媒体
树莓集团2 天前
什么是数字化转型?对企业发展的帮助有哪些?
大数据·人工智能·云计算·新媒体运营·媒体
布兰妮甜3 天前
图片和媒体资源的优化:提升Web应用性能与用户体验的关键
前端·媒体·优化·图片
4A广告文案3 天前
品牌在社交媒体上的营销框架,有哪些重要节点?
媒体
云存储小天使5 天前
突破时间与空间限制的富媒体百宝箱——智能工具箱:让云上内容生产更easy
媒体
130252015125 天前
企业直播间媒体分发新闻转播拉流推广名单(金融财经科技类)
人工智能·金融·媒体
liuweni5 天前
Next.js流量教程:如何在 Next.js 中使用 React Helmet 管理 SEO Meta 标签
开发语言·javascript·经验分享·前端框架·创业创新·媒体·程序员创富
红米饭配南瓜汤6 天前
WebRTC服务质量(06)- 重传机制(03) NACK找到真正的丢包
网络·音视频·webrtc·媒体
130252015126 天前
哪些视频媒体平台可给企业直播间做分发拉流转播宣传?提升流量数据!
音视频·媒体·twitter
818源码资源站7 天前
WordPress酱茄主题 开源版 博客资讯自媒体网站模板
前端·媒体