AVFoundation 实现人脸识别

接着之前的视频采集之后今天聊下人脸识别,现在很多拍摄工具中的美颜,激萌效果等 都需要用到人脸识别。人脸识别的方案有CoreImage、 face++、OpenCV、libefacedetection、AV Foundation、vision 等,本文主要聊下AVFoundation 在视频拍摄中对人脸的捕捉。

大体流程如下

  • AVCaptureSessin 设置AVCaptureMetadataOutput 捕获元数据输出
  • 设置元数据类型为 AVMetadataObjectTypeFace
  • setMetadataObjectsDelegate 设置回调代理
  • didOutputMetadataObjects 回调中 让人脸信息传给AVCaptureVideoPreviewLayer
  • AVCaptureVideoPreviewLayer 上显示对应的人脸信息

1.AVCaptureSessin 设置AVCaptureMetadataOutput

这里要注意人脸检测要使用到硬件加速所以要放到主线程中

    // AVCaptureMetadataOutput 用于处理捕获会话AVCaptureSession产生的定时元数据的捕获输出。
    self.metadataOutput = [[AVCaptureMetadataOutput alloc]init];
    if ([self.captureSession canAddOutput:self.metadataOutput]) {
        [self.captureSession addOutput:self.metadataOutput];
        
        // 获取人脸 属性  也可以是二维码 条形码等
        NSArray *metadatObjectTypes = @[AVMetadataObjectTypeFace];
         //设置metadataObjectTypes 指定对象输出的元数据类型。
         self.metadataOutput.metadataObjectTypes = metadatObjectTypes;
           //创建主队列: 因为人脸检测用到了硬件加速,而且许多重要的任务都在主线程中执行,所以需要为这次参数指定主队列。
           dispatch_queue_t mainQueue = dispatch_get_main_queue();
           //通过设置AVCaptureVideoDataOutput的代理,就能获取捕获到一帧一帧数据
        [self.metadataOutput setMetadataObjectsDelegate:self queue:mainQueue];
  
    }

2.AVCaptureMetadataOutputObjectsDelegate 捕捉代理回调
将捕捉的人脸信息传给显示的层的layer(这里是只做人脸的一个框选,其他功能跟脸部信息有关的实现也都可在这个回调中)

- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputMetadataObjects:(NSArray *)metadataObjects
       fromConnection:(AVCaptureConnection *)connection {

    NSLog(@"有输出的");
    //使用循环,打印人脸数据
    for (AVMetadataFaceObject *face in metadataObjects) {
        
        NSLog(@"Face detected with ID:%li",(long)face.faceID);
        NSLog(@"Face detected with rollAngle:%f",face.rollAngle);
        NSLog(@"Face detected with yawAngle:%f",face.yawAngle);
        NSLog(@"Face bounds:%@",NSStringFromCGRect(face.bounds));
        
    }
    
    //将元数据 传递给 previewView.m   将元数据转换为layer
    [self.PreView didDetectFaces:metadataObjects];

}

3.AVCaptureVideoPreviewLayer 人脸信息的渲染

这里涉及到3个点 1.人脸位置跟layer上位置的转化transformedMetadataObjectForMetadataObject:这里跟上一篇中的摄像头聚焦时候的位置转化很像 2.人脸的rollAngle 和 yawAngle 转化成对应的angle(角度) 3.这里的faceID对于同一个人并不是唯一的,但如果是一直在采集中没有出过采集框就是唯一的

- (void)didDetectFaces:(NSArray *)faces{
   //创建一个本地数组 保存转换后的人脸数据
    NSArray *transformedFaces = [self transformedFacesFromFaces:faces];
       //获取faceLayers的key,用于确定哪些人移除了视图并将对应的图层移出界面。
    /*
        支持同时识别10个人脸
     */
    NSMutableArray *lostFaces = [self.faceLayers.allKeys mutableCopy];
      //遍历每个转换的人脸对象
    for (AVMetadataFaceObject *face in transformedFaces) {
         //获取关联的faceID。这个属性唯一标识一个检测到的人脸
        NSNumber *faceID = @(face.faceID);
         //将对象从lostFaces 移除
        [lostFaces removeObject:faceID];
          //拿到当前faceID对应的layer
        CALayer *layer = self.faceLayers[faceID];
          //如果给定的faceID 没有找到对应的图层
        if (!layer) {
             //调用makeFaceLayer 创建一个新的人脸图层
            layer = [self makeFaceLayerWith:face.bounds.size];
             //将新的人脸图层添加到 overlayLayer上
            [self.overlayLayer addSublayer:layer];
              //将layer加入到字典中
            self.faceLayers[faceID] = layer;
         }
        
        //设置图层的transform属性 CATransform3DIdentity 图层默认变化 这样可以重新设置之前应用的变化
        layer.transform = CATransform3DIdentity;
          //图层的大小 = 人脸的大小
        layer.frame = face.bounds;
         //判断人脸对象是否具有有效的斜倾交。 头部向肩膀方向的侧斜角度
        if (face.hasRollAngle) {
              //如果为YES,则获取相应的CATransform3D 值
            CATransform3D t = [self transformForRollAngle:face.rollAngle];
               //将它与标识变化关联在一起,并设置transform属性
            layer.transform = CATransform3DConcat(layer.transform, t);
        }
           //判断人脸对象是否具有有效的偏转角 人脸绕y轴旋转的角度
        if (face.hasYawAngle) {
              //如果为YES,则获取相应的CATransform3D 值
            CATransform3D  t = [self transformForYawAngle:face.yawAngle];
            layer.transform = CATransform3DConcat(layer.transform, t);
            
        }
    }
    //遍历数组将剩下的人脸ID集合从上一个图层和faceLayers字典中移除
    for (NSNumber *faceID in lostFaces) {
        CALayer *layer = self.faceLayers[faceID];
        [layer removeFromSuperlayer];
        [self.faceLayers  removeObjectForKey:faceID];
    }
    
}

按照这个思路就可以看到人脸的标记了,这里要涉及到最基础的视频采集可以看上一篇 AVFoundation 视频拍摄
人脸信息拿出来之后可以做很多事情,比如人脸数据匹配,活体检测,激萌效果等等。对应代码也上传的git上 AVFoundation 人脸识别

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259