吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 9787|回复: 49
收起左侧

[其他转载] C#虹软 人脸识别1:N 10万级人脸库对比实现

   关闭 [复制链接]
jeongong 发表于 2022-3-21 09:13
本帖最后由 jeongong 于 2022-3-21 16:55 编辑

       最近在做一个医疗自助报到项目,本想用指纹识别方式去做,后来了解虹软的人脸识别还是比较人性化的,最重要的是免费。于是就用上了。按官方Demo写好后,发现还是挺快的,当人脸库图片加到10万级别时,算了下加载时间一张人脸得160毫秒左右,10万张单纯加载就得大半天了。(人脸图片直接存数据库,循环加载再提取人脸特征到内存)。后来看到可以预先保存人脸库到数据库。于是又倒腾了下,最终测试效果还是比较满意的,10万张人脸特征库,加载时间2~3秒。最最关键的是,可以不保存人脸图片了。对比时,在最坏的情况要对比到第10万张,得花7秒左右的时间对比。这个对于实际业务运用中还是不够的。这个可以使用多引擎多线程加快对比,但由于本项目特定业务需求,只加载了有业务需求的库,所以大大降低了人脸库的数量。主要实现代码:


人脸库采集、人脸特征保存:
           /// <summary>
        /// 注册一张人脸照片到特征库中
        /// 返回1成功,如果返回其他就是注册失败,有可能是提取人脸特征失败(没有人脸,人脸太小,太模糊等原因)
        /// </summary>
        /// <param name="image">待注册的张人脸照片</param>
        /// <returns>"1"成功,其他就是失败的提示信息</returns>
        public static string RegisterImageEx(Image image)
        {
            cutImage = null;
            ifeature = new FaceFeature();
            if (image == null)
            {
                return "图片为空";
            }
            if (image.Width > 1536 || image.Height > 1536)
            {
                image = ImageUtil.ScaleImage(image, 1536, 1536);
            }
            if (image == null)
            {
                return "图片缩放后为空";
            }
            if (image.Width % 4 != 0)
            {
                image = ImageUtil.ScaleImage(image, image.Width - (image.Width % 4), image.Height);
            }
            //人脸检测
            ASF_MultiFaceInfo multiFaceInfo = FaceUtil.DetectFace(pImageEngine, image);
            //判断检测结果
            if (multiFaceInfo.faceNum > 0)
            {
                // 存在人脸
                MRECT rect = MemoryUtil.PtrToStructure<MRECT>(multiFaceInfo.faceRects);
                image = ImageUtil.CutImage(image, rect.left, rect.top, rect.right, rect.bottom);
                if (image.Width % 4 != 0)
                {
                    image = ImageUtil.ScaleImage(image, image.Width - (image.Width % 4), image.Height);
                }
                cutImage = image;
            }
            else
            {
                //图片中没有人脸
                return "图片中没有人脸";
            }

            ASF_SingleFaceInfo singleFaceInfo = new ASF_SingleFaceInfo();
            FaceFeature feature = FaceUtil.ExtractFeatureEx(pImageEngine, image, out singleFaceInfo);
            if (singleFaceInfo.faceRect.left == 0 && singleFaceInfo.faceRect.right == 0)
            {
                return "特征值提取失败:未检测到人脸";
            }
            else
            {
                // 先清空,模拟人证比对,一次只能注册一张照片
                imagesFeatureListEx.Clear();
                // 添加特征值到人脸库
                imagesFeatureListEx.Add(feature);
                ifeature = feature;
                return "1";
            }
        }


/// <summary>
        /// 提取人脸特征
        /// </summary>
        /// <param name="pEngine">引擎Handle</param>
        /// <param name="image">图像</param>
        /// <returns>保存人脸特征结构体指针</returns>
        public static FaceFeature ExtractFeatureEx(IntPtr pEngine, Image image, out ASF_SingleFaceInfo singleFaceInfo)
        {
            FaceFeature localFeature = new FaceFeature();
            if (image.Width > 1536 || image.Height > 1536)
            {
                image = ImageUtil.ScaleImage(image, 1536, 1536);
            }
            else
            {
                image = ImageUtil.ScaleImage(image, image.Width, image.Height);
            }
            if (image == null)
            {
                singleFaceInfo = new ASF_SingleFaceInfo();

                return localFeature;
            }
            ImageInfo imageInfo = ImageUtil.ReadBMP(image);
            if (imageInfo == null)
            {
                singleFaceInfo = new ASF_SingleFaceInfo();
                return localFeature;
            }
            ASF_MultiFaceInfo multiFaceInfo = DetectFace(pEngine, imageInfo);
            singleFaceInfo = new ASF_SingleFaceInfo();
            localFeature = ExtractFeatureEx(pEngine, imageInfo, multiFaceInfo, out singleFaceInfo);
            MemoryUtil.Free(imageInfo.imgData);
            return localFeature;
        }

