C#基于Arcface人脸识别SDK完成人脸识别和注册

coding

整个项目使用虹软技术完成开发

一,准备工作

1.Afoge视频参数类

`using AForge.Video.DirectShow; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;

namespace FaceRecognization.Common { public class CameraPara { /// <summary> /// 是否有摄像头 /// </summary> public bool HasVideoDevice { get; set; } /// <summary> /// 视频源 /// </summary> public VideoCaptureDevice VideoSource { get; set; } /// <summary> /// 视频图片的宽度 /// </summary> public int FrameWidth { get; set; } /// <summary> /// 视频图片的高度 /// </summary> public int FrameHeight { get; set; } /// <summary> /// 视频图片的字节数 /// </summary> public int ByteCount { get; set; } public CameraPara() { var videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

        if (videoDevices.Count == 0)//没有检测到摄像头

{

HasVideoDevice = false;

return;

}

VideoSource = new VideoCaptureDevice(videoDevices[0].MonikerString);//连接第一个摄像头

var videoResolution = VideoSource.VideoCapabilities.First(ii => ii.FrameSize.Width == VideoSource.VideoCapabilities.Max(jj => jj.FrameSize.Width)); //获取摄像头最高的分辨率

FrameWidth = videoResolution.FrameSize.Width;

FrameHeight = videoResolution.FrameSize.Height;

ByteCount = videoResolution.BitCount / 8;

VideoSource.VideoResolution = videoResolution;

HasVideoDevice = true;

}

}

} `

2.人脸识别相关的结构、类 和枚举

using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks;

namespace FaceRecognization.Face { /// <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> public FaceModel FaceModel { get; set; } } } /// <summary> /// 人脸识别结果 /// </summary> public class FaceResult { //public int NotMatchedCount { get; set; } public string ID { get; set; } public float Score { get; set; } public System.Drawing.Rectangle Rectangle { get; set; } public int Age { get; set; } /// <summary> /// 0:男,1:女,其他:未知 /// </summary> public int Gender { get; set; } public override string ToString() {

        string ret = "";

if (!string.IsNullOrEmpty(ID))

ret = ID + ",";

ret += Age + "岁";

if (Gender == 0)

ret += ",男";

else if (Gender == 1)

ret += ",女";

return ret + "," + Score;

}

}

/// <summary>

/// 人脸跟踪、检测、性别年龄评估和获取人脸信息的输入参数

/// </summary>

[StructLayout(LayoutKind.Sequential)]

public struct ImageData

{

public uint u32PixelArrayFormat;

public int i32Width;

public int i32Height;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]

public IntPtr[] ppu8Plane;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.I4)]

public int[] pi32Pitch;

}

/// <summary>

/// 人脸跟踪的结果

/// </summary>

[StructLayout(LayoutKind.Sequential)]

internal struct TraceResult

{

[MarshalAs(UnmanagedType.I4)]

public int nFace;

[MarshalAs(UnmanagedType.I4)]

public int lfaceOrient;

public IntPtr rcFace;

}

/// <summary>

/// 人脸检测的结果

/// </summary>

[StructLayout(LayoutKind.Sequential)]

internal struct DetectResult

{

[MarshalAs(UnmanagedType.I4)]

public int nFace;

public IntPtr rcFace;

public IntPtr lfaceOrient;

}

/// <summary>

/// 人脸在图片中的位置

/// </summary>

[StructLayout(LayoutKind.Sequential)]

public struct FaceRect

{

public int left;

public int top;

public int right;

public int bottom;

}

/// <summary>

/// 获取人脸特征的输入参数

/// </summary>

[StructLayout(LayoutKind.Sequential)]

internal struct FaceFeatureInput

{

public FaceRect rcFace;

public int lOrient;

}

/// <summary>

/// 人脸特征

/// </summary>

[StructLayout(LayoutKind.Sequential)]

public struct FaceModel

{

public IntPtr pbFeature;

[MarshalAs(UnmanagedType.I4)]

public int lFeatureSize;

}

/// <summary>

/// 性别和年龄评估的输入参数

/// </summary>

[StructLayout(LayoutKind.Sequential)]

internal struct EstimationInput

