zoukankan      html  css  js  c++  java
  • C# 摄像头实时_4线程人脸识别demo

    效率有点低,大家看看哪里开可以节省时间?
    源代码: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,整个转换过程如下:

    ar 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
    识别成功后再次比对就很快,应该是首发命中。

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

    新视频帧(30帧/秒)
    获取检测和识别的结果(人脸框和ID)
    显示检测和识别的结果
    结果视频卡顿,获取人脸特征的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天后终于学会发表到博客园首页了,于是删除了打赏二维码,去首页亮了个相。
    话说首页和非首页效果着实不一样,截图为证:
    ![在这里插入图片描述](http://ai.arcsoft.com.cn/bbs/data/attachment/forum/201805/11/002853k57rrlhsbh5bwhc1.png)
    第二部分 多线程的折腾

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

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

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

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

    弄了个结果集,按最大人脸数设了个List( Items = new List();)
    增加了FaceFeatureInput FFI,省的每次都去创建
    并将人脸方向设成1(Orient = 1)(因为是视频图片,其他方向的人脸,呵呵),人脸检测后都不要去获取人脸方向的值
    增加并初始化了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万张人脸仅需390毫秒
    5万张人脸也就1525毫秒
    10万张人脸说我内存不够,可能是我的程序是32位的缘故,换成64位的sdk估计3秒钟也能搞定(太麻烦,不折腾了)
    结论是:虹软中型sdk用于考勤、小区门禁、写字楼门禁等场所完全没问题。

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

    40次检测人脸数为0,则确认为没人,识别频率降低
    是否换人了?
    同一个人3、4次识别不出ID后,确认为陌生人,不在遍历
    刷身份证获取照片人脸比对后存入人脸库
    另外想跟企业微信结合开发开发门禁、CRM什么的,有兴趣的朋友一起交流交流?

  • 相关阅读:
    自定义控件:瀑布流水字母
    Android ViewPager欢迎页+引导页+进入首页
    自定义控件:滑动开关按钮
    自定义控件:滑动开关按钮(自定义属性)
    关于div宽度和高度的100%设定
    html中的图片、css、js等路径加载问题
    Laravel 安装
    phpmyadmin数据库导入大小限制的修改
    linux套件安装过程中configure,make,make install的作用
    Ubuntu 12.04下PHP环境的搭建(LAMP)
  • 原文地址:https://www.cnblogs.com/Zzz-/p/10948453.html
Copyright © 2011-2022 走看看