保存人脸特征库时,转成base64 字符串保存。


/// <summary>
        /// 传入一张摄像头获取的人脸图片,与特征库中的图片进行比较,返回比较的结果
        /// 含RBG活体检测
        /// </summary>
        /// <param name="bitmap">摄像头拍摄的图片</param>
        /// <param name="rgbVideoSourceWidth">摄像头镜头的宽度(程序中视频的宽度)</param>
        /// <param name="rgbVideoSourceHeight">摄像头镜头的高度(程序中视频的高度)</param>
        /// <returns></returns>
        public static FaceCompareResult DoRgbCompareEx(Bitmap bitmap)
        {
            faceIndex = -1;
            if (bitmap == null)
            {
                faceCompareResult.faceIndex = -1;
                faceCompareResult.msg = "待识别图片为空";
                return faceCompareResult;
            }
            if (null == patientFaceList || patientFaceList.Count <= 0)
            {
                faceCompareResult.faceIndex = -1;
                faceCompareResult.msg = "人脸库中没有图片";
                return faceCompareResult;
            }

            //检测得到图片中的全部人脸,得到Rect框
            ASF_MultiFaceInfo multiFaceInfo = FaceUtil.DetectFace(pVideoEngine, bitmap);
            //得到最大人脸
            ASF_SingleFaceInfo maxFace = FaceUtil.GetMaxFace(multiFaceInfo);
            //得到Rect
            MRECT rect = maxFace.faceRect;
            float offsetX = VideoSource.Width * 1f / bitmap.Width;
            float offsetY = VideoSource.Height * 1f / bitmap.Height;

            //保证只检测一帧,防止页面卡顿以及出现其他内存被占用情况
            if (isRGBLock == false)
            {
                isRGBLock = true;
                //异步处理提取特征值和比对,不然页面会比较卡
                ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
                {
                    if (rect.left != 0 && rect.right != 0 && rect.top != 0 && rect.bottom != 0)
                    {
                        try
                        {
                            if (isUninitEngine)
                            {
                                return;
                            }

                            lock (rectLock)
                            {
                                allRect.left = (int)(rect.left * offsetX);
                                allRect.top = (int)(rect.top * offsetY);
                                allRect.right = (int)(rect.right * offsetX);
                                allRect.bottom = (int)(rect.bottom * offsetY);
                            }
                            //调整图片数据,非常重要
                            ImageInfo imageInfo = ImageUtil.ReadBMP(bitmap);
                            if (imageInfo == null)
                            {
                                faceCompareResult.faceIndex = -1;
                                faceCompareResult.msg = "bitmap转ImageInfo失败";
                                return;
                            }
                            int retCode_Liveness = -1;
                            bool isLiveness = false;
                            if (isUninitEngine)
                            {
                                return;
                            }
                            //RGB活体检测
                            ASF_LivenessInfo liveInfo = FaceUtil.LivenessInfo_RGB(pVideoRGBImageEngine, 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 (imageInfo != null)
                            {
                                MemoryUtil.Free(imageInfo.imgData);
                            }
                            if (isLiveness)
                            {
                                //提取人脸特征
                                FaceFeature feature = FaceUtil.ExtractFeatureEx(pVideoRGBImageEngine, bitmap, maxFace);
                                float similarity = 0f;
                                //得到比对结果

                                int result = CompareFeatureEx(feature, 0, patientFaceList.Count, out similarity);
                                if (result > -1)
                                {
                                    //将比对结果放到显示消息中,用于最新显示
                                    faceCompareResult.faceIndex = result;
                                    faceCompareResult.similarity = similarity;
                                    faceCompareResult.isLiveness = isLiveness;
                                    faceCompareResult.image = (Bitmap)bitmap.Clone(); //传回图像
                                    //faceCompareResult.msg = $"RGB活体,{result}号,相似度:{similarity}";
                                    faceIndex = result;
                                }
                                else
                                {
                                    //显示消息
                                    faceCompareResult.faceIndex = result;
                                    faceCompareResult.similarity = similarity;
                                    faceCompareResult.isLiveness = isLiveness;
                                    //faceCompareResult.msg = $"RGB活体,{result}号,相似度:{similarity}";
                                    faceIndex = result;
                                }
                            }
                            else
                            {
                                //显示消息
                                faceCompareResult.faceIndex = -1;
                                faceCompareResult.similarity = -1;
                                faceCompareResult.isLiveness = isLiveness;
                                faceCompareResult.msg = $"RGB假体";
                            }
                        }
                        catch (Exception ex)
                        {
                            //显示消息
                            faceCompareResult.faceIndex = -1;
                            faceCompareResult.similarity = -1;
                            faceCompareResult.isLiveness = false;
                            faceCompareResult.msg = ex.ToString();
                            Console.WriteLine(ex.Message);
                        }
                        finally
                        {
                            if (bitmap != null)
                            {
                                bitmap.Dispose();
                            }
                            isRGBLock = false;
                        }
                    }
                    else
                    {
                        //显示消息
                        faceCompareResult.faceIndex = -1;
                        faceCompareResult.similarity = -1;
                        faceCompareResult.isLiveness = false;
                        faceCompareResult.msg = "没有人脸";
                        lock (rectLock)
                        {
                            allRect.left = 0;
                            allRect.top = 0;
                            allRect.right = 0;
                            allRect.bottom = 0;
                        }
                    }
                    isRGBLock = false;
                }));
            }

            return faceCompareResult;
        }

