基于虹软人脸识别技术,实现新生实时身份认证和报到统计

由于工作业务需要,笔者开发了一套新生入学身份核验系统,用于在新生入学时实时核验其身份(教育部要求新生入学时要进行人脸比对),同时实时统计新生的报到情况。核验流程如下:学生持身份证报到,通过身份证读卡器读取身份证信息(包含姓名、身份证号和芯片中的照片),根据身份证号获取学生的录取信息(学院、班级、学号及录取库中照片等),确定是录取库中新生后通过摄像头采集其现场照片,然后比对身份证照片、录取库照片和采集的现场照片,三者一致即可完成新生的身份认证,最终可导出数据结果文件和存档的照片文件。为降低使用门槛,系统采用C/S结构,服务器为asp.net core webapi,无需配置即可使用,客户端采用WPF开发。在人脸比对算法包选择时,笔者考察了主几个要厂家的sdk,在综合考虑易用性、文档质量及demo质量后,最终选择了虹软公司的产品。客户端运行界面如下:

客户端运行界面

在该项目开发过程中,有几点体会想和大家分享一下:
1. B/S、C/S结构的选择
由于客户端需要连接身份证读卡器及摄像头(对采集照片质量要求高的可采用单反相机,目前程序支持连接佳能相机),采用B/S结构需要单独开发websocket连接硬件,以及考虑到B/S服务器部署和运维的成本,本项目最终选择了C/S结构进行开发。服务器采用asp.net core self-host webapi,直接运行程序即可启动,服务器启动后界面如下:

服务器运行界面

2. 人脸比对算法的选择
由于是应用开发,也是初次接触人脸比对应用,笔者考察了百度、阿里、虹软等几家的sdk库,最后考虑到识别效率、文档质量、demo质量(主要是有免费版可以快速学习)及性价比后,最终选择虹软sdk进行开发。关于人脸比对在服务器端进行还是在客户端进行,最初也进行了抉择。在服务器端进行比对的优势是不需要对客户端进行sdk授权(节省成本),缺点是对服务器要求比较高,需要两次请求才能得到比对结果;在客户端进行比对的优势是获取到学生信息后即可进行比对获得结果,缺点是成本增加(每个客户端都需要独立授权)。考虑到本项目的实际情况,最终人脸比对在客户端进行,从而减少服务器的压力(服务器只作提供webapi服务,普通笔记本就可以胜任),客户端的激活成本在可以接收的范围。
人脸识别引擎初始化代码如下:

        private void InitEngines()
        {
            //读取配置文件
            AppSettingsReader reader = new AppSettingsReader();
            string appId = (string)reader.GetValue("APPID", typeof(string));
            string sdkKey64 = (string)reader.GetValue("SDKKEY64", typeof(string));
            string sdkKey32 = (string)reader.GetValue("SDKKEY32", typeof(string));
            string activeKey64 = (string)reader.GetValue("ACTIVEKEY64", typeof(string));
            string activeKey32 = (string)reader.GetValue("ACTIVEKEY32", typeof(string));          
            //判断CPU位数
            var is64CPU = Environment.Is64BitProcess;
            string appId = is64CPU ? appId64 : appId32;
            if (string.IsNullOrWhiteSpace(appId) || string.IsNullOrWhiteSpace(is64CPU ? sdkKey64 : sdkKey32) || string.IsNullOrWhiteSpace(is64CPU ? activeKey64 : activeKey32))
            {             
                System.Windows.MessageBox.Show(string.Format("请先配置APP_ID和SDKKEY{0}!", is64CPU ? "64" : "32"));
                return;
            }
            //在线激活引擎    如出现错误,1.请先确认从官网下载的sdk库已放到对应的bin中,2.当前选择的CPU为x86或者x64
            int retCode = 0;
            try
            {
                retCode = imageLiveEngine.ASFOnlineActivation(appId, is64CPU ? sdkKey64 : sdkKey32,  is64CPU ? activeKey64: activeKey32);
                if (retCode != 0 && retCode != 90114)
                {
                    System.Windows.MessageBox.Show("激活SDK失败,错误码:" + retCode);
                    return;
                }
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("无法加载 DLL"))
                {
                    System.Windows.MessageBox.Show("请将SDK相关DLL放入bin对应的x86或x64下的文件夹中!");
                }
                else
                {
                    MessageBox.Show("激活SDK失败,请先检查依赖环境及SDK的平台、版本是否正确! \r\n"+ex.Message);
                }
                System.Environment.Exit(0);
            }
            //初始化引擎
            DetectionMode detectMode = DetectionMode.ASF_DETECT_MODE_IMAGE;
            //Video模式下检测脸部的角度优先值
            ASF_OrientPriority videoDetectFaceOrientPriority = ASF_OrientPriority.ASF_OP_ALL_OUT;
            //Image模式下检测脸部的角度优先值
            ASF_OrientPriority imageDetectFaceOrientPriority = ASF_OrientPriority.ASF_OP_ALL_OUT;
            //人脸在图片中所占比例,如果需要调整检测人脸尺寸请修改此值,有效数值为2-32
            int detectFaceScaleVal = 16;
            //最大需要检测的人脸个数
            int detectFaceMaxNum = 5;
            //引擎初始化时需要初始化的检测功能组合
            int combinedMask = FaceEngineMask.ASF_FACE_DETECT | FaceEngineMask.ASF_FACERECOGNITION | FaceEngineMask.ASF_AGE | FaceEngineMask.ASF_GENDER | FaceEngineMask.ASF_FACE3DANGLE | FaceEngineMask.ASF_IMAGEQUALITY;
            //初始化引擎,正常值为0,其他返回值请参考http://ai.arcsoft.com.cn/bbs/forum.php?mod=viewthread&tid=19&_dsign=dbad527e
            retCode = imageLiveEngine.ASFInitEngine(detectMode, imageDetectFaceOrientPriority, detectFaceScaleVal, detectFaceMaxNum, combinedMask);
            txtLogAppend("InitEngine Result:" + retCode);
            txtLogAppend((retCode == 0) ? "引擎初始化成功!" : string.Format("引擎初始化失败!错误码为:{0}", retCode));
            if (retCode != 0)
            {
                return;
            }
            isFaceSDKEnabled = true;           
        }

