public static void Close() { if (_DEnginer != IntPtr.Zero) { ArcWrapper.DClose(_DEnginer); _DEnginer = IntPtr.Zero; } if (_DBuffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(_DBuffer); _DBuffer = IntPtr.Zero; } for (int i = 0; i < TaskNum; i++) { if (_REngine[i] != IntPtr.Zero) { ArcWrapper.RClose(_REngine[i]); _REngine[i] = IntPtr.Zero; } if (_RBuffer[i] != IntPtr.Zero) { Marshal.FreeCoTaskMem(_RBuffer[i]); _RBuffer[i] = IntPtr.Zero; } foreach (var item in _FaceLib[i].Items) { Marshal.FreeCoTaskMem(item.FaceModel.PFeature); } } foreach (var item in CacheFaceResults.Items) { Marshal.FreeCoTaskMem(item.FaceModel.PFeature); } }
/// <summary> /// 初始化 /// </summary> /// <param name="appId">虹软SDK的AppId</param> /// <param name="dKey">虹软SDK人脸检测的Key</param> /// <param name="rKey">虹软SDK人脸比对的Key</param> /// <param name="orientPriority">脸部角度,毋宁说是鼻子方向,上下为0或180度,左右为90或270度</param> /// <param name="scale">最小人脸尺寸有效值范围[2,50] 推荐值 16。该尺寸是人脸相对于所在图片的长边的占比。例如,如果用户想检测到的最小人脸尺寸是图片长度的 1/8,那么这个 scale 就应该设置为8</param> /// <param name="maxFaceNumber">用户期望引擎最多能检测出的人脸数有效值范围[1,100]</param> /// <param name="faceDataPath">人脸数据文件夹</param> /// <param name="rateH">视频图片采集高度和显示高度的比值</param> /// <param name="rateW">视频图片采集宽度和显示宽度的比值</param> /// <param name="message"></param> /// <returns></returns> public static bool Init(out string message, string appId, string dKey, string rKey, EOrientPriority orientPriority = EOrientPriority.Ext0, int scale = 16, int maxFaceNumber = 10, string faceDataPath = "d:\\FeatureData") { if (scale < 2 || scale > 50) { message = "scale的值必须在2-50之间"; return(false); } if (maxFaceNumber < 1 || maxFaceNumber > 100) { message = "maxFaceNumber的值必须在1-100之间"; return(false); } _DBuffer = Marshal.AllocCoTaskMem(20 * 1024 * 1024); _RBuffer = Marshal.AllocCoTaskMem(40 * 1024 * 1024); var initResult = (ErrorCode)ArcWrapper.DInit(appId, dKey, _DBuffer, 20 * 1024 * 1024, out _DEnginer, (int)orientPriority, scale, maxFaceNumber); if (initResult != ErrorCode.Ok) { message = $"初始化人脸检测引擎失败,错误代码:{(int)initResult},错误描述:{ ((DescriptionAttribute)(initResult.GetType().GetCustomAttribute(typeof(DescriptionAttribute), false))).Description}"; return(false); } initResult = (ErrorCode)ArcWrapper.RInit(appId, rKey, _RBuffer, 40 * 1024 * 1024, out _REngine); if (initResult != ErrorCode.Ok) { message = $"初始化人脸比对引擎失败,错误代码:{(int)initResult},错误描述:{ ((DescriptionAttribute)(initResult.GetType().GetCustomAttribute(typeof(DescriptionAttribute), false))).Description}"; return(false); } FaceResults = new FaceResults(maxFaceNumber); _FaceDataPath = faceDataPath; if (!Directory.Exists(faceDataPath)) { Directory.CreateDirectory(faceDataPath); } else { foreach (var file in Directory.GetFiles(faceDataPath)) { var info = new FileInfo(file); var data = File.ReadAllBytes(file); var faceModel = new FaceModel { lFeatureSize = data.Length, pbFeature = Marshal.AllocCoTaskMem(data.Length) }; Marshal.Copy(data, 0, faceModel.pbFeature, data.Length); _FaceLib.Items.Add(new FaceLib.Item() { OrderId = 0, ID = info.Name.Replace(info.Extension, ""), FaceModel = faceModel }); } } _MaxFaceNumber = maxFaceNumber; message = "初始化成功"; return(true); }
public static void Close() { if (_DEnginer != IntPtr.Zero) { ArcWrapper.DClose(_DEnginer); _DEnginer = IntPtr.Zero; } if (_REngine != IntPtr.Zero) { ArcWrapper.RClose(_REngine); _REngine = IntPtr.Zero; } if (_DBuffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(_DBuffer); _DBuffer = IntPtr.Zero; Marshal.FreeCoTaskMem(_RBuffer); _RBuffer = IntPtr.Zero; } foreach (var item in _FaceLib.Items) { Marshal.FreeCoTaskMem(item.FaceModel.pbFeature); } }
/// <summary> /// 初始化,主要用于视频,取消人脸方向参数 /// </summary> /// <param name="appId">虹软SDK的AppId</param> /// <param name="dKey">虹软SDK人脸检测的Key</param> /// <param name="rKey">虹软SDK人脸比对的Key</param> /// <param name="orientPriority">脸部角度,毋宁说是鼻子方向,上下为0或180度,左右为90或270度</param> /// <param name="scale">最小人脸尺寸有效值范围[2,50] 推荐值 16。该尺寸是人脸相对于所在图片的长边的占比。例如,如果用户想检测到的最小人脸尺寸是图片长度的 1/8,那么这个 scale 就应该设置为8</param> /// <param name="maxFaceNumber">用户期望引擎最多能检测出的人脸数有效值范围[1,100]</param> /// <param name="faceDataPath">人脸数据文件夹</param> /// <param name="message"></param> /// <returns></returns> public static bool Init(out string message, string appId, string dKey, string rKey, int scale = 50, int maxFaceNumber = 10, string faceDataPath = "d:\\FeatureData") { if (scale < 2 || scale > 50) { message = "scale的值必须在2-50之间"; return(false); } if (maxFaceNumber < 1 || maxFaceNumber > 100) { message = "人脸数量必须在1-100之间"; return(false); } _DBuffer = Marshal.AllocCoTaskMem(20 * 1024 * 1024); var initResult = (ErrorCode)ArcWrapper.DInit(appId, dKey, _DBuffer, 20 * 1024 * 1024, out _DEnginer, (int)ArcFace.EOrientPriority.Only0, scale, maxFaceNumber); if (initResult != ErrorCode.Ok) { message = $"初始化人脸检测引擎失败,错误代码:{(int)initResult},错误描述:{ initResult.GetType().GetMember(initResult.ToString()).FirstOrDefault()?.GetCustomAttribute<DescriptionAttribute>().Description ?? initResult.ToString()}"; return(false); } for (int i = 0; i < TaskNum; i++) { _RBuffer[i] = Marshal.AllocCoTaskMem(40 * 1024 * 1024); initResult = (ErrorCode)ArcWrapper.RInit(appId, rKey, _RBuffer[i], 40 * 1024 * 1024, out _REngine[i]); if (initResult != ErrorCode.Ok) { message = $"初始化人脸比对引擎失败,错误代码:{(int)initResult},错误描述:{ initResult.GetType().GetMember(initResult.ToString()).FirstOrDefault()?.GetCustomAttribute<DescriptionAttribute>().Description ?? initResult.ToString()}"; return(false); } _FaceLib[i] = new FaceLib(); } CacheFaceResults = new FaceResults(maxFaceNumber); _MaxFaceNumber = maxFaceNumber; _FaceDataPath = faceDataPath; _FaceImagePath = Path.Combine(_FaceDataPath, "Image"); if (!Directory.Exists(faceDataPath)) { Directory.CreateDirectory(faceDataPath); } if (!Directory.Exists(_FaceImagePath)) { Directory.CreateDirectory(_FaceImagePath); } int index = 0; for (int i = 0; i < 100; i++) { foreach (var file in Directory.GetFiles(faceDataPath)) { var info = new FileInfo(file); var data = File.ReadAllBytes(file); var pFeature = Marshal.AllocCoTaskMem(data.Length); Marshal.Copy(data, 0, pFeature, data.Length); _FaceLib[index % TaskNum].Items.Add(new FaceLib.Item() { OrderId = 0, ID = info.Name.Replace(info.Extension, ""), FaceModel = new FaceModel { Size = FeatureSize, PFeature = pFeature } }); index++; } } message = "初始化成功"; return(true); }
/// <summary> /// 人脸比对 /// </summary> /// <param name="bitmap">输入图片</param> public static void FaceMatch(Bitmap bitmap) { 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 } }; var ret = (ErrorCode)ArcWrapper.Detection(_DEnginer, ref imageData, out pDetectResult); if (ret != ErrorCode.Ok) { bitmap.UnlockBits(bmpData); return; } var detectResult = Marshal.PtrToStructure <DetectResult>(pDetectResult); CacheFaceResults.FaceNumber = detectResult.FaceCout; for (int i = detectResult.FaceCout; i < _MaxFaceNumber; i++) { CacheFaceResults[i].ID = ""; } if (detectResult.FaceCout == 0) { bitmap.UnlockBits(bmpData); return; } if (detectResult.FaceCout == 1) { CacheFaceResults[0].FFI.FaceRect = Marshal.PtrToStructure <FaceRect>(detectResult.PFaceRect); if (ArcWrapper.ExtractFeature(_REngine[0], ref imageData, ref CacheFaceResults[0].FFI, out fm) == (int)ErrorCode.Ok) { ArcWrapper.CopyMemory(CacheFaceResults.Items[0].FaceModel.PFeature, fm.PFeature, FeatureSize); } } else { Task[] ts = new Task[TaskNum < detectResult.FaceCout ? TaskNum : detectResult.FaceCout]; int faceOffset = -1; for (int i = 0; i < ts.Length; i++) { var rEngine = _REngine[i]; ts[i] = Task.Factory.StartNew(() => { int faceIndex = 0; while ((faceIndex = Interlocked.Increment(ref faceOffset)) < detectResult.FaceCout) { CacheFaceResults[faceIndex].FFI.FaceRect = Marshal.PtrToStructure <FaceRect>(IntPtr.Add(detectResult.PFaceRect, faceIndex * Marshal.SizeOf <FaceRect>())); if (ArcWrapper.ExtractFeature(rEngine, ref imageData, ref CacheFaceResults[faceIndex].FFI, out fm) == (int)ErrorCode.Ok) { ArcWrapper.CopyMemory(CacheFaceResults.Items[faceIndex].FaceModel.PFeature, fm.PFeature, FeatureSize); } } }); } Task.WaitAll(ts); } bitmap.UnlockBits(bmpData); var tsr = new Task[TaskNum]; List <int> noMatchFaces = Enumerable.Range(0, detectResult.FaceCout).ToList(); for (int i = 0; i < TaskNum; i++) { var taskIndex = i; tsr[i] = Task.Factory.StartNew(() => { var rEngine = _REngine[taskIndex]; foreach (var item in _FaceLib[taskIndex].Items.OrderByDescending(ii => ii.OrderId)) { _RWL.EnterReadLock(); if (noMatchFaces.Count == 0) { _RWL.ExitReadLock(); break; } var faceIndexs = noMatchFaces.ToList(); _RWL.ExitReadLock(); foreach (var faceIndex in faceIndexs) { ArcWrapper.Match(rEngine, ref CacheFaceResults.Items[faceIndex].FaceModel, ref item.FaceModel, out score); if (score > 0.55) { _RWL.EnterWriteLock(); noMatchFaces.Remove(faceIndex); _RWL.ExitWriteLock(); CacheFaceResults[faceIndex].ID = item.ID; CacheFaceResults[faceIndex].Score = score; item.OrderId = DateTime.Now.Ticks; } } } }); } Task.WaitAll(tsr); foreach (var faceIndex in noMatchFaces) { CacheFaceResults[faceIndex].ID = ""; CacheFaceResults[faceIndex].Score = 0; } }
/// <summary> /// 人脸比对 /// </summary> /// <param name="bitmap">输入图片</param> /// <param name="featureDataIndex">需要转换人脸特征的序号</param> public static void FaceMatch(Bitmap bitmap, int featureDataIndex = -1) { var bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb); var imageData = new 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; try { var ret = (ErrorCode)ArcWrapper.Detection(_DEnginer, ref imageData, out var pDetectResult); if (ret != ErrorCode.Ok) { return; } var detectResult = Marshal.PtrToStructure <DetectResult>(pDetectResult); FaceResults.FaceNumber = detectResult.nFace; if (detectResult.nFace == 0) { return; } for (int i = 0; i < detectResult.nFace; i++) { IntPtr p = new IntPtr(detectResult.rcFace.ToInt32() + i * Marshal.SizeOf <FaceRect>()); var faceRect = Marshal.PtrToStructure <FaceRect>(p); FaceResults[i].Rectangle = new Rectangle(faceRect.left, faceRect.top, faceRect.right - faceRect.left, faceRect.bottom - faceRect.top); p = new IntPtr(detectResult.lfaceOrient.ToInt32() + i * Marshal.SizeOf <int>()); var faceOrient = Marshal.PtrToStructure <int>(p); var faceFeatureInput = new FaceFeatureInput { rcFace = faceRect, lOrient = faceOrient }; if ((ErrorCode)ArcWrapper.ExtractFeature(_REngine, ref imageData, ref faceFeatureInput, out var faceModel) != ErrorCode.Ok) { continue; } if (featureDataIndex == i) { if (FaceResults[i].FeatureData == null) { FaceResults[i].FeatureData = new byte[faceModel.lFeatureSize]; } Marshal.Copy(faceModel.pbFeature, FaceResults[i].FeatureData, 0, faceModel.lFeatureSize); } bool matched = false; foreach (var item in _FaceLib.Items.OrderByDescending(ii => ii.OrderId)) { var fm = item.FaceModel; ArcWrapper.Match(_REngine, ref fm, ref faceModel, out float score); if (score > 0.5) { matched = true; item.OrderId = DateTime.Now.Ticks; FaceResults[i].ID = item.ID; FaceResults[i].Score = score; break; } } if (!matched) { FaceResults[i].ID = "不认识"; FaceResults[i].Score = 0; } } } finally { bitmap.UnlockBits(bmpData); } }