美文网首页
C# 基于Arcface SDK实现人脸识别和注册

C# 基于Arcface SDK实现人脸识别和注册

作者: workhard_ | 来源:发表于2019-05-30 13:36 被阅读0次

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

    一,准备工作

    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实现人脸识别和注册

          本文链接:https://www.haomeiwen.com/subject/eknmtctx.html