C#_Demo_摄像头实时_4线程人脸识别注册开发全过程

效率有点低,大家看看哪里开可以节省时间?
源代码:https://github.com/catzhou2002/ArcFaceDemo

说实话,为了提高识别效率,我也是竭尽所能,干了不少自认为的优化,如有兴趣听我说说。

第一部分 单线程时候的各种折腾

一、折腾LPASVLOFFSCREEN
话说这个LPASVLOFFSCREEN的结果文档里面没有说明,或者是我没找到。
我也不知道从哪里复制来的,主要折腾的是ppu8Plane[0]地址,一般操作是

  1. 锁定图片内存
  2. ppu8Plane[0]分配制定长度的内存
  3. 把图片内存中的字节复制到一个临时数组
  4. 然后用Marshal.Copy复制到指定的地址
  5. 解锁图片内存

我改成:

  1. 锁定图片内存
  2. ppu8Plane[0]指向图片地址
  3. 等不需要LPASVLOFFSCREEN时(人脸检测、获取特征值、性别判断、年龄估算等结束后)解锁图片内存

就晚一点解锁,省了好多事情,耗时由4毫秒没成2微妙。当时就发了个帖:C# Bitmap转ASVLOFFSCREEN的最佳方式?

后来觉得这名字实在记不住,也不C#,改成了ImageData,整个转换过程如下:

var bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            var imageData = new ImageData
            {
                PixelArrayFormat = 513,//Rgb24,
                Width = bitmap.Width,
                Height = bitmap.Height,
                Pitch = new int[4] { bmpData.Stride, 0, 0, 0 },
                ppu8Plane = new IntPtr[4] { bmpData.Scan0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero }
            };
....
            bitmap.UnlockBits(bmpData);

其实如果是视频图片的话,图片的宽度和高度都是固定的,想了想,没折腾。

二、单线程时将获取到的FaceModel直接做人脸比对的参数

ExtractFeature(_FaceMatchEngine, ref imageData, ref faceFeatureInput, out var <font color="#ff8c00">faceModel</font>);
FacePairMatch(_FaceMatchEngine, ref fm, ref <font color="#ff8c00">faceModel</font>, out float score);

一般操作是faceModel里面的字节复制到临时字节数组,然后创建新的FaceModel,分配内存,在将临时字节数组复制到FaceModel。

三、人脸库直接用FaceModel

/// <summary>
    /// 人脸库
    /// </summary>
    public class FaceLib
    {
        public List<Item> Items { get; set; } = new List<Item>();
        public class Item
        {
            /// <summary>
            /// 用于排序
            /// </summary>
            public long OrderId { get; set; }
            /// <summary>
            /// 文件名作为ID
            /// </summary>
            public string ID { get; set; }
            /// <summary>
            /// 人脸模型
            /// </summary>
<font color="#ff8c00">            public FaceModel FaceModel { get; set; }</font>  
        }
    }

四、比对结果>0.5就算成功
五、人脸库增加OrderId
识别成功后再次比对就很快,应该是首发命中。

六、将人脸比对和结果显示分开
一开始没想太多,将人脸比对和结果显示放在新视频帧事件里面,流程是:

  1. 新视频帧(30帧/秒)
  2. 获取检测和识别的结果(人脸框和ID)
  3. 显示检测和识别的结果

结果视频卡顿,获取人脸特征的200毫秒成为瓶颈,改成:

  • 人脸比对
 Task.Factory.StartNew(() =>
            {
                Task.Delay(1000).Wait();
                while (!_CancellationTokenSource.IsCancellationRequested)
                {
                    #region 200毫秒左右
                    MatchFrame(); 
                    #endregion
                }
            }, _CancellationTokenSource.Token);
  • 结果显示
 private void VideoPlayer_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawRectangle(Pens.White, _FaceResult.Rectangle);
            e.Graphics.DrawString(_FaceResult.ID , this.Font, Brushes.White, _FaceResult.Rectangle.Left, _FaceResult.Rectangle.Top - 20);
        }

测试了一下,效果还可以,就在博客园发表了
C# 虹软SDK视频人脸识别和注册
,还顺手弄了个打赏二维码。
发表完觉得这么辛苦写出来的文章,必须到首页去亮个相,9天后终于学会发表到博客园首页了,于是删除了打赏二维码,去首页亮了个相。
话说首页和非首页效果着实不一样,截图为证:

这里写图片描述

第二部分 多线程的折腾

一、确定4线程为最佳
各种测试后得出的结论,也不知道对不对,也不知道为什么,哎。
因网友的要求,同步到了github

二、删除了单线程
有了更快的,就不要慢的了。

三、n张脸如何分配给4个线程获取特征值?
动了不少脑筋,Interlocked.Increment是关键。
最终有改了下面的内容

  1. 如果只有一张脸(窃以为一张脸的概率比较高),也用Task,影响效率,增加了 if (detectResult.FaceCount ==
  2. Intptr之间复制字节用CopyMemory比较快
  3. 两三张脸的时候开4个线程不好,改成 new Task[TaskNum < detectResult.FaceCount ?
    TaskNum : detectResult.FaceCount]

四、识别结果(集)的折腾

  1. 弄了个结果集,按最大人脸数设了个List( Items = new List<FaceResult>();)
  2. 增加了FaceFeatureInput FFI,省的每次都去创建
  3. 并将人脸方向设成1(Orient = 1)(因为是视频图片,其他方向的人脸,呵呵),人脸检测后都不要去获取人脸方向的值
  4. 增加并初始化了FaceModel(FaceModel FaceModel = new FaceModel() { Size =
    22020, PFeature = Marshal.AllocCoTaskMem(22020) };),获取到的特征字节直接复制过来便可

五、保存特征值到人脸库的时候同时保存头像
因为虹软说了,sdk升级的时候,特征值也有可能变化。那咱先把头像保存起来,到时候重新生成一下。
主要的操作是把矩形放大一点(Inflate((int)(r.Width * 0.5), (int)(r.Height * 0.5))),咱保存的头像怎么着得是个人头吧。

(想来条分割线,居然只有华丽的分割线,算了。顺便吐槽一下,这个论坛的编辑器实在是让人无语_)

各种折腾后,黔驴技穷了,10,000人脸的库得出10张不认识的脸的结论,需要10秒钟。当然,换好一点的电脑可以提高效率,如我的台式机(i5-7500),输入图片只有1张脸的时候,遍历

  1. 1万张人脸仅需390毫秒
  2. 5万张人脸也就1525毫秒
  3. 10万张人脸说我内存不够,可能是我的程序是32位的缘故,换成64位的sdk估计3秒钟也能搞定(太麻烦,不折腾了)

结论是:虹软中型sdk用于考勤、小区门禁、写字楼门禁等场所完全没问题。

下一步我打算(其实已经差不多完成,我公司的项目——酒店自助机)改成单脸多线程识别,增加以下功能:

  1. 40次检测人脸数为0,则确认为没人,识别频率降低
  2. 是否换人了?
  3. 同一个人3、4次识别不出ID后,确认为陌生人,不在遍历
  4. 刷身份证获取照片人脸比对后存入人脸库

另外想跟企业微信结合开发开发门禁、CRM什么的,有兴趣的朋友一起交流交流?

洗洗睡了,晚安。

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

推荐阅读更多精彩内容