v效率有点低,大家看看哪里开可以节省时间?
源代码:https://github.com/catzhou2002/ArcFaceDemo
说实话,为了提高识别效率,我也是竭尽所能,干了不少自认为的优化,如有兴趣听我说说。
第一部分 单线程时候的各种折腾
一、折腾LPASVLOFFSCREEN
话说这个LPASVLOFFSCREEN的结果文档里面没有说明,或者是我没找到。
我也不知道从哪里复制来的,主要折腾的是ppu8Plane[0]地址,一般操作是

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

我改成:

锁定图片内存
ppu8Plane[0]指向图片地址
等不需要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
识别成功后再次比对就很快,应该是首发命中。
六、将人脸比对和结果显示分开
一开始没想太多,将人脸比对和结果显示放在新视频帧事件里面,流程是:

新视频帧(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天后终于学会发表到博客园首页了,于是删除了打赏二维码,去首页亮了个相。
话说首页和非首页效果着实不一样,截图为证:

第二部分 多线程的折腾
一、确定4线程为最佳
各种测试后得出的结论,也不知道对不对,也不知道为什么,哎。
因网友的要求,同步到了github
二、删除了单线程
有了更快的,就不要慢的了。
三、n张脸如何分配给4个线程获取特征值?
动了不少脑筋,Interlocked.Increment是关键。
最终有改了下面的内容

如果只有一张脸(窃以为一张脸的概率比较高),也用Task,影响效率,增加了 if (detectResult.FaceCount ==

Intptr之间复制字节用CopyMemory比较快
两三张脸的时候开4个线程不好,改成 new Task[TaskNum < detectResult.FaceCount ?
TaskNum : detectResult.FaceCount]

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

弄了个结果集,按最大人脸数设了个List( Items = new List<FaceResult>();)
增加了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什么的,有兴趣的朋友一起交流交流?

C#_Demo_摄像头实时_4线程人脸识别注册开发全过程的更多相关文章

  1. java使用face++简单实现人脸识别注册登录

    java使用face++简单实现人脸识别注册登录 前言 人脸识别,好高大上!!! 理解之后很简单. 支付宝使用的就是face++, 至于face++账号信息,apikey…..,本文不做讲述,网上很多 ...

  2. Home Assistant系列 -- 接入手机摄像头做实时监控和人脸识别

    准备一部废旧(土豪忽略,主要是穷)的.摄像头还是好的手机做监控设备,(Android 和iPhone都行)当Home Assistant 获得实时的视频流后,可以接入各种图像处理组件完成人脸识别,动作 ...

  3. 基于javaweb人脸识别注册登录系统

    ---恢复内容开始--- 现在是2019年,人脸识别技术已经相当成熟了,百度自2017年发布人脸识别技术,已经被广泛应用,不管从现在的iphoneX掀起的面部解锁到手机应用端的各种人脸认证,这一技术已 ...

  4. Android 虹软免费人脸识别 SDK开发

    目前我们的应用内使用了 ArcFace 的人脸检测功能,其他的我们并不了解,所以这里就和大家分享一下我们的集成过程和一些使用心得集成ArcFace FD 的集成过程非常简单在 ArcFace FD 的 ...

  5. 虹软2.0 离线人脸识别 Android 开发 Demo

    环境要求1.运行环境 armeabi-v7a2.系统要求 Android 5.0 (API Level 21)及以上3.开发环境 Android Studio 下载地址:https://github. ...

  6. 离线人脸识别 ArcFaceSharp -- ArcFace 2.0 SDK C#封装库分享

    ArcFaceSharp ArcFaceSharp 是ArcSoft 虹软 ArcFace 2.0 SDK 的一个 C# 封装库,为方便进行 C# 开发而封装.欢迎 Start & Fork. ...

  7. 机器视觉及图像处理系列之二(C++,VS2015)——图像级的人脸识别(1)

    接上一篇,一切顺利的话,你从github上clone下来的整个工程应该已经成功编译并生成dll和exe文件了:同时,ImageMagic程序亦能够打开并编辑图像了,如此,证明接下来的操练你不会有任何障 ...

  8. 人脸识别FaceNet+TensorFlow

    一.本文目标 利用facenet源码实现从摄像头读取视频,实时检测并识别视频中的人脸.换句话说:把facenet源码中contributed目录下的real_time_face_recognition ...

  9. Github开源人脸识别项目face_recognition

    Github开源人脸识别项目face_recognition 原文:https://www.jianshu.com/p/0b37452be63e 译者注: 本项目face_recognition是一个 ...

随机推荐

  1. Golang对文件读写操作

    package main import ( "bufio" "fmt" "io" "os" ) //写 func Wri ...

  2. python使用super()调用父类的方法

    如果要在子类中引用父类的方法,但是又需要添加一些子类所特有的内容,可通过类名.方法()和super()来调用父类的方法,再个性化子类的对应函数. 直接使用类名.方法()来调用时,还是需要传入self为 ...

  3. bzoj3932 / P3168 [CQOI2015]任务查询系统(主席树+差分)

    P3168 [CQOI2015]任务查询系统 看到第k小,就是主席树辣 对于每一段任务(a,b,k),在版本a的主席树+k,版本b+1的主席树-k 同一时间可能有多次修改,所以开个vector存操作, ...

  4. 'root'@'127.0.0.1'没有grant privileges

    从另外一台服务器拷贝了个mysql实例过来,给root@'%'授权的时候提示ERROR 1045 (28000): Access denied for user 'root'@'localhost' ...

  5. DL_WITH_PY系统学习(第2章)

    ​ 本节提示: 1.第一个dl例子: 2.tensor和tensor操作: 3.DL如何通过逆向传播和梯度下降达到学习目的. 2.1 输入数据集的格式 ,*,))) network.add(layer ...

  6. MS11-050安全漏洞

    IE浏览器渗透攻击--MS11050安全漏洞 实验前准备 1.两台虚拟机,其中一台为kali,一台为windows xp sp3(包含IE7). 2.设置虚拟机网络为NAT模式,保证两台虚拟机可以相互 ...

  7. JavaScript中数组中的方法:push()、pop()、shift()、unshift()、slice()、splice()、reverse()、join()、split()、concat()、indexOf()、forEach()、map()、

      1.创建数组的几种方法 //a).通过new来创建数组,new可以省略 var arr=new Array(); var arr=Array(); //b). .通过new来创建数组,并且赋值 v ...

  8. python之udp

    import socket s = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) s.bind(('127.0.0.1',8888)) while T ...

  9. 我的QML

    1.键盘加Text import QtQuick 2.7 import QtGraphicalEffects 1.0 Rectangle{ width:; height:; color:"# ...

  10. Junit的套件使用

    定义一个类,在类的上方添加@RunWith(Suite.class)和@SuiteClasses({XX.class,YY.class,...}) 实例有两个类分别为:public class Log ...