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


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

    一,准备工作

    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复制的debugLibs文件夹或releaseLibs文件夹

    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个控件:
    ![在这里插入图片描述](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 });
    
    }
    
     
    
    
    }
    }
    

      

    三、运行

    按F5运行,能给最大的人脸画框,如比对通过显示框上面显示ID

    1.点击 视频;

    2.输入 ID

    3.点击 注册

  • 相关阅读:
    webView的缩放效果配置
    Tips:cell的选中类型修改
    纸牌生成算法(随机数组)
    Couldn’t communicate with a helper application.
    标记:音频扬声器+听筒切换
    向企业账号内添加开发者账号
    (四期)简单添加TableViewCell的3D动画效果
    (三期)Hybrid混合开发之Appcan技术
    (二期)IOS调试技巧
    openresty(lua)调试
  • 原文地址:https://www.cnblogs.com/Zzz-/p/10949029.html
Copyright © 2020-2023  润新知