{

public IntPtr pFaceRectArray;

public IntPtr pFaceOrientArray;

public int lFaceNumber;

}

/// <summary>

/// 性别和年龄评估的结果

/// </summary>

[StructLayout(LayoutKind.Sequential)]

internal struct EstimationResult

{

public IntPtr pResult;

public int lFaceNumber;

}

/// <summary>

/// 错误代码

/// </summary>

public enum ErrorCode

{

/// <summary>

/// 正确

/// </summary>

Ok = 0,

/// <summary>

/// 通用错误类型

/// </summary>

BasicBase = 0x0001,

/// <summary>

/// 错误原因不明

/// </summary>

Unknown = BasicBase,

/// <summary>

/// 无效的参数

/// </summary>

InvalidParam = BasicBase + 1,

/// <summary>

/// 引擎不支持

/// </summary>

Unsupported = BasicBase + 2,

/// <summary>

/// 内存不足

/// </summary>

NoMemory = BasicBase + 3,

/// <summary>

/// 状态错误

/// </summary>

BadState = BasicBase + 4,

/// <summary>

/// 用户取消相关操作

/// </summary>

UserCancel = BasicBase + 5,

/// <summary>

/// 操作时间过期

/// </summary>

Expired = BasicBase + 6,

/// <summary>

/// 用户暂停操作

/// </summary>

UserPause = BasicBase + 7,

/// <summary>

/// 缓冲上溢

/// </summary>

BufferOverflow = BasicBase + 8,

/// <summary>

/// 缓冲下溢

/// </summary>

BufferUnderflow = BasicBase + 9,

/// <summary>

/// 存贮空间不足

/// </summary>

NoDiskspace = BasicBase + 10,

/// <summary>

/// 组件不存在

/// </summary>

ComponentNotExist = BasicBase + 11,

/// <summary>

/// 全局数据不存在

/// </summary>

GlobalDataNotExist = BasicBase + 12,

/// <summary>

/// Free SDK通用错误类型

/// </summary>

SdkBase = 0x7000,

/// <summary>

/// 无效的App Id

/// </summary>

InvalidAppId = SdkBase + 1,

/// <summary>

/// 无效的SDK key

/// </summary>

InvalidSdkId = SdkBase + 2,

/// <summary>

/// AppId和SDKKey不匹配

/// </summary>

InvalidIdPair = SdkBase + 3,

/// <summary>

/// SDKKey 和使用的SDK 不匹配

/// </summary>

MismatchIdAndSdk = SdkBase + 4,

/// <summary>

/// 系统版本不被当前SDK所支持

/// </summary>

SystemVersionUnsupported = SdkBase + 5,

/// <summary>

/// SDK有效期过期,需要重新下载更新

/// </summary>

LicenceExpired = SdkBase + 6,

/// <summary>

/// Face Recognition错误类型

/// </summary>

FaceRecognitionBase = 0x12000,

/// <summary>

/// 无效的输入内存

/// </summary>

InvalidMemoryInfo = FaceRecognitionBase + 1,

/// <summary>

/// 无效的输入图像参数

/// </summary>

InvalidImageInfo = FaceRecognitionBase + 2,

/// <summary>

/// 无效的脸部信息

/// </summary>

InvalidFaceInfo = FaceRecognitionBase + 3,

/// <summary>

/// 当前设备无GPU可用

/// </summary>

NoGpuAvailable = FaceRecognitionBase + 4,

/// <summary>

/// 待比较的两个人脸特征的版本不一致

/// </summary>

MismatchedFeatureLevel = FaceRecognitionBase + 5

}

/// <summary>

/// 脸部角度的检测范围

/// </summary>

public enum OrientPriority

{

/// <summary>

/// 检测 0 度(±45 度)方向

/// </summary>

Only0 = 0x1,

/// <summary>

/// 检测 90 度(±45 度)方向

/// </summary>

Only90 = 0x2,

/// <summary>

/// 检测 270 度(±45 度)方向

/// </summary>

Only270 = 0x3,

/// <summary>

/// 检测 180 度(±45 度)方向

/// </summary>

Only180 = 0x4,

/// <summary>

/// 检测 0, 90, 180, 270 四个方向,0 度更优先

/// </summary>

Ext0 = 0x5

}

}