本项目涉及到3张照片,用户可自定义选择需要比对的照片(至少2张,最多3张),首先获取3张照片的特征值,再进行两两比对,代码如下:

    isPassed = true;
    if (currentExam.IsCompareWithIDCardImage)//采集照片和身份证照片比对
    {
        similarity = 0f;
        //调用对比函数
        if (imageLiveFeature.Feature != null && imageICFeature.Feature != null)
            ret = imageLiveEngine.ASFFaceFeatureCompare(imageLiveFeature.Feature, imageICFeature.Feature, out similarity, ASF_CompareModel.ASF_ID_PHOTO);
      if (similarity.ToString().IndexOf("E") > -1)
          similarity = 0f;
      if (similarity * 100 < threashHold)
          isPassed = false;
    }
    if (currentExam.IsCompareWithRegImage)//采集照片和录取库照片比对
    {
        similarity = 0f;
        if (imageLiveFeature.Feature != null && imageStudentFeature.Feature != null)
            ret = imageLiveEngine.ASFFaceFeatureCompare(imageLiveFeature.Feature, imageStudentFeature.Feature, out similarity, ASF_CompareModel.ASF_ID_PHOTO); 
        if (similarity.ToString().IndexOf("E") > -1)
        {
            similarity = 0f;
        }
        if (similarity * 100 < threashHold)
            isPassed = false;
    }
    if (currentExam.IsCompareRegWithIDCardImage)//录取库照片和身份证照片比对
    {
        similarity = 0f;
        if (imageICFeature.Feature != null && imageStudentFeature.Feature != null)
        ret = imageLiveEngine.ASFFaceFeatureCompare(imageICFeature.Feature, imageStudentFeature.Feature, out similarity, ASF_CompareModel.ASF_ID_PHOTO);   
        if (similarity.ToString().IndexOf("E") > -1)
        {
            similarity = 0f;
        }
        if (similarity * 100 < threashHold)
            isPassed = false;
    }

人脸比对可选择照片模式,其中ASF_CompareModel.ASF_ID_PHOTO是证件照或生活照和证件照的比对模式。

3. 数据库选择及查询优化
基于部署成本及项目本身对数据库及并发要求不高的考虑,数据库采用SQLite,基于CodeFirst开发,数据库结构会自动生成。每年的数据保存在单独的数据库中,要实现数据库切换,可以修改数据库连接字符串,或者将已有数据库重命名,操作起来还是比较麻烦,本项目中实现了在管理端可设置当前使用的数据库及新建数据库,从而方便切换数据库进行查询。

数据库切换及新增

数据库切换的代码如下:

        /// <summary>
        /// 更新数据库连接,实现切换数据库SQLite。
        /// </summary>
        public static void SqliteSelect(string strDatabaseName)
        {
            if (ConnectionPool.ContainsKey("Sqlite"))
                ConnectionPool.Remove("Sqlite");
            string conn = getConnectionString("Sqlite");
            conn = conn.Replace("Database.db", strDatabaseName);
            var freesql = new FreeSql.FreeSqlBuilder()
               .UseConnectionString(EnumHelper.StringConvertToEnum<DataType>("Sqlite"), conn)
               .UseAutoSyncStructure(true)
              .UseLazyLoading(false)
              .Build();
            freesql.Aop.ConfigEntityProperty += Aop_ConfigEntityProperty;
            ConnectionPool.Add("Sqlite", freesql);
        }

项目使用了国产的数据库ORM框架FreeSql,数据库使用了一个连接池,支持多种类型数据库连接。本项目只使用了SQLite,根据选择的文件名可以实时切换数据库。

在查询统计信息时,由于需要分学院、专业、班级来进行统计,当班级数量较多时,一次查询就非常耗时。由于专业、班级等分类数据没有做导航表,如有100个班级,要分别查询每个班级已报道男生人数、女生人数、班级总男生人数、总女生人数,就需要进行400次数据库查询,这个是不可接收的(当时开发阶段用的测试数据不够多,没有觉得这个地方有问题,项目上线前一天导入实际录取数据后才发现问题严重,干了一个通宵才把问题解决)。


统计信息查询(浏览器直接访问webapi,返回一个页面)

作为一个解决办法,笔者给出的方案是一次查询出所有的学生数据,然后在内存中进行LING查询统计各项数据。
以上是笔者采用虹软人脸算法开发新生报到身份认证系统中的一些体会,不当之处请各位批评指正。

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

推荐阅读更多精彩内容