Реализуйте аутентификацию личности и выдачу карт самообслуживания на основе распознавания лиц Arcsoft.

WebSocket

Во второй половине прошлого года я переключился с разработки BS на разработку CS, и я сделал несколько больших и малых проектов один за другим. Распознавание лица, которое я делаю в последнее время, довольно интересно.Как новичок, я также пересекаю реку, ощупывая камни. Этот проект в основном использует камеру для получения видеокадра, а затем использует SDK для извлечения функций видеокадра и фотографии удостоверения личности и использует функции для сравнения. Возьмите эту карту для последующих действий. Для машины, выпускающей карты, вам нужно только инкапсулировать некоторые методы работы и отправлять команды через последовательный порт.Информацию об удостоверении личности можно получить через устройство чтения карт.Здесь мы в основном говорим о бизнес-интеграции распознавания лиц, я надеюсь, что это будет помочь тебе. .

1. Блок-схема

Основной процесс показан на рисунке ниже. Пользователь выбирает операцию выдачи карты перед устройством для выдачи карт самообслуживания. В это время устройство самообслуживания включает камеру, и ему нужно только ввести удостоверение личности. карту на считывателе удостоверений личности, а затем лицо, захваченное камерой, и удостоверение личности. Лицо сравнивается на предмет сходства, и, если сравнение пройдено, устройство для выдачи карт записывает информацию и выполняет операцию выдачи карты.在这里插入图片描述2. Применить и настроить КЛЮЧ

Я использую SDK платформы разработки Arcsoft Vision здесь. Сначала зарегистрируйте разработчика, а затем создайте новое приложение. Вы получите новый APP_ID и SDK_KEY. Лично аутентифицированные пользователи имеют в общей сложности 100 устройств, которые можно активировать бесплатно каждый год, а срок действия составляет один год.По истечении одного года программу необходимо заменить на новый SDK. ​在这里插入图片描述Затем, после того, как мы получим соответствующий APP_ID и SDK_KEY, мы можем загрузить комплект для разработки.Здесь я выбираю версию V3.0 SDK, а затем настраиваю ее в программе.在这里插入图片描述3. Дизайн интерфейса

Общий интерфейс такой, очень распространенный, левая сторона - это видео, правая сторона - фотография на удостоверение личности и некоторый статус.在这里插入图片描述В-четвертых, инициализируйте двигатель

При разработке использовались три двигателя,

Во-первых, это механизм распознавания лиц в режиме изображения.

#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, чтобы извлечь значение функции лица из идентификационной фотографии. . Затем я могу получить изображение под текущей камерой, когда я могу прочитать информацию удостоверения личности и видеоинформация в порядке, ​

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

Пять, сравнение лица

