.NET 基于虹软人脸识别,实现身份认证和自助发卡

前言

去年下半年开始从BS开发转战CS开发了,相继做了一些大大小小的项目。最近在做的一个人脸识别挺有意思,作为一个初学者我也是摸着石头过河。

这个项目主要是通过摄像头捕获的人脸特征与身份证信息中的人脸照片进行比对,比对通过的话,可以通过发卡机写入信息至卡片并吐出这张卡片,用户拿着这张卡片进行后续操作。.

对于发卡机只需要把一些操作方法进行封装,通过串口发送命令就可以了,身份证信息可以通过读卡器进行获取,这里主要聊一聊进行人脸识别的业务集成,希望对你有所帮助。

开始使用

基本流程如下图,用户在自助发卡机前选择发卡操作,这时自助机会打开摄像头,只需要把身份证放到身份证读卡器上即可,然后摄像头捕获到的人脸与身份证上的人脸进行相似度比对,如果比对通过则由发卡机写入信息并进行发卡操作。

.NET 基于虹软人脸识别,实现身份认证和自助发卡

我这里使用的是虹软视觉开发平台的SDK,首先注册开发者,然后新建应用,你会得到全新的APP_ID和SDK_KEY。每个SDK(免费版的)可以激活100个设备也就是100个电脑,而且有效期是一年,一年之后需要给程序更换新的SDK。

.NET 基于虹软人脸识别,实现身份认证和自助发卡

然后我们拿到对应的APP_ID以及SDK_KEY之后,就可以下载开发包了,我这里选择V3.0版本的SDK,然后配置到程序中。

.NET 基于虹软人脸识别,实现身份认证和自助发卡

大致的界面是这个样子,很普通,左侧是视频,右边是身份证照片以及一些状态

.NET 基于虹软人脸识别,实现身份认证和自助发卡

开发时用到了三个引擎,

第一个是图片模式下的人脸检测引擎

#region 图片引擎pImageEngine初始化
//初始化引擎
uint detectMode = DetectionMode.ASF_DETECT_MODE_IMAGE;
//检测脸部的角度优先值
int detectFaceOrientPriority = ASF_OrientPriority.ASF_OP_0_HIGHER_EXT;
//人脸在图片中所占比例,如果需要调整检测人脸尺寸请修改此值,有效数值为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;
//初始化引擎,正常值为0,其他返回值请参考http://ai.arcsoft.com.cn/bbs/forum.php?mod=viewthread&tid=19&_dsign=dbad527e
retCode = ASFFunctions.ASFInitEngine(detectMode, detectFaceOrientPriority, detectFaceScaleVal, detectFaceMaxNum, combinedMask, ref pImageEngine);
if (retCode == 0)
{
    lbl_msg.Text=("图片引擎初始化成功!\n");
}
else
{
    lbl_msg.Text = (string.Format("图片引擎初始化失败!错误码为:{0}\n", retCode));
}
#endregion

第二个是视频模式下的人脸检测引擎

#region 初始化视频模式下人脸检测引擎
uint detectModeVideo = DetectionMode.ASF_DETECT_MODE_VIDEO;
int combinedMaskVideo = FaceEngineMask.ASF_FACE_DETECT | FaceEngineMask.ASF_FACERECOGNITION;
retCode = ASFFunctions.ASFInitEngine(detectModeVideo, detectFaceOrientPriority, detectFaceScaleVal, detectFaceMaxNum, combinedMaskVideo, ref pVideoEngine);
if (retCode == 0)
{
    lbl_msg.Text=("视频引擎初始化成功!\n");
}
else
{
    lbl_msg.Text = (string.Format("视频引擎初始化失败!错误码为:{0}\n", retCode));
}
#endregion

第三个是视频专用FR引擎,进行活体检测

#region 视频专用FR引擎
detectFaceMaxNum = 1;
combinedMask = FaceEngineMask.ASF_FACERECOGNITION | FaceEngineMask.ASF_FACE3DANGLE | FaceEngineMask.ASF_LIVENESS;
retCode = ASFFunctions.ASFInitEngine(detectMode, detectFaceOrientPriority, detectFaceScaleVal, detectFaceMaxNum, combinedMask, ref pVideoImageEngine);
Console.WriteLine("InitVideoEngine Result:" + retCode);

