C# 基於Arcface SDK實現人臉識別和註冊

整個項目使用虹軟技術完成開發java

一,準備工做緩存

1.Afoge視頻參數類app

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.人臉識別相關的結構、類 和枚舉ide

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封裝ui

注意要把相應的dll複製的debug\Libs文件夾或release\Libs文件夾this

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

  

2、正式開始spa

1.添加一個Form,將Name改成「Main」,添加Load和FormClosing事件pwa

2.拖一個Afoge.Controls.VideoSourcePlayer到Main,將Name改成「VideoPlayer」,添加Click事件;debug

3.拖一個PictureBox到Main,懶得更名字了,就叫「pictureBox1」;orm

4.拖一個Lable到Main,將Text改成「ID」;

5.拖一個TextBox到Main,將Name改成「TextBoxID」;

6.拖一個Button到Main,將Name改成ButtonRegister,將Text改成「註冊」,添加Click事件。

界面以下圖,從左到右,從上到下6個控件:
![在這裏插入圖片描述](https://images2018.cnblogs.com/blog/10915/201804/10915-20180418182709507-1552751980.png)
對應的代碼爲:

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

}

 


}
}

  

3、運行

按F5運行,能給最大的人臉畫框,如比對經過顯示框上面顯示ID

1.點擊 視頻;

2.輸入 ID

3.點擊 註冊

相關文章
相關標籤/搜索