3.虹软SDK的dll封装

注意要把相应的dll复制的debug\Libs文件夹或release\Libs文件夹

`using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks;

namespace FaceRecognization.Face { internal class Detect { private const string DllPath = "Libs/libarcsoft_fsdk_face_detection.dll"; /// <summary> /// /// </summary> /// <param name="appId"></param> /// <param name="sdkKey"></param> /// <param name="memory"></param> /// <param name="memroySize"></param> /// <param name="engine"></param> /// <param name="orientPriority"></param> /// <param name="scale">最小人脸尺寸有效值范围[2,50] 推荐值 16。该尺寸是人脸相对于所在图片的长边的占比。例如,如果用户想检测到的最小人脸尺寸是图片长度的 1/8,那么这个 nScale 就应该设置为8</param> /// <param name="maxFaceNumber">用户期望引擎最多能检测出的人脸数有效值范围[1,100]</param> /// <returns></returns> [DllImport(DllPath, EntryPoint = "AFD_FSDK_InitialFaceEngine", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern int Init(string appId, string sdkKey, byte[] memory, int memroySize, out IntPtr engine, int orientPriority, int scale, int maxFaceNumber); [DllImport(DllPath, EntryPoint = "AFD_FSDK_StillImageFaceDetection", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern int Detection(IntPtr engine, ref ImageData imgData, out IntPtr pDetectResult); [DllImport(DllPath, EntryPoint = "AFD_FSDK_UninitialFaceEngine", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern int Close(IntPtr engine); } internal class Trace { private const string DllPath = "Libs/libarcsoft_fsdk_face_tracking.dll"; /// <summary> /// /// </summary> /// <param name="appId"></param> /// <param name="sdkKey"></param> /// <param name="buffer"></param> /// <param name="bufferSize"></param> /// <param name="engine"></param> /// <param name="orientPriority"></param> /// <param name="scale">最小人脸尺寸有效值范围[2,16] 推荐值 16。该尺寸是人脸相对于所在图片的长边的占比。例如,如果用户想检测到的最小人脸尺寸是图片长度的 1/8,那么这个 nScale 就应该设置为8</param> /// <param name="faceNumber">用户期望引擎最多能检测出的人脸数有效值范围[1,20]</param> /// <returns></returns>
[DllImport(DllPath, EntryPoint = "AFT_FSDK_InitialFaceEngine", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern int Init(string appId, string sdkKey, byte[] buffer, int bufferSize, out IntPtr engine, int orientPriority, int scale, int faceNumber); [DllImport(DllPath, EntryPoint = "AFT_FSDK_FaceFeatureDetect", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern int Detection(IntPtr engine, ref ImageData imgData, out IntPtr pTraceResult); [DllImport(DllPath, EntryPoint = "AFT_FSDK_UninitialFaceEngine", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern int Close(IntPtr engine); }

internal class Match

{

private const string DllPath = "Libs/libarcsoft_fsdk_face_recognition.dll";

[DllImport(DllPath, EntryPoint = "AFR_FSDK_InitialEngine", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

public static extern int Init(string appId, string sdkKey, byte[] buffer, int bufferSize, out IntPtr engine);

[DllImport(DllPath, EntryPoint = "AFR_FSDK_ExtractFRFeature", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

public static extern int ExtractFeature(IntPtr engine, ref ImageData imageData, ref FaceFeatureInput faceFeatureInput, out FaceModel pFaceModels);

[DllImport(DllPath, EntryPoint = "AFR_FSDK_FacePairMatching", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

public static extern int FacePairMatch(IntPtr engine, ref FaceModel faceModel1, ref FaceModel faceModel2, out float score);

[DllImport(DllPath, EntryPoint = "AFR_FSDK_UninitialEngine", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

public static extern int Close(IntPtr engine);

}

internal class Age

{

private const string DllPosition = "libs/libarcsoft_fsdk_age_estimation.dll";

[DllImport(DllPosition, EntryPoint = "ASAE_FSDK_InitAgeEngine", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

public static extern int Init(string appId, string sdkKey, byte[] buffer, int bufferSize, out IntPtr engine);

[DllImport(DllPosition, EntryPoint = "ASAE_FSDK_AgeEstimation_StaticImage", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

public static extern int EstimationStatic(IntPtr engine, ref ImageData imgData, ref EstimationInput estimationInputInput, out EstimationResult pAgeResult);

[DllImport(DllPosition, EntryPoint = "ASAE_FSDK_AgeEstimation_Preview", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

public static extern int EstimationPreview(IntPtr engine, ref ImageData imgData, ref EstimationInput estimationInputInput, out EstimationResult pAgeResult);

[DllImport(DllPosition, EntryPoint = "ASAE_FSDK_UninitAgeEngine", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

public static extern int Close(IntPtr engine);

}

internal class Gender

{

private const string DllPosition = "libs/libarcsoft_fsdk_gender_estimation.dll";

[DllImport(DllPosition, EntryPoint = "ASGE_FSDK_InitGenderEngine", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

public static extern int Init(string appId, string sdkKey, byte[] buffer, int bufferSize, out IntPtr engine);

[DllImport(DllPosition, EntryPoint = "ASGE_FSDK_GenderEstimation_StaticImage", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

public static extern int EstimationStatic(IntPtr engine, ref ImageData imgData, ref EstimationInput estimationInputInput, out EstimationResult pGenderResult);

[DllImport(DllPosition, EntryPoint = "ASGE_FSDK_GenderEstimation_Preview", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

public static extern int EstimationPreview(IntPtr engine, ref ImageData imgData, ref EstimationInput estimationInputInput, out EstimationResult pGenderResesult);

[DllImport(DllPosition, EntryPoint = "ASGE_FSDK_UninitGenderEngine", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]

public static extern int Close(IntPtr engine);

}

} `

