整個項目使用虹軟技術完成開發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.點擊 註冊