精华内容
下载资源
问答
  • 人脸识别项目总结
    万次阅读 多人点赞
    2018-01-01 20:46:51

    前言

    这篇博客是记录如何将已有人脸识别算法的前提下,一步步搭建人脸识别系统,找人脸识别算法不用往下看了
    作为一水硕,研究生两年就做了一个半成品的人脸识别演示项目,突然想写点什么给以后的自己看看。也许未来自己会嘲笑现在写的烂代码,也许不会,也许未来会把这段经历忘掉。人脸识别伴随着我的研究生3年,也许这篇文章写着写着就成了我研究生的总结了。

    自己当前状态

    2015年,研究生正式入学,我以为我的生活是不停地搞学术,立刻我发现自己对学术没兴趣,我以为我的生活是参与一个精美的项目中进行coding,结果是不断地写demo做演示。我和我本科入学时犯了同样的错误看待问题,不全面,把事物看的太极端了,正如大学不是全是天堂,研究生也不是全是学术和项目。刚入学时,想着卧槽自己怎么也是个高级人才了,得学点高级的知识,什么机器学习,数据挖掘,图像处理都好好涉猎一下,但无奈没有钻研的决心与信心,自己又没啥天赋,到现在也只是知道名词,上网百度百度调用调用开源库。我们导师的人脸识别项目组,我可能是最后一届,整体项目已经过渡到另一个老师下面了。研一时不停地上课,被同学拉着参加两个比赛,顺带出差做演示;研二浑浑噩噩,看论文,出差,写demo,做演示;研三找工作、写论文,写项目;两年半,就这么平平淡淡过来了,并不出彩,但也没混日子。

    项目前身

    被分到人脸识别组时,人脸识别组已经火过一波了。当时,我们导师从外面搞来了一整套系统,这套系统是一个成熟而完整的产品,有多成熟而完整?这套系统支持sqlserver、 mysql 、oracle等数据库,安装包有近400M,有不错的GUI界面,以windows 服务作为提供后台服务,支持C#和C++调用接口,从1:1人脸相似度比较到1:N的黑名单搜索,从静态图片搜索到视频流实时跟踪都支持,印象中还有一些我看不懂的功能。我所做的项目也是模仿的这套系统。这套系统的缺点也很明显,那就是严格的加密,每次运行时都需要一个加密狗插在电脑上,每两个月需通过专门的人员更新加密狗,它做了什么?如何做的?对于我们几乎是黑盒。当时这套系统就是我们组的命根子,研一研二时的演示我们组就主要就靠它,每次要演示都要担心加密狗是否过期了。

    我无法回忆起当时的是什么促成了我想自己动手实现一个人脸识别的项目,也许是厌烦了整天拿着那套系统出去演示还要说是我们自己的技术,也许是当时出现了seetaface这样一个开源的技术,也许是师兄的鼓励,也许是闲的蛋疼自己想找点事做,也许是必然。

    在对那整套人脸识别的二次开发中,一次有客户要求能够从远程调用人脸识别接口,我询问师兄 ,师兄说写过。打开师兄封装的代码,封装得也太简单了,不就是WCF吗?本科我也学过。我得做些什么,C#不是可以查看引用dll的所有类吗?好!我把所有的类都自己二次封装一遍,以后远程调用就更加灵活了,然而最终并没有用上。这次封装直加深了我对这套系统的认识,算是对未来自己构建人脸识别系统打下基础。

    研一暑假时,导师来了一个行驶证识别项目,手机拍摄的照片,各种角度和光照的都有,导师让我和师兄试试,师兄和我不知道其中的难度,便开始了尝试。那个暑假我在师兄的指导下完成了opencv的配置;尝试opencv各种自带函数:膨胀收缩、放射变换、高斯模糊、霍夫变换、灰度均衡化等;使用tesseract进OCR,最终做出了针对某一张照片的识别,理所当然项目没成功。

    研二时,外面的人脸识别技术依旧火热,seetaface出现,听说效果不错,LFW能到97.1%,和现有的这套系统一对比,效果真的不错,好多没有检测到的人脸都检测出来了,如果我能照着写一套支持视频流的演示系统,那就不用受加密狗的约束了,说干就干,花了大概20天一套基于opencv的原始系统被我写出来了。期间人脸组也添加一个师弟,师弟是很厉害,初中学编程,能自己写外挂,ACM拿过奖。我让师弟给我的系统加一个线程并行,他花了半天加了一个线程池任务队列,这个机制我一直到研三才弄懂,但后来师弟到别的项目组了,可能觉得我们这边只有他一个16级的,亦或是在这边没人指导。后来老师又搞了一个人脸识别算法,这次不是一个系统,直接以库的形式给我们,但仍然需要加密狗,因为加密狗的缘故,它不能断点调试,开发很痛苦,不过有了前面seetaface的经验,我很快又完成了一个系统。研二寒假时,导师的合作人有个人脸开闸机的项目,需要做出演示系统来,为这个项目拖到了过年的前一天才回家。同时,我们导师手下的另一个老师L,接手了此前一个与外面合作的动态人脸识别的项目,项目搞得很大,有政府部门和好几家公司,但我们这边写代码的只有三人,我、L老师的一个学生P和公司的一个人X,此时,我带起了我真正意义上的师弟。项目是基于我的系统,几轮测试下来,不太理想,但还是让我们测试了一段时间。期间,我们对代码进行修正,但bug仍不段出现,内存泄漏,程序莫名崩溃,无法断点调试。项目一直持续到17年的7月,最终不了了之。

    17年的9月下旬时,此时我已研三了,L老师又有一个项目,要把以前的C/S架构改成B/S架构。我答应下来后端开发的任务,从github上找了一个http服务器魔改一下,前后断断续续花了一个月,完成了任务,后来将项目给了P。时至今日,2018年的元旦,估计P仍在我的基础上改着程序。

    人脸识别详情

    一、人脸识别SDK

    所谓人脸识别接口有三个:

    步骤名称函数名输入输出说明
    1人脸检测 face detectionDetectFace图像人脸位置
    2人脸特征抽取 feature extractionExtract图像,人脸位置特征数组将人脸图像变成大小固定的特征数组
    3特征相似度比较feature comparationCompare特征数组,特征相似度比较人脸特征的相似度

    有的人脸识别接口会存在第1.5步 :检测人脸关键点,眼睛鼻子嘴之类的,无需在意。

    二、人脸识别系统

    1基本功能

    一个初级人脸识别系统需要的基本功能如下:

    编号名称函数输入输出
    1人员注册Register人脸图像,人员信息————
    2人员搜索Search人脸图像,相似度阈值,最大候选数可能相似的人员
    • 人员注册
      人员注册会用到如下数据结构,最关键的是face_feature,它由人脸识别SDK的前两步得到:
    struct Person{
          int id;
          array<?> face_feature;
          string face_image_path;//(image face_image;)
          string name;
          string gender;//性别
          .
          .
    }
    • 人员搜索
      人员搜索会面临输入图像中存在多个人脸的情况,这里首先讨论单个人脸的情况。

    首先确定搜索的返回结构Hitrecord,如下:

    struct Hitrecord{
          float threshold;//搜索时设定的阈值
          //image search_face_image;//搜索的人脸图片
          string search_face_image_path;//搜索的人脸图片
          //`hit_detials`中的`HitDetial`是按`score`降序排列的
          array<HitDetial> hit_detials;//候选的人员结果
          time occur_time;//发生时间
    }
    struct HitrecordDetail{
          float score;//相似度
          int person_id;
    }

    在搜索之前所有的注册人员信息都载入内存了,整个搜索过程如下:

    • 利用SDK的前两步得到搜索的人脸特征feature
    • feature与每个已经注册的人员的face_feature依次进行Compare得到相似度,剔除掉小于相似度阈值的结果,保留最大的几个结果。

    对于输入中存在多个人脸的情况,只需分开处理即可

    2数据库模块-DataAgine 工程

    以上的基本功能并没有考虑数据存储的问题,当然我写过没有数据库的版本,直接将注册的人员库序列化到文件中,而不保留命中的记录,这样做很省事,但只能演示,客户肯定是要查看最终的命中纪录的,也就是以Hitrecord为基础的扩展数据。所以必须考虑存储的问题。
    最终我用了mysql数据库,原因很简单,mysql很容易安装,下载解压,输几个命令就行了。

    根据基本功能根据基本功能我写了如下几个表:

    CREATE DATABASE `frsdb`;
    USE `frsdb`;
    
    create table `frsdb`.`person`
    (
        `id` int(11) AUTO_INCREMENT,
        `name` nvarchar(50) NULL,
        `gender` char(1) NULL,
        `face_image_path` varchar(200) NOT NULL,
        `feature_data` LongBlob NOT NULL,
        PRIMARY KEY (`id`),
        UNIQUE KEY `id` (`id`)
    )ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    create table `frsdb`.`hitrecord`
    (
        `id` int(11) AUTO_INCREMENT,
        `search_face_image_path` varchar(200) NOT NULL,
        `threshold` float NOT NULL,
        `occur_time` datetime NOT NULL,
        PRIMARY KEY (`id`),
        UNIQUE KEY `id` (`id`)
    )ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    create table `frsdb`.`hitrecord_detail`
    (
        `id` int(11) AUTO_INCREMENT,
        `hitrecord_id` int(11) NOT NULL,
        `person_id` int(11) NOT NULL, 
        `rank` int(11) NOT NULL,
        `score` float NOT NULL,
        PRIMARY KEY (`id`),
        UNIQUE KEY `id` (`id`)
    )ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    create view `frsdb`.`hitalert` as 
    select 
        hit.id,
        hit.search_face_image_path,
        hit.threshold,
        hit.occur_time,
        detail.id as detail_id,
        detail.rank,
        detail.score,
        person.id as person_id,
        person.name as person_name,
        person.gender as person_gender,
        person.face_image_path as person_face_image_path,
        FROM 
        (`frsdb`.`hitrecord_detail` as detail
        left join `frsdb`.`hitrecord` as hit on detail.hitrecord_id=hit.id) 
        left join `frsdb`.`person` as person on detail.person_id = person.id;

    为了最后的方便查看命中记录,我创建了视图hitalert

    我用了动软的代码生成器,自动生成了Model,DLL,BLL,所谓的三层架构。动软Model,DLL,BLL三层分布在不同的项目中,我嫌项目太多,直接将他们合为一个DataAgine 项目,只是Model,DLL,BLL放在了三个不同的文件夹中。

    3基本实现

    完备的人脸识别演示系统,无非就是不断从视频中抽画面帧,进行人员搜索。

    现在我手里有一个对外提供C语言接口的windows人脸识别SDK,图片是以char数组的形式传入的,它可以检测人脸 提取人脸的特征(固定大小的数组),比较特征间的相似度。我要实现什么?注册、搜索、与视频流进行对接,实现实时监控。

    我的内心活动:图片什么的,用opencv就好了,貌似opencv也支持视频流的读取,等等,得有界面啊,opencv貌似只能用C++啊,C++ windows GUI开发下有qt和MFC,卧槽都不熟,我只会C# GUI,拖拽控件就行了。 C#和C++怎么交互啊。经过一番寻觅,最终我确定了用托管C++来实现,也就是“CLI/C++”,它可以同时使用C++和C#的库,C#也可以直接引用托管C++写的库,perfect! 就是它了,主体实现就用它了。

    话外音:其实主体用托管C++,不一定是最好的选择,C#一样可以处理图片和视频流的库,托管C++语法需要慢慢熟悉,有坑踩。托管C++(C#)的数组类型,与C++的数组类型转换就很烦,stackoverflow解决了。托管C++(C#)的Image类型到 opencv 的Mat类型也烦,github 找了个opencvsharp解决了。

    基本功能中的Register和Search 就放一个类中,就叫PersonDataset,人脸识别的接口也得托管C++用封装一下,以防C#调用(事实上并没有发生),还得有一个负责视处理频流的类,就参考opencv叫Capture,每个Capture就对应一个PersonDataset对象。

    class PersonDataset{
        array<Person> persons;//存放注册的用户
        int LoadAllPerson();//载入人员库
        int Register(Image im, String name,String gender..)//注册
        //搜索,接受图片,相似度阈值,每张人脸返回的最大候选数目,存在数据库操作
        array<Hitrecord> Search(Image im,float thresh,int maxCandinateNum);
    }
    Class Capture{
        PersonDataset *personDataset;
        Callback OnHit(array<Hitrecord> hits);//每次命中时的回掉函数,C#中用事件
        Callback OnGrab(Image im);//每次获取一帧画面时的回掉函数,用于展示,让一个控件显示im
        //循环搜索线程
        Thread searchThread{
               while(runing){
                  获取一帧画面frame;
                  hits=personDataset->Search(frame,..);
                  OnHit(hits);//调用回调
               }
        }
        //循环显示线程
        Thread showThread{
               while(runing){
                 获取一帧画面frame;
                 Sleep(30);//休眠30ms
                 OnGrab(frame);
               }
        }
    
        int Start(String videoAddress){
            开启视频流;
            showThread.start();
            searchThread.start();
        }
    }

    由于使用了多线程Capture,在读取画面时,互斥必不可少。Capture需要与一个PersonDataset相关联。Capture 靠回调函数返回结果。开始时,Start开启了两个线程一个用来显示画面,一个用来返回命中结果。

    以上都是一个后台逻辑的实现,采用的都是托管C++,还需要一个界面。界面用的是winform,C#直接引用DataAngine的所编译的库,其他就是接收视频地址的TextBox,开始停止,查询用的Button,显示查询结果的DatagridView,显示监控画面的PictureBox,做的很是丑陋。

    4系统改进

    opencv 处理的视频流用的是VideoCapture类有bug,会花屏,每次开启关闭视频流会内存泄漏,后来改用了vlc,在github上搜vlc opencv windows 找到个例子直接用了 。

    为了提高精度,L老师想出了利用海康摄像头自带人脸跟踪的功能,一个人从出现到消失在镜头中海康摄像头会记录这个人的几张照片。提高精度就靠这几张照片,假设有5张,首先对这5张照片都搜索,返回:

    {{a1,b1,c1,d1,e1},{a2,b2,c2,d2,e2},{a3,b3,c3,d3,e3},{a4,b4,c4,d4,e4},{a5,b5,c5,d5,e5}}

    a b c d e 的分数为降序。

    • 返回这五张照片中分数最高的那个
    • 返回ab 相差最大的那个a,这个貌似结果好一点
    • 返回a 中多数的那个

    三、从C/S到B/S

    从C/S到B/S,客户需要自己添加设备信息(device),人员库类别也有多种(person 表添加一个type字段就可以),还需要一个表将设备与人员库象关联(surveillance_task

    create table `frsdb`.`device`
    (
        `id` int(11) AUTO_INCREMENT,    
        `name` nvarchar(50) NOT NULL,
        `video_address` nvarchar(200) NOT NULL
        PRIMARY KEY (`id`),
        UNIQUE KEY `id` (`id`)
    )ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    create table `frsdb`.`surveillance_task`
    (
        `id` int(11) AUTO_INCREMENT,
        `name` nvarchar(50) NOT NULL,
        `person_type` int(11) NOT NULL,
        `device_id` int(11) NOT NULL,
        PRIMARY KEY (`id`),
        UNIQUE KEY `id` (`id`)
    )ENGINE=InnoDB DEFAULT CHARSET=utf8;

    每次开始需要指定一个surveillance_taskid来载入指定的人员,监控指定的设备。

    不得不说程序员都是乐观的,当时我从来没有做过这样的项目,没写过网站项目。完全不知道怎么返回数据,思考了半天,我觉得和http服务器有点像,客户端(浏览器)请求一个地址,我给它返回一个数据,于是在gitihub找了个C#的http服务器,直接魔改了。当然其中过程有些曲折。原来的服务器只能返回静态文件,后来改成了可以根据不同的地址和参数接受返回不同的(json)数据,期间我接触了restful 风格的设计,于是就有了以下的设计:

    获得id1的设备
    GET http://localhost:8080/v1/device/1/update 
    
    添加设备
    GET http://localhost:8080/v1/device/
    
    更新id1的设备
    POST http://localhost:8080/v1/device/1/update 
    
    删除id1的设备
    POST http://localhost:8080/v1/device/1/delete 

    至此传统的 服务–客户端 已经走通,还有个难题,那就是如何实时更新命中的数据(hitrecord)到客户端?我查了一下可以用websocket,没错又是在github上找了一个C#的websocket 库– fleck,但我不是直接用,而是将其最主要的通信功能抠出来,fleck原来是通过回掉函数进行通信,一旦有连接到达就发送数据,通信完毕就直接关闭websocket了。现在我需要改成:只要客户端不关闭,我就一直向客户端发送数据的逻辑,同时如果有别的客户端连接了,我就主动关闭。没错这只是一个伪B/S,因为实时更新的websocket只能有一个客户端。

    FaceAngine的改动并不大,只需要在OnHit中使用websocket向客户端发送数据就可以,OnGrab没有作用了。

    总结

    自学。

    更多相关内容
  • 人脸识别技术总结 人脸识别技术大总结Face Detection Alignment 20XX-04-08 搞了一年人脸识别寻思着记录点什么于是 想写这么个系列介绍人脸识别的四大块Face detection,alignment,verification and identification...
  • opencv 机器学习 人脸识别 图像图形处理总结, 入门学习
  • 人脸识别技术大总结 百度人脸识别技术大总结 觉得应该跟大家分享这里给大家转摘到百度 篇一人脸识别技术的主要研究方法绪论人脸识别是通过分析脸部器官的唯一形状和位置来进行身份鉴别 人脸识别是一种重要的生物特征...
  • 人脸识别是人工智能在智能感知领域的一项重要任务,同时也具备巨大的实用价值。本文主要从人脸识别的起源、发展历程、主要方法、关键技术、主要应用和发展前景等方面对人脸识别进行阐述。
  • 人脸识别综合实践报告 人脸识别综合实践报告 一实践背景 人脸识别技术作为生物特征识别领域中一种基于生理特征的识别是通过计算机提取人脸特征并根据这些特征进行身份验证的一种技术同其它生物识别技术相比人脸识别...
  • 基于百度AI人脸识别的考勤系统设计与实现.pdf
  • 点击上方“小白学视觉”,选择加"星标"或“置顶”重磅干货,第一时间送达英国赫特福德大学与 GBG Plc 的研究者近日发布了一篇综述论文,对人脸识别方法进行了全面的梳理和总结,其中涵盖各种传统方法和如今风头正盛...

    点击上方“小白学视觉”,选择加"星标"或“置顶

    重磅干货,第一时间送达

    英国赫特福德大学与 GBG Plc 的研究者近日发布了一篇综述论文,对人脸识别方法进行了全面的梳理和总结,其中涵盖各种传统方法和如今风头正盛的深度学习方法。机器之心重点编译介绍了其中的深度学习方法部分,更多有关传统人脸识别方法的内容请参阅原论文。

    4767da93caf13d70b108ec4e87c879b3.png

    论文地址:https://arxiv.org/abs/1811.00116

    自七十年代以来,人脸识别已经成为了计算机视觉和生物识别领域被研究最多的主题之一。基于人工设计的特征和传统机器学习技术的传统方法近来已被使用非常大型的数据集训练的深度神经网络取代。在这篇论文中,我们对流行的人脸识别方法进行了全面且最新的文献总结,其中既包括传统方法(基于几何的方法、整体方法、基于特征的方法和混合方法),也有深度学习方法。

    引言

    人脸识别是指能够识别或验证图像或视频中的主体的身份的技术。首个人脸识别算法诞生于七十年代初 [1,2]。自那以后,它们的准确度已经大幅提升,现在相比于指纹或虹膜识别 [3] 等传统上被认为更加稳健的生物识别方法,人们往往更偏爱人脸识别。让人脸识别比其它生物识别方法更受欢迎的一大不同之处是人脸识别本质上是非侵入性的。比如,指纹识别需要用户将手指按在传感器上,虹膜识别需要用户与相机靠得很近,语音识别则需要用户大声说话。相对而言,现代人脸识别系统仅需要用户处于相机的视野内(假设他们与相机的距离也合理)。这使得人脸识别成为了对用户最友好的生物识别方法。这也意味着人脸识别的潜在应用范围更广,因为它也可被部署在用户不期望与系统合作的环境中,比如监控系统中。人脸识别的其它常见应用还包括访问控制、欺诈检测、身份认证和社交媒体。

    当被部署在无约束条件的环境中时,由于人脸图像在现实世界中的呈现具有高度的可变性(这类人脸图像通常被称为自然人脸(faces in-the-wild)),所以人脸识别也是最有挑战性的生物识别方法之一。人脸图像可变的地方包括头部姿势、年龄、遮挡、光照条件和人脸表情。图 1 给出了这些情况的示例。

    87155da63722135264adcbc3a75768cc.png

    图 1:在自然人脸图像中找到的典型变化。(a)头部姿势,(b)年龄,(c)光照,(d)面部表情,(e)遮挡。

    人脸识别技术这些年已经发生了重大的变化。传统方法依赖于人工设计的特征(比如边和纹理描述量)与机器学习技术(比如主成分分析、线性判别分析或支持向量机)的组合。人工设计在无约束环境中对不同变化情况稳健的特征是很困难的,这使得过去的研究者侧重研究针对每种变化类型的专用方法,比如能应对不同年龄的方法 [4,5]、能应对不同姿势的方法 [6]、能应对不同光照条件的方法 [7,8] 等。近段时间,传统的人脸识别方法已经被基于卷积神经网络(CNN)的深度学习方法接替。深度学习方法的主要优势是它们可用非常大型的数据集进行训练,从而学习到表征这些数据的最佳特征。网络上可用的大量自然人脸图像已让研究者可收集到大规模的人脸数据集 [9-15],这些图像包含了真实世界中的各种变化情况。使用这些数据集训练的基于 CNN 的人脸识别方法已经实现了非常高的准确度,因为它们能够学到人脸图像中稳健的特征,从而能够应对在训练过程中使用的人脸图像所呈现出的真实世界变化情况。此外,深度学习方法在计算机视觉方面的不断普及也在加速人脸识别研究的发展,因为 CNN 也正被用于解决许多其它计算机视觉任务,比如目标检测和识别、分割、光学字符识别、面部表情分析、年龄估计等。

    人脸识别系统通常由以下构建模块组成:

    • 人脸检测。人脸检测器用于寻找图像中人脸的位置,如果有人脸,就返回包含每张人脸的边界框的坐标。如图 3a 所示。

    • 人脸对齐。人脸对齐的目标是使用一组位于图像中固定位置的参考点来缩放和裁剪人脸图像。这个过程通常需要使用一个特征点检测器来寻找一组人脸特征点,在简单的 2D 对齐情况中,即为寻找最适合参考点的最佳仿射变换。图 3b 和 3c 展示了两张使用了同一组参考点对齐后的人脸图像。更复杂的 3D 对齐算法(如 [16])还能实现人脸正面化,即将人脸的姿势调整到正面向前。

    • 人脸表征。在人脸表征阶段,人脸图像的像素值会被转换成紧凑且可判别的特征向量,这也被称为模板(template)。理想情况下,同一个主体的所有人脸都应该映射到相似的特征向量。

    • 人脸匹配。在人脸匹配构建模块中,两个模板会进行比较,从而得到一个相似度分数,该分数给出了两者属于同一个主体的可能性。

    ea65587e442bea056c2da3732f016917.png

    图 2:人脸识别的构建模块。

    很多人认为人脸表征是人脸识别系统中最重要的组件,这也是本论文第二节所关注的重点。

    36aee811934f4d86ede9574c45503076.png

    图 3:(a)人脸检测器找到的边界框。(b)和(c):对齐后的人脸和参考点。

    深度学习方法

    卷积神经网络(CNN)是人脸识别方面最常用的一类深度学习方法。深度学习方法的主要优势是可用大量数据来训练,从而学到对训练数据中出现的变化情况稳健的人脸表征。这种方法不需要设计对不同类型的类内差异(比如光照、姿势、面部表情、年龄等)稳健的特定特征,而是可以从训练数据中学到它们。深度学习方法的主要短板是它们需要使用非常大的数据集来训练,而且这些数据集中需要包含足够的变化,从而可以泛化到未曾见过的样本上。幸运的是,一些包含自然人脸图像的大规模人脸数据集已被公开 [9-15],可被用来训练 CNN 模型。除了学习判别特征,神经网络还可以降维,并可被训练成分类器或使用度量学习方法。CNN 被认为是端到端可训练的系统,无需与任何其它特定方法结合。

    用于人脸识别的 CNN 模型可以使用不同的方法来训练。其中之一是将该问题当作是一个分类问题,训练集中的每个主体都对应一个类别。训练完之后,可以通过去除分类层并将之前层的特征用作人脸表征而将该模型用于识别不存在于训练集中的主体 [99]。在深度学习文献中,这些特征通常被称为瓶颈特征(bottleneck features)。在这第一个训练阶段之后,该模型可以使用其它技术来进一步训练,以为目标应用优化瓶颈特征(比如使用联合贝叶斯 [9] 或使用一个不同的损失函数来微调该 CNN 模型 [10])。另一种学习人脸表征的常用方法是通过优化配对的人脸 [100,101] 或人脸三元组 [102] 之间的距离度量来直接学习瓶颈特征。

    使用神经网络来做人脸识别并不是什么新思想。1997 年就有研究者为人脸检测、眼部定位和人脸识别提出了一种名为「基于概率决策的神经网络(PBDNN)」[103] 的早期方法。这种人脸识别 PDBNN 被分成了每一个训练主体一个全连接子网络,以降低隐藏单元的数量和避免过拟合。研究者使用密度和边特征分别训练了两个 PBDNN,然后将它们的输出组合起来得到最终分类决定。另一种早期方法 [104] 则组合使用了自组织映射(SOM)和卷积神经网络。自组织映射 [105] 是一类以无监督方式训练的神经网络,可将输入数据映射到更低维的空间,同时也能保留输入空间的拓扑性质(即在原始空间中相近的输入在输出空间中也相近)。注意,这两种早期方法都不是以端到端的方式训练的([103] 中使用了边特征,[104] 中使用了 SOM),而且提出的神经网络架构也都很浅。[100] 中提出了一种端到端的人脸识别 CNN。这种方法使用了一种孪生式架构,并使用了一个对比损失函数 [106] 来进行训练。这个对比损失使用了一种度量学习流程,其目标是最小化对应同一主体的特征向量对之间的距离,同时最大化对应不同主体的特征向量对之间的距离。该方法中使用的 CNN 架构也很浅,且训练数据集也较小。

    上面提到的方法都未能取得突破性的成果,主要原因是使用了能力不足的网络,且训练时能用的数据集也相对较小。直到这些模型得到扩展并使用大量数据 [107] 训练后,用于人脸识别的首个深度学习方法 [99,9] 才达到了当前最佳水平。尤其值得一提的是 Facebook 的 DeepFace [99],这是最早的用于人脸识别的 CNN 方法之一,其使用了一个能力很强的模型,在 LFW 基准上实现了 97.35% 的准确度,将之前最佳表现的错误率降低了 27%。研究者使用 softmax 损失和一个包含 440 万张人脸(来自 4030 个主体)的数据集训练了一个 CNN。本论文有两个全新的贡献:(1)一个基于明确的 3D 人脸建模的高效的人脸对齐系统;(2)一个包含局部连接的层的 CNN 架构 [108,109],这些层不同于常规的卷积层,可以从图像中的每个区域学到不同的特征。在那同时,DeepID 系统 [9] 通过在图块(patch)上训练 60 个不同的 CNN 而得到了相近的结果,这些图块包含十个区域、三种比例以及 RGB 或灰度通道。在测试阶段,会从每个图块提取出 160 个瓶颈特征,加上其水平翻转后的情况,可形成一个 19200 维的特征向量(160×2×60)。类似于 [99],新提出的 CNN 架构也使用了局部连接的层。其验证结果是通过在这种由 CNN 提取出的 19200 维特征向量上训练一个联合贝叶斯分类器 [48] 得到的。训练该系统所使用的数据集包含 202599 张人脸图像,来自 10177 位名人 [9]。

    对于基于 CNN 的人脸识别方法,影响准确度的因素主要有三个:训练数据、CNN 架构和损失函数。因为在大多数深度学习应用中,都需要大训练集来防止过拟合。一般而言,为分类任务训练的 CNN 的准确度会随每类的样本数量的增长而提升。这是因为当类内差异更多时,CNN 模型能够学习到更稳健的特征。但是,对于人脸识别,我们感兴趣的是提取出能够泛化到训练集中未曾出现过的主体上的特征。因此,用于人脸识别的数据集还需要包含大量主体,这样模型也能学习到更多类间差异。[110] 研究了数据集中主体的数量对人脸识别准确度的影响。在这项研究中,首先以降序形式按照每个主体的图像数量对一个大数据集进行了排序。然后,研究者通过逐渐增大主体数量而使用训练数据的不同子集训练了一个 CNN。当使用了图像数量最多的 10000 个主体进行训练时,得到的准确度是最高的。增加更多主体会降低准确度,因为每个额外主体可用的图像非常少。另一项研究 [111] 研究了更宽度的数据集更好,还是更深度的数据集更好(如果一个数据集包含更多主体,则认为它更宽;类似地,如果每个主体包含的图像更多,则认为它更深)。这项研究总结到:如果图像数量相等,则更宽的数据集能得到更好的准确度。研究者认为这是因为更宽度的数据集包含更多类间差异,因而能更好地泛化到未曾见过的主体上。表 1 展示了某些最常用于训练人脸识别 CNN 的公开数据集。

    6ad25e8579621ca784a8c2b7033105e3.png

    表 1:公开的大规模人脸数据集。

    用于人脸识别的 CNN 架构从那些在 ImageNet 大规模视觉识别挑战赛(ILSVRC)上表现优异的架构上取得了很多灵感。举个例子,[11] 中使用了一个带有 16 层的 VGG 网络 [112] 版本,[10] 中则使用了一个相似但更小的网络。[102] 中探索了两种不同类型的 CNN 架构:VGG 风格的网络 [112] 和 GoogleNet 风格的网络 [113]。即使这两种网络实现了相当的准确度,但 GoogleNet 风格的网络的参数数量少 20 倍。更近段时间,残差网络(ResNet)[114] 已经成为了很多目标识别任务的最受偏爱的选择,其中包括人脸识别 [115-121]。ResNet 的主要创新点是引入了一种使用捷径连接的构建模块来学习残差映射,如图 7 所示。捷径连接的使用能让研究者训练更深度的架构,因为它们有助于跨层的信息流动。[121] 对不同的 CNN 架构进行了全面的研究。在准确度、速度和模型大小之间的最佳权衡是使用带有一个残差模块(类似于 [122] 中提出的那种)的 100 层 ResNet 得到的。

    51d1ff9c080b87ed5061f4819ce65fdc.png

    图 7:[114] 中提出的原始的残差模块。

    选择用于训练 CNN 方法的损失函数已经成为近来人脸识别最活跃的研究领域。即使使用 softmax 损失训练的 CNN 已经非常成功 [99,9,10,123],但也有研究者认为使用这种损失函数无法很好地泛化到训练集中未出现过的主体上。这是因为 softmax 损失有助于学习能增大类间差异的特征(以便在训练集中区别不同的类),但不一定会降低类内差异。研究者已经提出了一些能缓解这一问题的方法。优化瓶颈特征的一种简单方法是使用判别式子空间方法,比如联合贝叶斯 [48],就像 [9,124,125,126,10,127] 中所做的那样。另一种方法是使用度量学习。比如,[100,101] 中使用了配对的对比损失来作为唯一的监督信号,[124-126] 中还结合使用了分类损失。人脸识别方面最常用的度量学习方法是三元组损失函数 [128],最早在 [102] 中被用于人脸识别任务。三元组损失的目标是以一定余量分开正例对之间的距离和负例对之间的距离。从数学形式上讲,对于每个三元组 i,需要满足以下条件 [102]:

    778a0ec5a1ae19b4a4ae963aaf5ed76c.png

    其中 x_a 是锚图像,x_p 是同一主体的图像,x_n 是另一个不同主体的图像,f 是模型学习到的映射关系,α 施加在正例对和负例对距离之间的余量。在实践中,使用三元组损失训练的 CNN 的收敛速度比使用 softmax 的慢,这是因为需要大量三元组(或对比损失中的配对)才能覆盖整个训练集。尽管这个问题可以通过在训练阶段选择困难的三元组(即违反余量条件的三元组)来缓解 [102],但常见的做法是在第一个训练阶段使用 softmax 损失训练,在第二个训练阶段使用三元组损失来对瓶颈特征进行调整 [11,129,130]。研究者们已经提出了三元组损失的一些变体。比如 [129] 中使用了点积作为相似度度量,而不是欧几里德距离;[130] 中提出了一种概率式三元组损失;[131,132] 中提出了一种修改版的三元组损失,它也能最小化正例和负例分数分布的标准差。用于学习判别特征的另一种损失函数是 [133] 中提出的中心损失(centre loss)。中心损失的目标是最小化瓶颈特征与它们对应类别的中心之间的距离。通过使用 softmax 损失和中心损失进行联合训练,结果表明 CNN 学习到的特征能够有效增大类间差异(softmax 损失)和降低类内个体差异(中心损失)。相比于对比损失和三元组损失,中心损失的优点是更高效和更容易实现,因为它不需要在训练过程中构建配对或三元组。另一种相关的度量学习方法是 [134] 中提出的范围损失(range loss),这是为改善使用不平衡数据集的训练而提出的。范围损失有两个组件。类内的损失组件是最小化同一类样本之间的 k-最大距离,而类间的损失组件是最大化每个训练批中最近的两个类中心之间的距离。通过使用这些极端案例,范围损失为每个类都使用同样的信息,而不管每个类别中有多少样本可用。类似于中心损失,范围损失需要与 softmax 损失结合起来以避免损失降至零 [133]。

    当结合不同的损失函数时,会出现一个困难,即寻找每一项之间的正确平衡。最近一段时间,已有研究者提出了几种修改 softmax 损失的方法,这样它无需与其它损失结合也能学习判别特征。一种已被证明可以增加瓶颈特征的判别能力的方法是特征归一化 [115,118]。比如,[115] 提出归一化特征以具有单位 L2 范数,[118] 提出归一化特征以具有零均值和单位方差。一个成功的方法已经在 softmax 损失中每类之间的决策边界中引入了一个余量 [135]。为了简单,我们介绍一下使用 softmax 损失进行二元分类的情况。在这种情况下,每类之间的决策边界(如果偏置为零)可由下式给定:

    82ce6e8573c61f683fcfd7863344686c.png

    其中 x 是特征向量,W_1 和 W_2 是对应每类的权重,θ_1 和 θ_2 是 x 分别与 W_1 和 W_2 之间的角度。通过在上式中引入一个乘法余量,这两个决策边界可以变得更加严格:

    dfcd870009af94ec23f6d474d091ef6d.png

    如图 8 所示,这个余量可以有效地增大类别之间的区分程度以及各自类别之内的紧凑性。根据将该余量整合进损失的方式,研究者们已经提出了多种可用方法 [116,119-121]。比如 [116] 中对权重向量进行了归一化以具有单位范数,这样使得决策边界仅取决于角度 θ_1 和 θ_2。[119,120] 中则提出了一种加性余弦余量。相比于乘法余量 [135,116],加性余量更容易实现和优化。在这项工作中,除了归一化权重向量,特征向量也如 [115] 中一样进行了归一化和比例调整。[121] 中提出了另一种加性余量,它既有 [119,120] 那样的优点,还有更好的几何解释方式,因为这个余量是加在角度上的,而不是余弦上。表 2 总结了有余量的 softmax 损失的不同变体的决策边界。这些方法是人脸识别领域的当前最佳。

    1e7c6f3c42ad631cd9f5b9a4008fe9e8.png

    图 8:在两个类别之间的决策边界中引入一个余量 m 的效果。(a)softmax 损失,(b)有余量的 softmax 损失。

    9b500ee8a0edc664342c95608d959880.png

    表 2:有余量的 softmax 损失的不同变体的决策边界。注意这些决策边界针对的是二元分类案例中的类别 1。

    小白团队出品:零基础精通语义分割↓

    1ac0b73e4755ffa7a94ecc04f49d2244.png

    下载1:OpenCV-Contrib扩展模块中文版教程

    在「小白学视觉」公众号后台回复:扩展模块中文教程即可下载全网第一份OpenCV扩展模块教程中文版,涵盖扩展模块安装、SFM算法、立体视觉、目标跟踪、生物视觉、超分辨率处理等二十多章内容。

    下载2:Python视觉实战项目52讲

    在「小白学视觉」公众号后台回复:Python视觉实战项目即可下载包括图像分割、口罩检测、车道线检测、车辆计数、添加眼线、车牌识别、字符识别、情绪检测、文本内容提取、面部识别等31个视觉实战项目,助力快速学校计算机视觉。

    下载3:OpenCV实战项目20讲

    在「小白学视觉」公众号后台回复:OpenCV实战项目20讲即可下载含有20个基于OpenCV实现20个实战项目,实现OpenCV学习进阶。

    交流群

    欢迎加入公众号读者群一起和同行交流,目前有SLAM、三维视觉、传感器、自动驾驶、计算摄影、检测、分割、识别、医学影像、GAN、算法竞赛等微信群(以后会逐渐细分),请扫描下面微信号加群,备注:”昵称+学校/公司+研究方向“,例如:”张三 + 上海交大 + 视觉SLAM“。请按照格式备注,否则不予通过。添加成功后会根据研究方向邀请进入相关微信群。请勿在群内发送广告,否则会请出群,谢谢理解~

    0f3488e8e440b8b78505b9512c350344.png

    0cf76b78f6816bff590890a700c96b62.png

    展开全文
  • 有关人脸识别技术论文 摘要人脸识别技术(FaceRecognitionTechnologyFRT)是近年来模式识别图像处理以及计算机视觉等领域的熟点研究课题之一本文重点现有的人脸检测与识别方法及研究进行总结分析和比较各种识别方法...
  • 人脸识别闸机系统 设 计 方 案 word 专业资料 . 一人脸识别技术需求分析 随着社会经济的高速发展居住环境的舒适性和安全性已经成为人们居住首选而门禁系统在安全的居 住环境中起到的重要作用得到越来越多的重视目前...
  • 2.人脸识别中用到了深度学习 3.是个完整的考勤签到系统 用C++调用OpenCV库实现人脸检测、人脸关键点定位、面容特征提取; 用Windows版Caffe建立训练模型,将训练好的模型部署到C++程序 MySQL数据库 利用Visual ...
  • 英国赫特福德大学与 GBG Plc 的研究者近日发布了一篇综述论文,对人脸识别方法进行了全面的梳理和总结,其中涵盖各种传统方法和如今风头正盛的深度学习方法。机器之心重点编译介绍了其中的深度学习方法部分,更多...
    英国赫特福德大学与 GBG Plc 的研究者近日发布了一篇综述论文,对人脸识别方法进行了全面的梳理和总结,其中涵盖各种传统方法和如今风头正盛的深度学习方法。机器之心重点编译介绍了其中的深度学习方法部分,更多有关传统人脸识别方法的内容请参阅原论文。
    8873238977d4d032df0428d3abc2098d.png

    论文地址:https://arxiv.org/abs/1811.00116

    自七十年代以来,人脸识别已经成为了计算机视觉和生物识别领域被研究最多的主题之一。基于人工设计的特征和传统机器学习技术的传统方法近来已被使用非常大型的数据集训练的深度神经网络取代。在这篇论文中,我们对流行的人脸识别方法进行了全面且最新的文献总结,其中既包括传统方法(基于几何的方法、整体方法、基于特征的方法和混合方法),也有深度学习方法。

    引言

    人脸识别是指能够识别或验证图像或视频中的主体的身份的技术。首个人脸识别算法诞生于七十年代初 [1,2]。自那以后,它们的准确度已经大幅提升,现在相比于指纹或虹膜识别 [3] 等传统上被认为更加稳健的生物识别方法,人们往往更偏爱人脸识别。让人脸识别比其它生物识别方法更受欢迎的一大不同之处是人脸识别本质上是非侵入性的。比如,指纹识别需要用户将手指按在传感器上,虹膜识别需要用户与相机靠得很近,语音识别则需要用户大声说话。相对而言,现代人脸识别系统仅需要用户处于相机的视野内(假设他们与相机的距离也合理)。这使得人脸识别成为了对用户最友好的生物识别方法。这也意味着人脸识别的潜在应用范围更广,因为它也可被部署在用户不期望与系统合作的环境中,比如监控系统中。人脸识别的其它常见应用还包括访问控制、欺诈检测、身份认证和社交媒体。

    当被部署在无约束条件的环境中时,由于人脸图像在现实世界中的呈现具有高度的可变性(这类人脸图像通常被称为自然人脸(faces in-the-wild)),所以人脸识别也是最有挑战性的生物识别方法之一。人脸图像可变的地方包括头部姿势、年龄、遮挡、光照条件和人脸表情。图 1 给出了这些情况的示例。

    0a7c230b10b59bfc6db5f824b43ccf9e.png

    图 1:在自然人脸图像中找到的典型变化。(a)头部姿势,(b)年龄,(c)光照,(d)面部表情,(e)遮挡。

    人脸识别技术这些年已经发生了重大的变化。传统方法依赖于人工设计的特征(比如边和纹理描述量)与机器学习技术(比如主成分分析、线性判别分析或支持向量机)的组合。人工设计在无约束环境中对不同变化情况稳健的特征是很困难的,这使得过去的研究者侧重研究针对每种变化类型的专用方法,比如能应对不同年龄的方法 [4,5]、能应对不同姿势的方法 [6]、能应对不同光照条件的方法 [7,8] 等。近段时间,传统的人脸识别方法已经被基于卷积神经网络(CNN)的深度学习方法接替。深度学习方法的主要优势是它们可用非常大型的数据集进行训练,从而学习到表征这些数据的最佳特征。网络上可用的大量自然人脸图像已让研究者可收集到大规模的人脸数据集 [9-15],这些图像包含了真实世界中的各种变化情况。使用这些数据集训练的基于 CNN 的人脸识别方法已经实现了非常高的准确度,因为它们能够学到人脸图像中稳健的特征,从而能够应对在训练过程中使用的人脸图像所呈现出的真实世界变化情况。此外,深度学习方法在计算机视觉方面的不断普及也在加速人脸识别研究的发展,因为 CNN 也正被用于解决许多其它计算机视觉任务,比如目标检测和识别、分割、光学字符识别、面部表情分析、年龄估计等。

    人脸识别系统通常由以下构建模块组成:

    • 人脸检测。人脸检测器用于寻找图像中人脸的位置,如果有人脸,就返回包含每张人脸的边界框的坐标。如图 3a 所示。
    • 人脸对齐。人脸对齐的目标是使用一组位于图像中固定位置的参考点来缩放和裁剪人脸图像。这个过程通常需要使用一个特征点检测器来寻找一组人脸特征点,在简单的 2D 对齐情况中,即为寻找最适合参考点的最佳仿射变换。图 3b 和 3c 展示了两张使用了同一组参考点对齐后的人脸图像。更复杂的 3D 对齐算法(如 [16])还能实现人脸正面化,即将人脸的姿势调整到正面向前。
    • 人脸表征。在人脸表征阶段,人脸图像的像素值会被转换成紧凑且可判别的特征向量,这也被称为模板(template)。理想情况下,同一个主体的所有人脸都应该映射到相似的特征向量。
    • 人脸匹配。在人脸匹配构建模块中,两个模板会进行比较,从而得到一个相似度分数,该分数给出了两者属于同一个主体的可能性。
    87e7616ae4a95ce47f4992868605bfd3.png

    图 2:人脸识别的构建模块。

    很多人认为人脸表征是人脸识别系统中最重要的组件,这也是本论文第二节所关注的重点。

    8c8e81775b203c3313682f7cedae9d77.png

    图 3:(a)人脸检测器找到的边界框。(b)和(c):对齐后的人脸和参考点。

    深度学习方法

    卷积神经网络(CNN)是人脸识别方面最常用的一类深度学习方法。深度学习方法的主要优势是可用大量数据来训练,从而学到对训练数据中出现的变化情况稳健的人脸表征。这种方法不需要设计对不同类型的类内差异(比如光照、姿势、面部表情、年龄等)稳健的特定特征,而是可以从训练数据中学到它们。深度学习方法的主要短板是它们需要使用非常大的数据集来训练,而且这些数据集中需要包含足够的变化,从而可以泛化到未曾见过的样本上。幸运的是,一些包含自然人脸图像的大规模人脸数据集已被公开 [9-15],可被用来训练 CNN 模型。除了学习判别特征,神经网络还可以降维,并可被训练成分类器或使用度量学习方法。CNN 被认为是端到端可训练的系统,无需与任何其它特定方法结合。

    用于人脸识别的 CNN 模型可以使用不同的方法来训练。其中之一是将该问题当作是一个分类问题,训练集中的每个主体都对应一个类别。训练完之后,可以通过去除分类层并将之前层的特征用作人脸表征而将该模型用于识别不存在于训练集中的主体 [99]。在深度学习文献中,这些特征通常被称为瓶颈特征(bottleneck features)。在这第一个训练阶段之后,该模型可以使用其它技术来进一步训练,以为目标应用优化瓶颈特征(比如使用联合贝叶斯 [9] 或使用一个不同的损失函数来微调该 CNN 模型 [10])。另一种学习人脸表征的常用方法是通过优化配对的人脸 [100,101] 或人脸三元组 [102] 之间的距离度量来直接学习瓶颈特征。

    使用神经网络来做人脸识别并不是什么新思想。1997 年就有研究者为人脸检测、眼部定位和人脸识别提出了一种名为「基于概率决策的神经网络(PBDNN)」[103] 的早期方法。这种人脸识别 PDBNN 被分成了每一个训练主体一个全连接子网络,以降低隐藏单元的数量和避免过拟合。研究者使用密度和边特征分别训练了两个 PBDNN,然后将它们的输出组合起来得到最终分类决定。另一种早期方法 [104] 则组合使用了自组织映射(SOM)和卷积神经网络。自组织映射 [105] 是一类以无监督方式训练的神经网络,可将输入数据映射到更低维的空间,同时也能保留输入空间的拓扑性质(即在原始空间中相近的输入在输出空间中也相近)。注意,这两种早期方法都不是以端到端的方式训练的([103] 中使用了边特征,[104] 中使用了 SOM),而且提出的神经网络架构也都很浅。[100] 中提出了一种端到端的人脸识别 CNN。这种方法使用了一种孪生式架构,并使用了一个对比损失函数 [106] 来进行训练。这个对比损失使用了一种度量学习流程,其目标是最小化对应同一主体的特征向量对之间的距离,同时最大化对应不同主体的特征向量对之间的距离。该方法中使用的 CNN 架构也很浅,且训练数据集也较小。

    上面提到的方法都未能取得突破性的成果,主要原因是使用了能力不足的网络,且训练时能用的数据集也相对较小。直到这些模型得到扩展并使用大量数据 [107] 训练后,用于人脸识别的首个深度学习方法 [99,9] 才达到了当前最佳水平。尤其值得一提的是 Facebook 的 DeepFace [99],这是最早的用于人脸识别的 CNN 方法之一,其使用了一个能力很强的模型,在 LFW 基准上实现了 97.35% 的准确度,将之前最佳表现的错误率降低了 27%。研究者使用 softmax 损失和一个包含 440 万张人脸(来自 4030 个主体)的数据集训练了一个 CNN。本论文有两个全新的贡献:(1)一个基于明确的 3D 人脸建模的高效的人脸对齐系统;(2)一个包含局部连接的层的 CNN 架构 [108,109],这些层不同于常规的卷积层,可以从图像中的每个区域学到不同的特征。在那同时,DeepID 系统 [9] 通过在图块(patch)上训练 60 个不同的 CNN 而得到了相近的结果,这些图块包含十个区域、三种比例以及 RGB 或灰度通道。在测试阶段,会从每个图块提取出 160 个瓶颈特征,加上其水平翻转后的情况,可形成一个 19200 维的特征向量(160×2×60)。类似于 [99],新提出的 CNN 架构也使用了局部连接的层。其验证结果是通过在这种由 CNN 提取出的 19200 维特征向量上训练一个联合贝叶斯分类器 [48] 得到的。训练该系统所使用的数据集包含 202599 张人脸图像,来自 10177 位名人 [9]。

    对于基于 CNN 的人脸识别方法,影响准确度的因素主要有三个:训练数据、CNN 架构和损失函数。因为在大多数深度学习应用中,都需要大训练集来防止过拟合。一般而言,为分类任务训练的 CNN 的准确度会随每类的样本数量的增长而提升。这是因为当类内差异更多时,CNN 模型能够学习到更稳健的特征。但是,对于人脸识别,我们感兴趣的是提取出能够泛化到训练集中未曾出现过的主体上的特征。因此,用于人脸识别的数据集还需要包含大量主体,这样模型也能学习到更多类间差异。[110] 研究了数据集中主体的数量对人脸识别准确度的影响。在这项研究中,首先以降序形式按照每个主体的图像数量对一个大数据集进行了排序。然后,研究者通过逐渐增大主体数量而使用训练数据的不同子集训练了一个 CNN。当使用了图像数量最多的 10000 个主体进行训练时,得到的准确度是最高的。增加更多主体会降低准确度,因为每个额外主体可用的图像非常少。另一项研究 [111] 研究了更宽度的数据集更好,还是更深度的数据集更好(如果一个数据集包含更多主体,则认为它更宽;类似地,如果每个主体包含的图像更多,则认为它更深)。这项研究总结到:如果图像数量相等,则更宽的数据集能得到更好的准确度。研究者认为这是因为更宽度的数据集包含更多类间差异,因而能更好地泛化到未曾见过的主体上。表 1 展示了某些最常用于训练人脸识别 CNN 的公开数据集。

    738c7c6abcad045ed593f31a80858b5a.png

    表 1:公开的大规模人脸数据集。

    用于人脸识别的 CNN 架构从那些在 ImageNet 大规模视觉识别挑战赛(ILSVRC)上表现优异的架构上取得了很多灵感。举个例子,[11] 中使用了一个带有 16 层的 VGG 网络 [112] 版本,[10] 中则使用了一个相似但更小的网络。[102] 中探索了两种不同类型的 CNN 架构:VGG 风格的网络 [112] 和 GoogleNet 风格的网络 [113]。即使这两种网络实现了相当的准确度,但 GoogleNet 风格的网络的参数数量少 20 倍。更近段时间,残差网络(ResNet)[114] 已经成为了很多目标识别任务的最受偏爱的选择,其中包括人脸识别 [115-121]。ResNet 的主要创新点是引入了一种使用捷径连接的构建模块来学习残差映射,如图 7 所示。捷径连接的使用能让研究者训练更深度的架构,因为它们有助于跨层的信息流动。[121] 对不同的 CNN 架构进行了全面的研究。在准确度、速度和模型大小之间的最佳权衡是使用带有一个残差模块(类似于 [122] 中提出的那种)的 100 层 ResNet 得到的。

    fb4d39aac7b7342d6147bcb6d4c0f366.png

    图 7:[114] 中提出的原始的残差模块。

    选择用于训练 CNN 方法的损失函数已经成为近来人脸识别最活跃的研究领域。即使使用 softmax 损失训练的 CNN 已经非常成功 [99,9,10,123],但也有研究者认为使用这种损失函数无法很好地泛化到训练集中未出现过的主体上。这是因为 softmax 损失有助于学习能增大类间差异的特征(以便在训练集中区别不同的类),但不一定会降低类内差异。研究者已经提出了一些能缓解这一问题的方法。优化瓶颈特征的一种简单方法是使用判别式子空间方法,比如联合贝叶斯 [48],就像 [9,124,125,126,10,127] 中所做的那样。另一种方法是使用度量学习。比如,[100,101] 中使用了配对的对比损失来作为唯一的监督信号,[124-126] 中还结合使用了分类损失。人脸识别方面最常用的度量学习方法是三元组损失函数 [128],最早在 [102] 中被用于人脸识别任务。三元组损失的目标是以一定余量分开正例对之间的距离和负例对之间的距离。从数学形式上讲,对于每个三元组 i,需要满足以下条件 [102]:

    8c042096cfc65b46007a0c0d3990eacc.png

    其中 x_a 是锚图像,x_p 是同一主体的图像,x_n 是另一个不同主体的图像,f 是模型学习到的映射关系,α 施加在正例对和负例对距离之间的余量。在实践中,使用三元组损失训练的 CNN 的收敛速度比使用 softmax 的慢,这是因为需要大量三元组(或对比损失中的配对)才能覆盖整个训练集。尽管这个问题可以通过在训练阶段选择困难的三元组(即违反余量条件的三元组)来缓解 [102],但常见的做法是在第一个训练阶段使用 softmax 损失训练,在第二个训练阶段使用三元组损失来对瓶颈特征进行调整 [11,129,130]。研究者们已经提出了三元组损失的一些变体。比如 [129] 中使用了点积作为相似度度量,而不是欧几里德距离;[130] 中提出了一种概率式三元组损失;[131,132] 中提出了一种修改版的三元组损失,它也能最小化正例和负例分数分布的标准差。用于学习判别特征的另一种损失函数是 [133] 中提出的中心损失(centre loss)。中心损失的目标是最小化瓶颈特征与它们对应类别的中心之间的距离。通过使用 softmax 损失和中心损失进行联合训练,结果表明 CNN 学习到的特征能够有效增大类间差异(softmax 损失)和降低类内个体差异(中心损失)。相比于对比损失和三元组损失,中心损失的优点是更高效和更容易实现,因为它不需要在训练过程中构建配对或三元组。另一种相关的度量学习方法是 [134] 中提出的范围损失(range loss),这是为改善使用不平衡数据集的训练而提出的。范围损失有两个组件。类内的损失组件是最小化同一类样本之间的 k-最大距离,而类间的损失组件是最大化每个训练批中最近的两个类中心之间的距离。通过使用这些极端案例,范围损失为每个类都使用同样的信息,而不管每个类别中有多少样本可用。类似于中心损失,范围损失需要与 softmax 损失结合起来以避免损失降至零 [133]。

    当结合不同的损失函数时,会出现一个困难,即寻找每一项之间的正确平衡。最近一段时间,已有研究者提出了几种修改 softmax 损失的方法,这样它无需与其它损失结合也能学习判别特征。一种已被证明可以增加瓶颈特征的判别能力的方法是特征归一化 [115,118]。比如,[115] 提出归一化特征以具有单位 L2 范数,[118] 提出归一化特征以具有零均值和单位方差。一个成功的方法已经在 softmax 损失中每类之间的决策边界中引入了一个余量 [135]。为了简单,我们介绍一下使用 softmax 损失进行二元分类的情况。在这种情况下,每类之间的决策边界(如果偏置为零)可由下式给定:

    e36b2096314694c6acc3b375e093d7ef.png

    其中 x 是特征向量,W_1 和 W_2 是对应每类的权重,θ_1 和 θ_2 是 x 分别与 W_1 和 W_2 之间的角度。通过在上式中引入一个乘法余量,这两个决策边界可以变得更加严格:

    7ebe97a83c70145a52fccd22ec6957cc.png

    如图 8 所示,这个余量可以有效地增大类别之间的区分程度以及各自类别之内的紧凑性。根据将该余量整合进损失的方式,研究者们已经提出了多种可用方法 [116,119-121]。比如 [116] 中对权重向量进行了归一化以具有单位范数,这样使得决策边界仅取决于角度 θ_1 和 θ_2。[119,120] 中则提出了一种加性余弦余量。相比于乘法余量 [135,116],加性余量更容易实现和优化。在这项工作中,除了归一化权重向量,特征向量也如 [115] 中一样进行了归一化和比例调整。[121] 中提出了另一种加性余量,它既有 [119,120] 那样的优点,还有更好的几何解释方式,因为这个余量是加在角度上的,而不是余弦上。表 2 总结了有余量的 softmax 损失的不同变体的决策边界。这些方法是人脸识别领域的当前最佳。

    a68b9ff46368d1ba346af387e973f9df.png

    图 8:在两个类别之间的决策边界中引入一个余量 m 的效果。(a)softmax 损失,(b)有余量的 softmax 损失。

    7928b008c62f209feb8e176847d46f64.png

    表 2:有余量的 softmax 损失的不同变体的决策边界。注意这些决策边界针对的是二元分类案例中的类别 1。

    展开全文
  • 人脸识别专题报告

    2021-03-20 23:21:39
    我们把人脸识别总结为两种应用模式和四步流程。两种应用模式包括1:1 比对和1:N 识别:人脸验证技术(1:1 比对)。1:1 的定义是一个判断的作用,使用人脸识别技术计算出拍摄对象与数据库中两个人脸的相似度,...
  • 完成人脸识别所需的步骤: 注册百度账号api,创建自己的应用; 创建vs控制台应用程序,引入动态链接库; 编写代码调试,效果图查看; 总结。 1、注册百度账号api,创建自己的应用 注册地址: ...
  • 基于CNN的人脸识别方法,包含全部代码和操作流程,包含人脸识别示例及总结
  • 自己整理的人脸识别的几篇经典文章,特别是gabor|小波和eigenface的两篇文章,写的非常好。
  • python + opencv实现人脸识别项目总结

    千次阅读 2021-10-22 00:04:22
    通过python+opencv实现摄像头输入的图像实时人脸识别,或者输入的图片进行人脸识别 2、解决思路 本项目主要有两个模块:数据训练和人脸识别 1.1 数据训练 数据训练模块的思路如下: (1)定义...

    1、提出问题

    通过python+opencv实现对摄像头输入的图像实时人脸识别,或者对输入的图片进行人脸识别

    2、解决思路

    本项目主要有两个模块:数据训练和人脸识别

    1.1 数据训练

    数据训练模块的思路如下:

    (1)定义getImageAndLabels()用来返回训练图像的脸部数据和图像文件名中的顺序数据:

    faces和ids

    (2)创建、加载识别器recognizer

    (3)对faces和np.array(ids)进行训练:recognizer.train(faces, np.array(ids))

    (4)训练好的数据存储在trainer.yml下,便于人脸识别模块调用

    1.2 人脸识别

    人脸识别模块的思路如下:

    (1)加载数据训练模块的训练数据

    (2)加载opencv提供的人脸分类器

    (3)定义face_detect_demo()方法获取需要识别的图片上的人脸并在脸部绘制方框,把方框内部的人脸数据与trainer.yml中的数据对比,返回trainer.yml文件中相似图片数据的idconfidence

    (4)定义name()方法获取训练图片的人名,以便于对识别出的图片中的人脸做标记

    (5)将摄像头捕捉的图像抽帧传入face_detect_demo()实时识别并在图片上显示结果

    3、代码

    3.1 数据训练模块代码

    import os
    import cv2 as cv
    import numpy as np
    from PIL import Image
    
    def getImageAndLabels(path):
        #储存人脸信息
        facesSamples = []
        #储存序号数据
        ids = []
        #储存姓名信息
        names = []
        #储存图片信息
        imagePaths = []
        # 得到文件名中的人名
    
        # listdir列出文件夹下的文件
        for file in os.listdir(path):
    
            if file.endswith('jpg'):
                        # 路径拼接,imagePath是图片的绝对路径
                        imagePath = os.path.join(path, file)
                        # 将图片路径添加到列表中
                        imagePaths.append(imagePath)
    
    
    
    
    
        #加载分类器
        face_detector = cv.CascadeClassifier('D:/Software/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml')
    
        #id从0开始
        id = 1
        #遍历imagePaths中存储的绝对路径对应的图片
        for imagePath in imagePaths:
            #打开图片,灰度化PIL有九种不同模式,其中1为黑白,L为灰度
            PIL_img = Image.open(imagePath).convert('L')
            #将图像转换成数组,以黑白深浅
            img_numpy = np.array(PIL_img,'uint8')
            #获取图片人脸特征
            faces = face_detector.detectMultiScale(image=img_numpy,scaleFactor=1.01,minNeighbors=5,minSize=(180,180),maxSize=(300,300))
            # 得到图片绝对路径列表中的人名,存储在names列表
    
            name = (os.path.split(imagePath)[1].split('-')[1]).split('.')[0]
    
    
    
            #预防无面容照片
            for x,y,w,h in faces:
                names.append(name)
                ids.append(id)
                facesSamples.append(img_numpy[y:y+h,x:x+w])
                #打印脸部特征和id
                print('id:',id)
                print('name:',name)
                print('fs',img_numpy[y:y+h,x:x+w])
                # id自增1
                id += 1
    
        print(ids)
        print(names)
        return facesSamples,ids
    if __name__ == '__main__':
        #图片的路径
        path = 'D:/SoftwareCache/PyCharmCache/Project_Face/trainer/faces'
        #获取图像数组和id标签数组和姓名
        faces,ids = getImageAndLabels(path)
        #加载识别器
        recognizer = cv.face.LBPHFaceRecognizer_create()
        #训练
        recognizer.train(faces, np.array(ids))
    
        print(ids)
        #保存文件
        recognizer.write('./trainer.yml')

    3.2 人脸识别模块代码

    import cv2 as cv
    import os
    import numpy as np
    from PIL import Image
    import urllib
    import urllib.request
    
    #加载训练数据集文件
    recognizer = cv.face.LBPHFaceRecognizer_create()
    #加载数据
    recognizer.read('./trainer.yml')
    #名字
    names = []
    #警报全局变量
    warningtime = 0
    
    face_detector = cv.CascadeClassifier('D:/Software/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml')
    
    #准备识别的图像
    def face_detect_demo(img):
        gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)#转换为灰度
        #加载官方人脸识别器
        face_detector = cv.CascadeClassifier('D:/Software/opencv/opencv/sources/data/haarcascades/haarcascade_frontalface_alt2.xml')
        #在gray图上找出人脸
        face = face_detector.detectMultiScale(gray,1.01,5,cv.CASCADE_SCALE_IMAGE,(180,180),(300,300))
    
        for x,y,w,h in face:
            #在img上面绘制脸部方框
            cv.rectangle(img,(x,y),(x+w,y+h),color=(0,0,255),thickness=1)
            #img上绘制脸部圆圈
            cv.circle(img,center=(x+w//2,y+h//2),radius=w//2,color=(0,255,0),thickness=1)
            #人脸识别
    
            ids,confidence = recognizer.predict(gray[y:y+h,x:x+w])
            print(ids)
            print('confidence:',confidence)
            print('name:',names[ids-1])
    
    
            if confidence > 120:
                #gloal声明一个全局变量
                global warningtime
                warningtime += 1
    
                if warningtime > 100:
                    #不是存储在数据库中的人脸,图片上打印:unknown
            #
            #
                    cv.putText(img,'unknown',(x,y+15),cv.FONT_HERSHEY_SIMPLEX,0.75,(0,255,0),1)
    
            else:
                cv.putText(img,str(names[ids-1]),(x,y+15),cv.FONT_HERSHEY_SIMPLEX,0.75,(0,255,0),1)
    
        cv.imshow('result',img)
    def name():
        imagePaths = []
        path = './faces'
    
        for file in os.listdir(path):
    
            if file.endswith('jpg'):
                # 路径拼接,imagePath是图片的绝对路径
                imagePath = os.path.join(path, file)
                # 将图片路径添加到列表中
                imagePaths.append(imagePath)
        #得到图片文件名中的名字
        for imagePath in imagePaths:
            # 打开图片,灰度化PIL有九种不同模式,其中1为黑白,L为灰度
            PIL_img = Image.open(imagePath).convert('L')
            # 将图像转换成数组,以黑白深浅
            img_numpy = np.array(PIL_img, 'uint8')
            # 获取图片人脸特征
            faces = face_detector.detectMultiScale(image=img_numpy, scaleFactor=1.01, minNeighbors=5, minSize=(180, 180),
                                                   maxSize=(300, 300))
            # 得到图片绝对路径列表中的人名,存储在names列表
    
            name = (os.path.split(imagePath)[1].split('-')[1]).split('.')[0]
    
            # 预防无面容照片
            for x, y, w, h in faces:
                names.append(name)
    
                # 打印脸部特征和id
                print('id:', id)
                print('name:', name)
                print('fs', img_numpy[y:y + h, x:x + w])
        print(names)
    cap = cv.VideoCapture(0)
    name()
    
    
    
    
    # #以图片做实验
    # #D:\SoftwareCache\PyCharmCache\Project_Face\trainer\FERET_80_80\FERET_80_80-人脸数据库\FERET-001-Lesley
    #
    # frame = cv.imread('./face8.jpg')
    # face_detect_demo(frame)
    #
    # while True:
    #     if ord('q') == cv.waitKey(0):
    #         break
    #
    # cv.destroyAllWindows()
    
    
    #以摄像头捕捉图像做实验
    while True:
        flag,frame = cap.read()
        if not flag:
            break
        face_detect_demo(frame)
    
        if ord(' ') == cv.waitKey(10):
            break
    
    cv.destroyAllWindows()
    cap.release()
    
    
    

    4、结果如下

     5、声明

    此篇博客为笔者学习B站python+opencv人脸识别项目后自己的一点总结,侵权请联系笔者删除。

    B站视频链接:一天搞定人脸识别项目!学不会up直接下跪!(python+opencv)_哔哩哔哩_bilibiliicon-default.png?t=L9C2https://www.bilibili.com/video/BV1Lq4y1Z7dm?spm_id_from=333.999.0.0

    展开全文
  • 人脸识别学习总结

    万次阅读 多人点赞 2019-05-03 13:02:48
    对人脸识别算法进行了一定程度的学习,从最开始的特征脸到如今的CNN人脸检测,有了较为全面的了解。重点掌握了基于PCA的特征脸检测,LDA线性判别分析(Fisher线性判别),以及基于级联器的Haar特征,LBP特征的人脸...
  • 简单的人脸识别项目 附上我的思维导图 附上我的项目路径 其中我的lfw-a的图片库是在网上下载的 下载网站http://vis-www.cs.umass.edu/lfw/ 下面的这个就是界面 人脸识别数据库进行扫描,让后加载到模型中去,到...
  • 树莓派 人脸识别——从小白到大白 @。@初探树莓派系统拷入一些问题人脸识别yolov3结果 初探树莓派 这是大鱼的第一篇博客,唉唉,客官留步!!!! 系统拷入 一些问题 人脸识别 作为一个小白,我带着我炽热的心,滚过...
  • 百度、腾讯、阿里、Face++、商汤等人脸识别 Face++人脸识别介绍 商汤人脸识别介绍 以上均采用设备数或QPS数付费授权 虹软人脸识别 介绍地址:https://ai.arcsoft.com.cn/product/arcface.html 技术文档地址:...
  • 并按照AFR发展特点,将AFR研究划分为三个历史阶段,每个阶段研究的特点以及代表性方法进行了较为详尽的总结,并从面部特征自动定位、人脸表示模型、分类和识别算法三个角度对人脸识别领域的主要方法进行了分类整理...
  • 人脸识别案例

    2017-11-20 21:16:20
    人脸识别!个人的一些总结,有很多地方不足,大家多多指教!
  • 3.对人脸进行拍照,描绘到canvas画布上面 4.将照片转换成base64格式 5.调用后台接口,后台调用人脸比对接口进行比对。 人脸检测及相关文章 tracking.js 库将不同的计算机视觉算法和技术引入浏览器环境。通过使用现代...
  • 人脸识别毕设论文

    2018-01-15 12:51:06
    该毕设论文是本人学习研究人脸识别总结,里面详细介绍了实现人脸识别的各个步骤的原理及实现过程,可以说非常的详细了。里面有论述不当之处还请指正。
  • 人脸识别文档

    2018-02-02 15:00:59
    人脸识别文档,有助于集成web项目的人脸识别文档,自己看视频总结
  • 人脸识别实验报告.doc

    千次阅读 2020-11-27 17:23:16
    您所在位置:网站首页 > 海量文档 > 计算机 > 图形图像人脸识别实验报告.doc3页本文档一共被下载:次,您可全文免费在线阅读后下载本文档。 下载提示1.本站不保证该用户上传的文档完整性,不预览、...
  • 第四,通过遗忘人脸识别领域论文的挖掘,我们总结人脸识别领域的研究热点;最后,我们介绍了与人脸识别相关的国际著名会议,以帮助读者更好获取人脸识别热点渠道。 2.人脸识别技术原理 研究首先介绍了人脸识别...
  • 一 行业分析 1 行业定义 中软高科属于人脸识别行业人脸识别是基于人的脸部特征信息进行身份识别的一种 生物识别技术用摄像机或摄像头采集含有人脸的图像或视频流并自动在图像中检测 和跟踪人脸进而检测到的人脸...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 27,255
精华内容 10,902
关键字:

对人脸识别的总结