if (retCode == 0)
{
    lbl_msg.Text = ("视频专用FR引擎初始化成功!\n");
}
else
{
    lbl_msg.Text = (string.Format("视频专用FR引擎初始化失败!错误码为:{0}\n", retCode));
}
// 摄像头初始化
filterInfoCollection = new FilterInfoCollection(FilterCategory.VideoInputDevice);
lbl_msg.Text = (string.Format("摄像头初始化完成...\n"));
#endregion

视频处理这里使用的是AForge.Video 视频处理类库,然后我们在电脑上接上USB摄像头,通过此类库就可以调用摄像头的开关了,那具体的人脸识别我们肯定要放在视频流渲染事件上了。

我们首先将身份证放在身份证阅读器上,获取到身份信息,并把身份信息中的人脸照片拿出来,这时我们要用到pImageEngine图片引擎去从证件照中提取人脸特征值。然后我在能够读到身份证信息 和 视频信息都OK的情况下再去获取当前摄像头下的图片,

//得到当前摄像头下的图片
Bitmap bitmap = videoSource.GetCurrentVideoFrame();
//传入比对函数中进行比对
CompareImgWithIDImg(bitmap, e);

我们这个时候是获取的视频中的图片,需要用到视频引擎pVideoEngine去从bitmap中检测人脸并获取最大的那张脸,并提取人脸特征值。获取到视频中和照片中两张人脸的特征值了,那接下来就是将两张照片交给虹软人脸比对算法获取相似度,我们可以设置一个阈值,超过90%我们就可以认定是同一个人,这个还是要在实际项目中去做权衡。

.NET 基于虹软人脸识别,实现身份认证和自助发卡

这样我们就算是比对成功,可以进行后续业务了。但是还没完,我刷完身份证后,迅速用身份证对着摄像头,发现竟然也比对成功了,那如果这样的话,即使不是本人,别人从手机里面拿着照片就可以进行认证了,必然造成不安全性,于是我就把活体检测加上了,活体检测,顾名思义,就是看看是不是个大活人而非照片。

int retCode_Liveness = -1;
//RGB活体检测
ASF_LivenessInfo liveInfo = FaceUtil.LivenessInfo_RGB(pVideoImageEngine, imageInfo, multiFaceInfo, out retCode_Liveness);
//判断检测结果
if (retCode_Liveness == 0 && liveInfo.num > 0)
{
    int isLive = MemoryUtil.PtrToStructure<int>(liveInfo.isLive);
    isLiveness = (isLive == 1) ? true : false;
}
if (isLiveness)//活体检测成功

加上活体检测,即使是照片,就算相似度达到90%以上,我们也不会放过。

.NET 基于虹软人脸识别,实现身份认证和自助发卡

到这里基本功能都已经结束了,但是在多次的调试中发现,时不时就会来一次闪退,就是内存溢出。因为我的这个页面是单独弹出来的,这是一个子页面,之前关闭窗口的时候没有把引擎释放,所以导致每次初始化一个引擎大概需要50M左右的内存,迟早会出现内存溢出的情况。于是我就在这个子窗口关闭的时候,对这三个引擎进行释放,这个问题就最终解决了。

/// <summary>
/// 窗体关闭事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void IdentityVerify_FormClosed(object sender, FormClosedEventArgs e)
{
    //销毁引擎
    int retCode = ASFFunctions.ASFUninitEngine(pImageEngine);
    Console.WriteLine("UninitEngine pImageEngine Result:" + retCode);
    //销毁引擎
    retCode = ASFFunctions.ASFUninitEngine(pVideoEngine);
    Console.WriteLine("UninitEngine pVideoEngine Result:" + retCode);
    //销毁引擎
    retCode = ASFFunctions.ASFUninitEngine(pVideoImageEngine);
    Console.WriteLine("UninitEngine pVideoImageEngine Result:" + retCode);
    if (videoSource.IsRunning)
    {
        videoSource.SignalToStop(); //关闭摄像头
    }
    idCardHelper.CloseService();
    this.Dispose();
    this.Close();
    MemoryUtil.ClearMemory();
}

GitHub已开源:https://github.com/yumaster/ReceiveCardAIO