二、正式开始

1.添加一个Form,将Name改为“Main”,添加Load和FormClosing事件 2.拖一个Afoge.Controls.VideoSourcePlayer到Main,将Name改为“VideoPlayer”,添加Click事件; 3.拖一个PictureBox到Main,懒得改名字了,就叫“pictureBox1”; 4.拖一个Lable到Main,将Text改为“ID”; 5.拖一个TextBox到Main,将Name改为“TextBoxID”; 6.拖一个Button到Main,将Name改为ButtonRegister,将Text改为“注册”,添加Click事件。 界面如下图,从左到右,从上到下6个控件:

对应的代码为:

`using AForge.Video.DirectShow; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using FaceRecognization.Common; using System.Runtime.InteropServices; using System.Diagnostics; using System.IO; using System.Threading; using System.Drawing.Imaging;

namespace FaceRecognization { public partial class Main : Form { #region Property /// <summary> /// 保存人脸数据的文件夹 /// </summary> const string FeaturePath = "d:\FeatureData"; /// <summary> /// 虹软SDK的AppId /// </summary> const string FaceAppId = "BKgqTWQPQQbomfqvyd2VJzTbzo5C4T5w4tzgN3GL6euK"; /// <summary> /// 虹软SDK人脸跟踪的Key /// </summary> const string FaceTraceKey = "2Yqm2EcsJyBbJjSrirPSNoyHDRKCrS53XgUDeRRxtKyR"; /// <summary> /// 虹软SDK人脸检测的Key /// </summary> const string FaceDetectKey = "2Yqm2EcsJyBbJjSrirPSNoyQNpaSJz19noCteLQ88SoG"; /// <summary> /// 虹软SDK人脸比对的Key /// </summary> const string FaceMatchKey = "2Yqm2EcsJyBbJjSrirPSNoyu2Rd4j1ydfwxwFX9vPmtY"; /// <summary> /// 虹软SDK年龄识别的Key /// </summary> const string FaceAgeKey = "2Yqm2EcsJyBbJjSrirPSNoz9ME9R4xnKU9yecD8Axu1D"; /// <summary> /// 虹软SDK性别识别的Key /// </summary> const string FaceGenderKey = "2Yqm2EcsJyBbJjSrirPSNozGWdQedYzhEUMw5FBegKVR"; /// <summary> /// 缓存大小 /// </summary> const int BufferSize = 40 * 1024 * 1024; /// <summary> /// 人脸跟踪的缓存 /// </summary> //byte[] _FaceTraceBuffer = new byte[BufferSize]; /// <summary> /// 人脸检测的缓存 /// </summary> byte[] _FaceDetectBuffer = new byte[BufferSize]; /// <summary> /// 人脸比对的缓存 /// </summary> byte[] _FaceMatchBuffer = new byte[BufferSize]; /// <summary> /// 年龄识别的缓存 /// </summary> //byte[] _FaceAgeBuffer = new byte[BufferSize]; /// <summary> /// 性别识别的缓存 /// </summary> //byte[] _FaceGenderBuffer = new byte[BufferSize]; /// <summary> /// 人脸跟踪的引擎 /// </summary> //IntPtr _FaceTraceEnginer = IntPtr.Zero; /// <summary> /// 人脸检测的引擎 /// </summary> IntPtr _FaceDetectEnginer = IntPtr.Zero; /// <summary> /// 人脸比对的引擎 /// </summary> IntPtr _FaceMatchEngine = IntPtr.Zero; /// <summary> /// 年龄识别的引擎 /// </summary> //IntPtr _FaceAgeEngine = IntPtr.Zero; /// <summary> /// 性别识别的引擎 /// </summary> //IntPtr _FaceGenderEngine = IntPtr.Zero; /// <summary> /// 人脸库字典 /// </summary> Face.FaceLib _FaceLib = new Face.FaceLib(); /// <summary> /// 摄像头参数 /// </summary> CameraPara _CameraPara = null; double _RateW, _RateH; private readonly ReaderWriterLockSlim _CacheLock = new ReaderWriterLockSlim(); Face.FaceResult _FaceResult = new Face.FaceResult(); System.Threading.CancellationTokenSource _CancellationTokenSource = new System.Threading.CancellationTokenSource(); bool _RegisterClicked = false; byte[] _RegisterFeatureData = null; #endregion public Main() { InitializeComponent(); }

    private void Main_Load(object sender, EventArgs e)

{

if (!Directory.Exists(FeaturePath))

Directory.CreateDirectory(FeaturePath);

foreach (var file in Directory.GetFiles(FeaturePath))

{

var info = new FileInfo(file);

var data = File.ReadAllBytes(file);

var faceModel = new Face.FaceModel

{

lFeatureSize = data.Length,

pbFeature = Marshal.AllocHGlobal(data.Length)

};

Marshal.Copy(data, 0, faceModel.pbFeature, data.Length);

_FaceLib.Items.Add(new Face.FaceLib.Item() { OrderId = 0, ID = info.Name.Replace(info.Extension, ""), FaceModel = faceModel });

}

_CameraPara = new Common.CameraPara();

if (!_CameraPara.HasVideoDevice)

{

MessageBox.Show("没有检测到摄像头");

this.Close();

return;

}

this.VideoPlayer.VideoSource = _CameraPara.VideoSource;

this.VideoPlayer.Start();

_RateH = 1.0 * this.VideoPlayer.Height / this._CameraPara.FrameHeight;

_RateW = 1.0 * this.VideoPlayer.Width / this._CameraPara.FrameWidth;

//var initResult = (Face.ErrorCode)Face.Trace.Init(FaceAppId, FaceTraceKey, _FaceTraceBuffer, BufferSize, out _FaceTraceEnginer, (int)Face.OrientPriority.Only0, 16, 1);

//if (initResult != Face.ErrorCode.Ok)

//{

// MessageBox.Show("初始化人脸跟踪引擎失败,错误代码为:" + initResult);

// this.Close();

// return;

//}

var initResult = (Face.ErrorCode)Face.Detect.Init(FaceAppId, FaceDetectKey, _FaceDetectBuffer, BufferSize, out _FaceDetectEnginer, (int)Face.OrientPriority.Only0, 16, 1);

if (initResult != Face.ErrorCode.Ok)

{

MessageBox.Show("初始化人脸检测引擎失败,错误代码为:" + initResult);

this.Close();

return;

}

initResult = (Face.ErrorCode)Face.Match.Init(FaceAppId, FaceMatchKey, _FaceMatchBuffer, BufferSize, out _FaceMatchEngine);

if (initResult != Face.ErrorCode.Ok)

{

MessageBox.Show("初始化人脸比对引擎失败,错误代码为:" + initResult);

this.Close();

return;

}

//initResult = (Face.ErrorCode)Face.Age.Init(FaceAppId, FaceAgeKey, _FaceAgeBuffer, BufferSize, out _FaceAgeEngine);

//if (initResult != Face.ErrorCode.Ok)

//{

// MessageBox.Show("初始化年龄识别引擎失败,错误代码为:" + initResult);

// this.Close();

// return;

//}

//initResult = (Face.ErrorCode)Face.Gender.Init(FaceAppId, FaceGenderKey, _FaceGenderBuffer, BufferSize, out _FaceGenderEngine);

//if (initResult != Face.ErrorCode.Ok)

//{

// MessageBox.Show("初始化性别识别引擎失败,错误代码为:" + initResult);

// this.Close();

// return;

//}

Task.Factory.StartNew(() =>

{

Task.Delay(1000).Wait();

while (!_CancellationTokenSource.IsCancellationRequested)

{

#region 200毫秒左右

MatchFrame();

#endregion

}

}, _CancellationTokenSource.Token);

}

private void Main_FormClosing(object sender, FormClosingEventArgs e)

{

if (_CameraPara.HasVideoDevice)

{

_CancellationTokenSource.Cancel();

System.Threading.Thread.Sleep(500);

this.VideoPlayer.Stop();

if (_FaceMatchEngine != IntPtr.Zero)

Face.Match.Close(_FaceMatchEngine);

//if (_FaceTraceEnginer != IntPtr.Zero)

// Face.Trace.Close(_FaceTraceEnginer);

if (_FaceDetectEnginer != IntPtr.Zero)

Face.Detect.Close(_FaceDetectEnginer);

//if (_FaceAgeEngine != IntPtr.Zero)

// Face.Age.Close(_FaceAgeEngine);

//if (_FaceGenderEngine != IntPtr.Zero)

// Face.Gender.Close(_FaceGenderEngine);

}

}

private void MatchFrame()

{

#region 获取图片 1毫秒

var bitmap = this.VideoPlayer.GetCurrentVideoFrame();

#endregion

Stopwatch sw = new Stopwatch();

sw.Start();

#region 图片转换 0.7-2微妙

var bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

var imageData = new Face.ImageData

{

u32PixelArrayFormat = 513,//Rgb24,

i32Width = bitmap.Width,

i32Height = bitmap.Height,

pi32Pitch = new int[4],

ppu8Plane = new IntPtr[4]

};

imageData.pi32Pitch[0] = bmpData.Stride;

imageData.ppu8Plane[0] = bmpData.Scan0;

sw.Stop();

_FaceResult.Score = sw.ElapsedTicks;

#endregion

try

{

#region 人脸检测 5-8毫秒

var ret = (Face.ErrorCode)Face.Detect.Detection(_FaceDetectEnginer, ref imageData, out var pDetectResult);

if (ret != Face.ErrorCode.Ok)

return;

var detectResult = Marshal.PtrToStructure<Face.DetectResult>(pDetectResult);

if (detectResult.nFace == 0)

return;

var faceRect = Marshal.PtrToStructure<Face.FaceRect>(detectResult.rcFace);

_FaceResult.Rectangle = new Rectangle((int)(faceRect.left * _RateW), (int)(faceRect.top * _RateH), (int)((faceRect.right - faceRect.left) * _RateW), (int)((faceRect.bottom - faceRect.top) * _RateH));

var faceOrient = Marshal.PtrToStructure<int>(detectResult.lfaceOrient);

#endregion

#region 性别识别基本准确 年龄识别误差太大,没什么应用场景

//Face.ExtraFaceInput faceInput = new Face.ExtraFaceInput()

//{

// lFaceNumber = facesDetect.nFace,

// pFaceRectArray = Marshal.AllocHGlobal(Marshal.SizeOf(faceRect)),

// pFaceOrientArray = Marshal.AllocHGlobal(Marshal.SizeOf(faceOrient))

//};

//Marshal.StructureToPtr(faceRect, faceInput.pFaceRectArray, false);

//Marshal.StructureToPtr(faceOrient, faceInput.pFaceOrientArray, false);

//var ageResult = Face.Age.ASAE_FSDK_AgeEstimation_Preview(_FaceAgeEngine, ref imageData, ref faceInput, out var pAgeRes);

//var ages = pAgeRes.pResult.ToStructArray<int>(pAgeRes.lFaceNumber);

//var genderResult = Face.Gender.ASGE_FSDK_GenderEstimation_Preview(_FaceGenderEngine, ref imageData, ref faceInput, out var pGenderRes);

//var genders = pGenderRes.pResult.ToStructArray<int>(pGenderRes.lFaceNumber);

//_FaceResult.Age = ages[0];

//_FaceResult.Gender = genders[0];

//Marshal.FreeHGlobal(faceInput.pFaceOrientArray);

//Marshal.FreeHGlobal(faceInput.pFaceRectArray);

#endregion

#region 获取人脸特征 160-180毫秒

var faceFeatureInput = new Face.FaceFeatureInput

{

rcFace = faceRect,

lOrient = faceOrient

};

ret = (Face.ErrorCode)Face.Match.ExtractFeature(_FaceMatchEngine, ref imageData, ref faceFeatureInput, out var faceModel);

#endregion

if (ret == Face.ErrorCode.Ok)

{

if (_RegisterClicked)

{

_RegisterFeatureData = new byte[faceModel.lFeatureSize];

Marshal.Copy(faceModel.pbFeature, _RegisterFeatureData, 0, faceModel.lFeatureSize);

}

#region 人脸识别(100张人脸) 17-20毫秒

foreach (var item in _FaceLib.Items.OrderByDescending(ii => ii.OrderId))

{

var fm = item.FaceModel;

Face.Match.FacePairMatch(_FaceMatchEngine, ref fm, ref faceModel, out float score);

if (score > 0.5)

{

item.OrderId = DateTime.Now.Ticks;

_FaceResult.ID = item.ID;

break;

}

}

#endregion

}

}

finally

{

bitmap.UnlockBits(bmpData);

if (_RegisterClicked)

{

this.pictureBox1.Invoke(new Action(() =>

{

this.pictureBox1.Image = bitmap;

}));

_RegisterClicked = false;

}

else

{

bitmap.Dispose();

}

}

}

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);

}

private void VideoPlayer_Click(object sender, EventArgs e)

{

_RegisterFeatureData = null;

_RegisterClicked = true;

this.TextBoxID.Text = _FaceResult.ID;

}

private void ButtonRegister_Click(object sender, EventArgs e)

{

if (_RegisterFeatureData == null)

{

MessageBox.Show("没有人脸数据,请面对摄像头并点击视频");

return;

}

if (string.IsNullOrEmpty(this.TextBoxID.Text))

{

MessageBox.Show("请输入Id");

this.TextBoxID.Focus();

return;

}

var fileName = FeaturePath + "\\" + this.TextBoxID.Text + ".dat";

if (System.IO.File.Exists(fileName))

{

if (MessageBox.Show($"您要替换[{this.TextBoxID.Text}]的人脸数据吗?", "咨询", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) == DialogResult.No)

return;

}

System.IO.File.WriteAllBytes(fileName, _RegisterFeatureData);

var faceModel = new Face.FaceModel

{

lFeatureSize = _RegisterFeatureData.Length,

pbFeature = Marshal.AllocHGlobal(_RegisterFeatureData.Length)

};

Marshal.Copy(_RegisterFeatureData, 0, faceModel.pbFeature, _RegisterFeatureData.Length);

_FaceLib.Items.Add(new Face.FaceLib.Item() { OrderId = DateTime.Now.Ticks, ID = this.TextBoxID.Text, FaceModel = faceModel });

}

}

} `

三、运行

按F5运行,能给最大的人脸画框,如比对通过显示框上面显示ID 1.点击 视频; 2.输入 ID 3.点击 注册

以上是 C#基于Arcface人脸识别SDK完成人脸识别和注册 的全部内容, 来源链接: utcz.com/z/508942.html

回到顶部