/// <summary>
        /// 得到feature比较结果
        /// </summary>
        /// <param name="feature"></param>
        /// <returns></returns>
        private static int CompareFeatureEx(FaceFeature feature,int start,int end ,out float similarity)
        {
            int result = -1;
            similarity = 0f;

            //如果人脸库不为空,则进行人脸匹配

                for(int i=start;i<end;i++)
                {
                    //调用人脸匹配方法,进行匹配
                   int refCode= FaceUtil.ASFFaceFeatureCompare(pVideoRGBImageEngine, feature, new FaceFeature() { feature = Convert.FromBase64String(patientFaceList.Feature), featureSize = patientFaceList.FeatureSize }, out similarity);
                    if (refCode==0&&similarity >= threshold)
                    {
                        result = patientFaceList.PatientID;
                        break;
                    }
                }
            Console.WriteLine("Get Result:" + result+ " Get similarity:"+ similarity);
            return result;
        }

FaceCompare.7z

5.27 KB, 下载次数: 221, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 1吾爱币 +1 收起 理由
有本事你来找我 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| jeongong 发表于 2022-3-30 16:45
RemMai 发表于 2022-3-29 19:34
做过对接,其实挺简单的。
就是工厂任务终端。

是的对接是比较简单,就处理人脸库对比麻烦点,业务需求要求高,对比的响应基本得在3秒内,用户才能接受
 楼主| jeongong 发表于 2022-3-21 16:58
tb612443 发表于 2022-3-21 15:09
感谢分享,为什么我看到的虹软都是收费的接口

有免费版,增值版。免费个人版可以注册100台设备。只不过每年都要更新本地的SDK

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
tb612443 + 1 + 1 我很赞同!

查看全部评分

mengkaikai 发表于 2022-3-21 11:10
hackgsl 发表于 2022-3-21 11:14
感谢分享。
zzyang115 发表于 2022-3-21 11:33
不懂,但看着就很厉害··
neptune88 发表于 2022-3-21 11:43
感谢楼主分享,方便的话,能否直接给个完整的demo,谢谢!
疯情都市 发表于 2022-3-21 12:59
这也会,确实牛B的
zhao2021 发表于 2022-3-21 13:44
感谢分享。
caxzan 发表于 2022-3-21 13:48
楼主,你这个有没有案例啊,就是登入界面,实现人脸
13149158 发表于 2022-3-21 14:05
这个会不会有点太凌乱了,我这复制粘贴之后有很多连接不上的句子似的。
symbolshen 发表于 2022-3-21 14:16
收藏一下 应该会很有用
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 17:18

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表