/// <summary>
/// 比对函数,将每一帧抓拍的照片和身份证照片进行比对
/// </summary>
/// <param name="bitmap"></param>
/// <param name="e"></param>
/// <returns></returns>
private bool CompareImgWithIDImg(Bitmap bitmap, PaintEventArgs e)
{
    recTimes--;
    if (bitmap == null)
    {
        return false;
    }
    Graphics g = e.Graphics;
    float offsetX = videoSource.Width * 1f / bitmap.Width;
    float offsetY = videoSource.Height * 1f / bitmap.Height;
    //检测人脸,得到Rect框
    ASF_MultiFaceInfo multiFaceInfo = FaceUtil.DetectFace(pVideoEngine, bitmap);
    //得到最大人脸
    ASF_SingleFaceInfo maxFace = FaceUtil.GetMaxFace(multiFaceInfo);
    //得到Rect
    MRECT rect = maxFace.faceRect;
    float x = rect.left * offsetX;
    float width = rect.right * offsetX - x;
    float y = rect.top * offsetY;
    float height = rect.bottom * offsetY - y;
    //根据Rect进行画框
    g.DrawRectangle(pen, x, y, width, height);
    //将上一帧检测结果显示到页面上
    g.DrawString(trackUnit.message, font, brush, x, y + 5);
    //保证只检测一帧,防止页面卡顿以及出现其他内存被占用情况
    if (isLock == false)
    {
        isLock = true;
        //异步处理提取特征值和比对,不然页面会比较卡
        ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
        {
            if (rect.left != 0 && rect.right != 0 && rect.top != 0 && rect.bottom != 0)
            {
                try
                {
                    //提取人脸特征
                    IntPtr feature = FaceUtil.ExtractFeature(pVideoImageEngine, bitmap, maxFace);
                    float similarity = CompareTwoFeatures(feature, idCardHelper.idInfo.imageFeature);
                    this.similarity.Text = ("相似度为: " + similarity.ToString("P")); ; //显示在界面上
                    this.similarity.ForeColor = similarity > threshold ? Color.Green : Color.Red;
                    //得到比对结果
                    int result = (CompareTwoFeatures(feature, idCardHelper.idInfo.imageFeature) >= threshold) ? 1 : -1;
                    if (result > -1)
                    {
                        bool isLiveness = false;
                        ImageInfo imageInfo = ImageUtil.ReadBMP(bitmap); //调整图片数据
                        if (imageInfo == null)
                            return;
                        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)//活体检测成功
                        {
                            //存放当前人脸识别的相似度
                            idCardHelper.idInfo.similarity = similarity;
                            //记录下当前的摄像头的人脸抓拍照
                            idCardHelper.idInfo.capImage = bitmap;
                            //验证通过则不再是当前身份证,等待下一次身份证
                            idCardHelper.idInfo.isRight = false;
                            //在子线程中输出信息到messageBox
                            AppendText p = new AppendText(AddTextToMessBox);
                            lbl_msg.Invoke(p, "人脸验证成功,请取卡...\n");
                            pass = 1;
                            idCardHelper.idInfo.isPass = 1;
                            //将比对结果放到显示消息中,用于最新显示
                            trackUnit.message = string.Format("通过验证,相似度为{0}", similarity);
                            FileHelper.DeleteFile(m_strPath);   //删除验证过的本地文件
                            Thread.Sleep(1000);//延时1秒
                            this.IDPbox.Image = defaultImage;//照片恢复默认照片
                            trackUnit.message = "";//人脸识别框文字置空
                            setFormResultValue(true);
                        }
                        else
                        {
                            pass = 0;//标志未通过
                            trackUnit.message = "未通过,系统识别为照片";
                            AppendText p = new AppendText(AddTextToMessBox);
                            lbl_msg.Invoke(p, "抱歉,您未通过人脸验证...\n");
                            FileHelper.DeleteFile(m_strPath);//删除验证过的本地文件
                        }
                    }
                    else
                    {
                        pass = 0;//标志未通过
                        trackUnit.message = "未通过人脸验证";
                        AppendText p = new AppendText(AddTextToMessBox);
                        lbl_msg.Invoke(p, "抱歉,您未通过人脸验证...\n");
                        FileHelper.DeleteFile(m_strPath);//删除验证过的本地文件
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    FileHelper.DeleteFile(m_strPath);//删除验证过的本地文件
                }
                finally
                {
                    isLock = false;
                }
            }
            isLock = false;
        }));
    }
    return false;
}

/// <summary>
/// 比较两个特征值的相似度,返回相似度
/// </summary>
/// <param name="feature1"></param>
/// <param name="feature2"></param>
/// <returns></returns>
private float CompareTwoFeatures(IntPtr feature1, IntPtr feature2)
{
    float similarity = 0.0f;
    //调用人脸匹配方法,进行匹配
    ASFFunctions.ASFFaceFeatureCompare(pVideoImageEngine, feature1, feature2, ref similarity);
    return similarity;
}

В это время мы получаем изображение в видео.Нам нужно использовать видеодвижок pVideoEngine, чтобы обнаружить лицо из растрового изображения и получить самое большое лицо, а также извлечь значение функции лица. После получения собственных значений двух лиц на видео и на фотографии следующим шагом является передача двух фотографий в алгоритм сравнения лиц ArcSoft для получения сходства.Мы можем установить порог, и если он превышает 90% , мы можем определить, что это один и тот же человек, это еще нужно взвесить в реальном проекте.

在这里插入图片描述Таким образом, даже если сравнение прошло успешно, мы можем продолжить работу. Но это еще не конец. После того, как я провел удостоверение личности, я быстро направил свое удостоверение личности на камеру и обнаружил, что сравнение прошло успешно. Если это так, даже если это не я, кто-то другой может сделать снимок с телефон для аутентификации. Должно быть, это вызвало небезопасность, поэтому я добавил обнаружение в реальном времени. Как следует из названия, это чтобы увидеть, большой ли это живой человек, а не фотография. ​

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%, мы не упустим его.在这里插入图片描述6. Возникшие проблемы

На этом основные функции закончились, но во многих отладках обнаруживается, что время от времени будет возникать воспоминание, то есть переполнение памяти. Поскольку эта моя страница всплывает отдельно, это подстраница, и движок не был выпущен, когда окно было закрыто до этого, поэтому каждый раз для инициализации движка требуется около 50 МБ памяти, и переполнение памяти произойдет рано или поздно. позже. Итак, я выпустил три двигателя, когда подокно было закрыто, и проблема была окончательно решена.

/// <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 открыл исходный код этой демонстрации.

Чтобы узнать больше о продуктах для распознавания лиц, посетитеОткрытая платформа Arcsoft Visionой