ArcFace2 #C 视频人脸比对教程
请允许我大言不惭,叫做教程,特希望各位能指正。哦,我用的是vs2017。使用虹软技术
一、准备工作
1.创建项目
2.添加EMGU.CV包
3.复制虹软的dll到项目
,并设属性“复制到输出目录”为“如果较新则复制
准备工作到此结束,按F7切换到代码,然后进入第二步。
二、代码
using Emgu.CV;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms; namespace ArcFace2Demo
{
public partial class Form1 : Form
{
#region ArcFaceConst
const uint ASF_DETECT_MODE_VIDEO = 0x00000000; //Video模式,一般用于多帧连续检测
const uint ASF_DETECT_MODE_IMAGE = 0xFFFFFFFF; //Image模式,一般用于静态图的单次检测 const uint ASF_NONE = 0x00000000;
const uint ASF_FACE_DETECT = 0x00000001; //此处detect可以是tracking或者detection两个引擎之一,具体的选择由detect mode 确定
const uint ASF_FACERECOGNITION = 0x00000004;
const uint ASF_AGE = 0x00000008;
const uint ASF_GENDER = 0x00000010;
const uint ASF_FACE3DANGLE = 0x00000020; /// <summary>
/// 结构ASF_FaceRect的长度
/// 32位程序是16,64位程序需要改为32
/// </summary>
const int SizeOfASF_FaceRect = 16; #endregion #region ArceDataStructure
/// <summary>
/// 人脸在图片中的位置
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct ASF_FaceRect
{
public int Left;
public int Top;
public int Right;
public int Bottom;
public Rectangle GetRectangle()
{
return new Rectangle(Left, Top, Right - Left, Bottom - Top);
}
}
/// <summary>
/// 多人脸信息
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct ASF_MultiFaceInfo
{ public IntPtr PFaceRect;
public IntPtr PFaceOrient;
[MarshalAs(UnmanagedType.I4)]
public int FaceNum;
} /// <summary>
/// 单人脸信息
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct ASF_SingleFaceInfo
{
public ASF_FaceRect FaceRect;
public int FaceOrient; } /// <summary>
/// 人脸特征
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct ASF_FaceFeature
{
public IntPtr PFeature;
[MarshalAs(UnmanagedType.I4)]
public int FeatureSize;
} #endregion #region ArcWrapper /// <summary>
/// 激活SDK
/// </summary>
/// <param name="appId"></param>
/// <param name="sdkKey"></param>
/// <returns>0:激活成功,0x16002表示已经激活</returns>
[DllImport("libarcsoft_face_engine.dll", EntryPoint = "ASFActivation", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int ASFActivation(string appId, string sdkKey); /// <summary>
/// 初始化引擎
/// </summary>
/// <param name="detectMode">long会返回scale错误0x16004</param>
/// <param name="orientPriority"></param>
/// <param name="scale"></param>
/// <param name="maxFaceNumber"></param>
/// <param name="combinedMask"></param>
/// <param name="pEngine"></param>
/// <returns></returns>
[DllImport("libarcsoft_face_engine.dll", EntryPoint = "ASFInitEngine", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int ASFInitEngine(uint detectMode, int orientPriority, int scale, int maxFaceNumber, uint combinedMask, out IntPtr pEngine);
/// <summary>
/// 人脸检测
/// </summary>
/// <param name="pEngine"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="format"></param>
/// <param name="pImageData"></param>
/// <param name="faceInfo"></param>
/// <returns></returns>
[DllImport("libarcsoft_face_engine.dll", EntryPoint = "ASFDetectFaces", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int ASFDetectFaces(IntPtr pEngine, int width, int height, int format, IntPtr pImageData, out ASF_MultiFaceInfo faceInfo); /// <summary>
/// 单人脸特征提取
/// </summary>
/// <param name="pEngine"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="format"></param>
/// <param name="faceInfo"></param>
/// <param name="faceFeature"></param>
/// <returns></returns>
[DllImport("libarcsoft_face_engine.dll", EntryPoint = "ASFFaceFeatureExtract", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int ASFFaceFeatureExtract(IntPtr pEngine, int width, int height, int format, IntPtr pImageData, ref ASF_SingleFaceInfo faceInfo, out ASF_FaceFeature faceFeature);
/// <summary>
/// 脸特征比对
/// </summary>
/// <param name="pEngine"></param>
/// <param name="faceFeature1"></param>
/// <param name="faceFeature2"></param>
/// <param name="result"></param>
/// <returns></returns>
[DllImport("libarcsoft_face_engine.dll", EntryPoint = "ASFFaceFeatureCompare", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int ASFFaceFeatureCompare(IntPtr pEngine, ref ASF_FaceFeature faceFeature1, ref ASF_FaceFeature faceFeature2, out float result);
/// <summary>
/// 销毁引擎
/// </summary>
/// <param name="engine"></param>
/// <returns></returns>
[DllImport("libarcsoft_face_engine.dll", EntryPoint = "ASFUninitEngine", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private static extern int ASFUninitEngine(IntPtr engine);
#endregion /// <summary>
/// 特征库
/// </summary>
IntPtr _PFeatureLib;
/// <summary>
/// 特征库人脸数量
/// </summary>
int _FeatureLibFaceCount = 0;
/// <summary>
/// 特征库人脸ID列表
/// </summary>
List<string> _FeatureLibIDList = new List<string>(); /// <summary>
/// 人脸特征结构
/// </summary>
ASF_FaceFeature _FaceFeature = new ASF_FaceFeature { FeatureSize = 1032 }; /// <summary>
/// 人脸识别的结果
/// </summary>
class FaceResult
{
/// <summary>
/// 人脸框矩形
/// </summary>
public Rectangle Rectangle { get; set; }
/// <summary>
/// 人脸ID
/// </summary>
public string ID { get; set; }
/// <summary>
/// 比对结果
/// </summary>
public float Score { get; set; } public override string ToString()
{
return [ DISCUZ_CODE_0 ]quot;ID:{ID}\r\n结果:{Score}";
}
}
/// <summary>
/// 多人脸识别结果集
/// </summary>
ConcurrentDictionary<int, FaceResult> _FaceResults = new ConcurrentDictionary<int, FaceResult>();
/// <summary>
/// 检测到的人脸数量
/// </summary>
int _DetectedFaceCount = 0; /// <summary>
/// 视频捕获
/// </summary>
VideoCapture _VideoCapture;
Mat _Frame = new Mat(); /// <summary>
/// 虹软人脸引擎
/// </summary>
IntPtr _PEngine = IntPtr.Zero; /// <summary>
/// 比对一次总耗时
/// </summary>
long _TotalElapsedMilliseconds = 0;
/// <summary>
/// 识别任务
/// </summary>
Task _TaskMatch;
/// <summary>
/// 向识别任务发送取消指令的东东
/// </summary>
CancellationTokenSource _CTS = new CancellationTokenSource(); /// <summary>
/// 图像数据
/// </summary>
IntPtr _PImageData;
/// <summary>
/// 宽、高、图像数据长度
/// </summary>
int _ImageWidth, _ImageHeight, _ImageSize;
/// <summary>
/// 是否要保存当前人脸特征
/// </summary>
bool _SaveFlag = false; PictureBox _PictureBox; public Form1()
{
InitializeComponent(); _PictureBox = new PictureBox();
_PictureBox.SizeMode = PictureBoxSizeMode.StretchImage;
_PictureBox.Dock = DockStyle.Fill;
this.Controls.Add(_PictureBox); this.Load += Form1_Load;
this.FormClosing += Form1_FormClosing;
} private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (_TaskMatch != null)
{
_CTS.Cancel();
while (_TaskMatch.Status == TaskStatus.Running)
Task.Delay(1000).Wait();
}
_VideoCapture.Stop(); if (_PEngine != IntPtr.Zero)
ASFUninitEngine(_PEngine); if (_PFeatureLib != IntPtr.Zero)
Marshal.FreeCoTaskMem(_PFeatureLib); if (_PImageData != IntPtr.Zero)
Marshal.FreeCoTaskMem(_PImageData);
} private unsafe void Form1_Load(object sender, EventArgs e)
{
var ret = ASFActivation("BKgqTWQPQQbomfqvyd2VJzTUqPp3JD8zjAzDcqsL1jLa", "2nkDTmnkpS53cpSY42fFS9nEUzg8x4MDGkAubSsebtm1");
if (ret != 0 && ret != 0x16002)
{
MessageBox.Show("SDK激活失败:0x" + ret.ToString("x2"));
return;
}
ret = ASFInitEngine(ASF_DETECT_MODE_IMAGE, 1, 32, 10, ASF_FACE_DETECT | ASF_FACERECOGNITION, out _PEngine);
if (ret != 0)
{
MessageBox.Show([ DISCUZ_CODE_0 ]quot;人脸识别引擎初始化失败:" + ret.ToString("x2"));
return;
}
//初始化识别结果集
for (int i = 0; i < 10; i++)
_FaceResults[i] = new FaceResult();
//初始化特征库
_PFeatureLib = Marshal.AllocCoTaskMem(1032 * 1000 + 1032 * 10000 * 20);
var bytes = File.ReadAllBytes("Feature.dat");
var ids = File.ReadAllLines("Id.txt");
for (int i = 0; i < 20 * 20; i++)
{
Marshal.Copy(bytes, 0, IntPtr.Add(_PFeatureLib, _FeatureLibFaceCount * 1032), bytes.Length);
_FeatureLibIDList.AddRange(ids);
_FeatureLibFaceCount += ids.Length;
} _VideoCapture = new VideoCapture(); //_VideoCapture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameWidth, 1024);
//_VideoCapture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.FrameHeight, 768);
_VideoCapture.SetCaptureProperty(Emgu.CV.CvEnum.CapProp.Fps, 10);
_VideoCapture.Start(); _VideoCapture.ImageGrabbed += (object oo, EventArgs es) =>
{
_VideoCapture.Retrieve(_Frame, 1);
using (Graphics g = Graphics.FromImage(_Frame.Bitmap))
{
g.DrawString([ DISCUZ_CODE_0 ]quot;比对总耗时{_TotalElapsedMilliseconds}毫秒", this.Font, Brushes.White, 0, 0);
for (int i = 0; i < _DetectedFaceCount; i++)
{
if (_FaceResults.TryGetValue(i, out var faceResult))
{
g.DrawRectangle(Pens.Red, faceResult.Rectangle);
g.DrawString(faceResult.ToString(), this.Font, Brushes.White, faceResult.Rectangle.Location);
}
}
}
this._PictureBox.Image = _Frame.Bitmap;
}; _PictureBox.Click += (object oo, EventArgs es) =>
{
if (MessageBox.Show("您确定要保存人脸特征数据吗?", "确认信息", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
_SaveFlag = true;
}; _ImageSize = _VideoCapture.Width * _VideoCapture.Height * 3;
_PImageData = Marshal.AllocCoTaskMem(_ImageSize);
_ImageWidth = _VideoCapture.Width;
_ImageHeight = _VideoCapture.Height; _TaskMatch = Task.Run(() =>
{
Task.Delay(1000).Wait(); while (!_CTS.IsCancellationRequested)
{
try
{
Stopwatch sw = new Stopwatch();
sw.Restart(); Marshal.Copy(_Frame.GetData(), 0, _PImageData, _ImageSize);
ret = ASFDetectFaces(_PEngine, _ImageWidth, _ImageHeight, 513, _PImageData, out var faceInfo); if (ret != 0 || faceInfo.FaceNum == 0)
{
_DetectedFaceCount = 0;
continue;
} for (int detectedFaceIndex = 0; detectedFaceIndex < faceInfo.FaceNum; detectedFaceIndex++)
{ float score = 0;
string id = "";
ASF_SingleFaceInfo singleFaceInfo = new ASF_SingleFaceInfo
{
FaceRect = Marshal.PtrToStructure<ASF_FaceRect>(IntPtr.Add(faceInfo.PFaceRect, SizeOfASF_FaceRect * detectedFaceIndex)),
FaceOrient = 1// Marshal.ReadInt32(IntPtr.Add(faceInfo.PFaceOrient, i * 4))
}; ret = ASFFaceFeatureExtract(_PEngine, _ImageWidth, _ImageHeight, 513, _PImageData, ref singleFaceInfo, out var faceFeature);
if (ret != 0)
continue;
_FaceResults[detectedFaceIndex].Rectangle = singleFaceInfo.FaceRect.GetRectangle(); if (_SaveFlag)
{
byte[] bufferSave = new byte[1032];
Marshal.Copy(faceFeature.PFeature, bufferSave, 0, 1032);
var newId = DateTime.Now.Ticks.ToString(); FileStream fs = new FileStream("Feature.dat", FileMode.Append);
fs.Write(bufferSave, 0, 1032);
fs.Close(); var streamWriter = File.AppendText("Id.txt");
streamWriter.Write("\r\n" + newId);
streamWriter.Close(); Marshal.Copy(bufferSave, 0, IntPtr.Add(_PFeatureLib, 1032 * _FeatureLibFaceCount), 1032);
_FeatureLibIDList.Add(newId);
_FeatureLibFaceCount++; if (detectedFaceIndex == faceInfo.FaceNum - 1)
{
MessageBox.Show("保存特征数据成功!");
_SaveFlag = false;
}
continue;
} ConcurrentBag<int> needCompareFaceIndexs = new ConcurrentBag<int>(); Parallel.For(0, _FeatureLibFaceCount, faceIndex =>
{ byte* pLib = ((byte*)_PFeatureLib) + 1032 * faceIndex + 8;
byte* pCurrent = ((byte*)faceFeature.PFeature) + 8;
int count = 0;
for (int j = 0; j < 1024; j++)
{
if (*pLib++ == *pCurrent++)
count++;
}
if (count > 80)
needCompareFaceIndexs.Add(faceIndex);
}); foreach (var index in needCompareFaceIndexs)//650ms
{
_FaceFeature.PFeature = IntPtr.Add(_PFeatureLib, index * 1032);
ASFFaceFeatureCompare(_PEngine, ref faceFeature, ref _FaceFeature, out var r); if (r > 0.8 && r > score)
{
score = r;
id = _FeatureLibIDList[index];
}
} _FaceResults[detectedFaceIndex].Score = score;
_FaceResults[detectedFaceIndex].ID = id;
} _DetectedFaceCount = faceInfo.FaceNum; sw.Stop();
_TotalElapsedMilliseconds = sw.ElapsedMilliseconds; }
catch (Exception ex)
{ }
}
}, _CTS.Token); } }
}
三、下载测试用特征数据(500张人脸)并解压到运行目录
ArcFaceData.zip (463.7 KB, 下载次数: 0)
四、按F5运行
点击视频增加当前人脸的特征数据,基本上800毫秒可以从20万人脸中找到你。
ArcFace2 #C 视频人脸比对教程的更多相关文章
- 【C#】ArcFace2 视频人脸比对教程
请允许我大言不惭,叫做教程,特希望各位能指正.哦,我用的是vs2017.了解更多详情可以访问虹软人工智能开放平台 一.准备工作 1.创建项目 2.添加EMGU.CV包 ,并设属性“复制到输出目录”为“ ...
- [深度应用]·实战掌握Dlib人脸识别开发教程
[深度应用]·实战掌握Dlib人脸识别开发教程 个人网站--> http://www.yansongsong.cn/ 项目GitHub地址--> https://github.com/xi ...
- C++开发人脸性别识别教程(19)——界面美化
在这篇博文中将完毕<C++开发人脸性别识别>的收尾工作.主要内容分为两部分:加入视频暂定功能.界面规范化. 一 视频暂停功能 严格来说这个视频暂定功能算是视频人脸性别识别的一个遗留问题,本 ...
- 视频人脸检测——OpenCV版(三)
视频人脸检测是图片人脸检测的高级版本,图片检测详情点击查看我的上一篇<图片人脸检测——OpenCV版(二)> 实现思路: 调用电脑的摄像头,把摄像的信息逐帧分解成图片,基于图片检测标识出人 ...
- 视频人脸检测——Dlib版(六)
往期目录 视频人脸检测--Dlib版(六) OpenCV添加中文(五) 图片人脸检测--Dlib版(四) 视频人脸检测--OpenCV版(三) 图片人脸检测--OpenCV版(二) OpenCV环境搭 ...
- 2018-06-21 中文代码示例视频演示Python入门教程第五章 数据结构
知乎原链 续前作: 中文代码示例视频演示Python入门教程第四章 控制流 对应在线文档: 5. Data Structures 这一章起初还是采取了尽量与原例程相近的汉化方式, 但有些语义较偏(如T ...
- 2018-06-20 中文代码示例视频演示Python入门教程第四章 控制流
知乎原链 续前作: 中文代码示例视频演示Python入门教程第三章 简介Python 对应在线文档: 4. More Control Flow Tools 录制中出了不少岔子. 另外, 输入法确实是一 ...
- 阿里云视频直播PHP-SDK接入教程
阿里云视频直播PHP-SDK接入教程 阿里云 视频直播 配置 及 PHP-SDK 接入教程 准备工作 域名管理 配置鉴权 地址生成器及DEMO演 ...
- C++开发人脸性别识别教程(12)——加入性别识别功能
经过之前几篇博客的解说,我们已经成功搭建了MFC应用框架,并实现了主要的图像显示和人脸检測程序,在这篇博文中我们要向当中加入性别识别代码. 关于性别识别,之前已经专门拿出两篇博客的篇幅来进行解说.这里 ...
随机推荐
- enq: TM - contention一例
今天下午,有台服务器出现异常,响应特别慢,io等待奇高,awr top 5事件如下: 经回查ash,找到了造成这些事件的sql语句,如下: select * from v$active_session ...
- 一致性哈希算法(适用于分库分表、RPC负载均衡)转
在分布式应用中,应该来说使用到hash最多的地方就是rpc负载均衡和分库分表,通常对于正式意义上的分布式应用来说,扩容和收缩是一个半自动化的过程,在此期间,应用基本上是可用的,所以不能发生大规模动荡的 ...
- 【题解】 Luogu P4312 / SP4155 [COCI 2009] OTOCI / 极地旅行社
原题地址:P4312 [COCI 2009] OTOCI / 极地旅行社/SP4155 OTOCI - OTOCI lct入门难度的题,十分弱智(小蒟蒻说lct是什么,能吃吗?) bridge操作判联 ...
- How to Conduct High-Impact Research and Produce High-Quality Papers
How to Conduct High-Impact Research and Produce High-Quality Papers Contents From Slide Russell Grou ...
- 主动攻击:利用ms08_067_netapi进行攻击
利用ms09_053_wins进行攻击 ms08_067漏洞 如果用户在受影响的系统上收到特制的 RPC 请求,则该漏洞可能允许远程执行代码. 在 Microsoft Windows 2000.Win ...
- Ubuntu软件操作的相关命令
Ubuntu软件操作的相关命令 sudo apt-get update ------------------------------- 更新源 sudo apt-get install package ...
- webpack --watch和supervisor的不同
webpack --watch只是热打包,也就是前端代码的热加载,要实现后端代码的热加载,也就是热部署,需要使用supervisor 如何使用热部署可以参考这里:http://www.cnblogs ...
- 使用注释来解决关于inline-block元素换行问题
昨天群里有人问个问题:为什么button加了文字后,产生了对齐不一致的问题. 原因在于baseline的对齐问题. 然后就有人推荐了一篇文章:关于Vertical-Align你需要知道的事情 其中里面 ...
- Codeforces 375C Circling Round Treasures - 最短路 - 射线法 - 位运算
You have a map as a rectangle table. Each cell of the table is either an obstacle, or a treasure wit ...
- Android studio 搭建测试环境 创建虚拟机
1.打开android studio2.0 ,选择AVD Manger 2.选择Create Virtual Device 3.在左侧Category中选择Phone,然后选择自己喜欢的手机型号,点击 ...