添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
上一篇文章 https://blog.xgcos.com/show/306.html 已经介绍了如何注册申请虹软的人脸识别SDK,也总结过虹软的SDK是VC++封装的,说明文档也都是VC++的调用方式,这対使用其他变成语言的小伙伴来说可能就遇到难题了。这篇文章最主要是介绍研究如何通过C#也能调用,并且提供一个人脸识别的DEMO供大家学习,现在进入正题,介绍一下C#是通过什么方式来引用C++的SDK动态链接库。 首先我们先来理解一个关键字 DllImport ,顾名思义就是把DLL加载到程序的意思。首先看下面一段代码:
[DllImport("libarcsoft_fsdk_face_detection.dll", EntryPoint = "AFD_FSDK_InitialFaceEngine", CallingConvention = CallingConvention.Cdecl)]
这段代码的意思就是引入了 libarcsoft_fsdk_face_detection.dll 这个动态链接库 ,然后再通过堆栈可变参数数目的方式调用函数 AFD_FSDK_InitialFaceEngine 通过这样的方式咋们就可以引用动态库中开放的所有函数,所以我们通过这种方式把动态库包装了一遍供C#方便调用,参照以下代码: AFDFUnction32.cs类
public class AFDFunction32
        /// <summary>
        /// 初始化脸部检测引擎
        /// </summary>
        /// <param name="appId">用户申请SDK时获取的AppId</param>
        /// <param name="sdkKey">用户申请 SDK 时获取的 SDK Key</param>
        /// <param name="pMem">分配给引擎使用的内存地址</param>
        /// <param name="lMemSize">分配给引擎使用的内存大小</param>
        /// <param name="pEngine">引擎 handle</param>
        /// <param name="iOrientPriority">期望的脸部检测角度的优先级</param>
        /// <param name="nScale">用于数值表示的最小人脸尺寸 有效值范围[2,50] 推荐值 16</param>
        /// <param name="nMaxFaceNum">用户期望引擎最多能检测出的人脸数 有效值范围[1,100]</param>
        /// <returns></returns>
        [DllImport("libarcsoft_fsdk_face_detection.dll", EntryPoint = "AFD_FSDK_InitialFaceEngine", CallingConvention = CallingConvention.Cdecl)]
        public static extern int AFD_FSDK_InitialFaceEngine(string AppId, string SDKKey, IntPtr pMem, int lMemSize, ref IntPtr pEngine, int iOrientPriority, int nScale, int nMaxFaceNum);
        /// <summary>
        /// 根据输入的图像检测出人脸位置,一般用于静态图像检测
        /// </summary>
        /// <param name="pEngine">引擎 handle</param>
        /// <param name="pImgData">带检测图像信息</param>
        /// <param name="pFaceRes">人脸检测结果</param>
        /// <returns></returns>
        [DllImport("libarcsoft_fsdk_face_detection.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int AFD_FSDK_StillImageFaceDetection(IntPtr pEngine, IntPtr pImgData, ref IntPtr pFaceRes);
        /// <summary>
        /// 销毁引擎,释放相应资源
        /// </summary>
        /// <param name="pEngine">引擎 handle</param>
        /// <returns></returns>
        [DllImport("libarcsoft_fsdk_face_detection.dll", CallingConvention = CallingConvention.Cdecl)]
        public static extern int AFD_FSDK_UninitialFaceEngine(IntPtr pEngine);
    AFRFUnction32.cs类 
public class AFRFunction32
        /// <summary>
        /// 初始化引擎
        /// </summary>
        /// <param name="appId">用户申请SDK时获取的AppId</param>
        /// <param name="sdkKey">用户申请 SDK 时获取的 SDK Key</param>
        /// <param name="pMem">分配给引擎使用的内存地址</param>
        /// <param name="lMemSize">分配给引擎使用的内存大小</param>
        /// <param name="pEngine">引擎 handle</param>
        /// <returns></returns>
        [DllImport("libarcsoft_fsdk_face_recognition.dll", EntryPoint = "AFR_FSDK_InitialEngine", CallingConvention = CallingConvention.Cdecl)]
        public static extern int AFR_FSDK_InitialEngine(string AppId, string SDKKey, IntPtr pMem, int lMemSize, ref IntPtr phEngine);
        /// <summary>
        /// 获取脸部特征
        /// </summary>
        /// <param name="hEngine">引擎 handle</param>
        /// <param name="pInputImage">输入的图像数据</param>
        /// <param name="pFaceRes">已检测到到的脸部信息</param>
        /// <param name="pFaceModels">提取的脸部特征信息</param>
        /// <returns></returns>
        [DllImport("libarcsoft_fsdk_face_recognition.dll", EntryPoint = "AFR_FSDK_ExtractFRFeature", CallingConvention = CallingConvention.Cdecl)]
        public static extern int AFR_FSDK_ExtractFRFeature(IntPtr hEngine, IntPtr pInputImage, IntPtr pFaceRes, IntPtr pFaceModels);
        /// <summary>
        /// 脸部特征比较
        /// </summary>
        /// <param name="hEngine">引擎 handle</param>
        /// <param name="reffeature">已有脸部特征信息</param>
        /// <param name="probefeature">被比较的脸部特征信息</param>
        /// <param name="pfSimilScore">相似程度数值</param>
        /// <returns></returns>
        [DllImport("libarcsoft_fsdk_face_recognition.dll", EntryPoint = "AFR_FSDK_FacePairMatching", CallingConvention = CallingConvention.Cdecl)]
        public static extern int AFR_FSDK_FacePairMatching(IntPtr hEngine, IntPtr reffeature, IntPtr probefeature, ref float pfSimilScore);
        /// <summary>
        /// 销毁引擎,释放相应资源
        /// </summary>
        /// <param name="hEngine">引擎 handle</param>
        /// <returns></returns>
        [DllImport("libarcsoft_fsdk_face_recognition", EntryPoint = "AFR_FSDK_UninitialEngine", CallingConvention = CallingConvention.Cdecl)]
        public static extern int AFR_FSDK_UninitialEngine(IntPtr hEngine);
	通过这样的封装,我们就能通过C#调用C++中的函数,但细心一点的骚年发现很多都是IntPtr类型,这个类型日常使用C#都很少用到呀。IntPtr类型称为“平台特定的整数类型”,它们用于本机资源,如窗口句柄。资源的大小取决于使用的硬件和操作系统,但其大小总是足以包含系统的指针。对C++有所了解的骚年都知道C++的指针概念,在C#这种高级的面向对象语言已经舍弃了指针改用对象(虽然还可以用unsafe的方式使用指针),所以C#这个变量可以引用C++中的指针类型,但貌似这种封装还不够通俗,所以小西瓜再封装了一层。 
	    ARCFace.cs类 
        string appId32 = "替换你的APPID";
        string sdkFDKey32 = "替换你的FDKEY";
        string sdkFRKey32 = "替换你的FRKEY";
        int Size = 40 * 1024 * 1024;
        int nScale = 16;
        int nMaxFaceNum = 5;
        public ArcFace()
        /// <summary>
        /// 获取图片中的人脸数目
        /// </summary>
        /// <param name="imageData">图片流数据</param>
        /// <param name="faceCount">返回人脸数</param>
        /// <returns>0为调用成功,其他返回错误码</returns>
        public int GetImageFaceCount(byte[] imageData, ref int faceCount)
            ArcStruct.AFD_FSDK_FACERES faceRes = new ArcStruct.AFD_FSDK_FACERES();
            int res = 0;
            IntPtr pem = new IntPtr();
            res = GetStillImageFaceDetection32(BytesToBitmap(imageData), ref faceRes, ref pem);
            if (res == 0)
                faceCount = faceRes.nFace;
                faceCount = 0;
            Marshal.FreeHGlobal(pem);
            return res;
        /// <summary>
        /// 比对图片
        /// </summary>
        /// <param name="imageData1">图片1流数据</param>
        /// <param name="imageData2">图片2流数据</param>
        /// <param name="similscore">返回相似度</param>
        /// <returns>0为调用成功,-1为检测图片人脸失败,其他返回错误码</returns>
        public int FaceMatching(Bitmap b1, Bitmap b2, ref float similscore)
            similscore = 0f;
            ArcStruct.AFD_FSDK_FACERES faceRes1 = new ArcStruct.AFD_FSDK_FACERES();
            ArcStruct.AFD_FSDK_FACERES faceRes2 = new ArcStruct.AFD_FSDK_FACERES();
            IntPtr pem1 = new IntPtr();
            IntPtr pem2 = new IntPtr();
            int res = GetStillImageFaceDetection32(b1, ref faceRes1, ref pem1);
            if (res != 0)
                Marshal.FreeHGlobal(pem1);
                return res;
            res = GetStillImageFaceDetection32(b2, ref faceRes2, ref pem2);
            if (res != 0)
                Marshal.FreeHGlobal(pem1);
                Marshal.FreeHGlobal(pem2);
                return res;
            if (faceRes1.nFace == 1 && faceRes2.nFace == 1)
                ArcStruct.AFR_FSDK_FaceModel faceModel1 = new ArcStruct.AFR_FSDK_FaceModel();
                ArcStruct.AFR_FSDK_FaceModel faceModel2 = new ArcStruct.AFR_FSDK_FaceModel();
                IntPtr pemM1 = new IntPtr();
                IntPtr pemM2 = new IntPtr();
                int mres = GetFaceModel32(b1, faceRes1, ref faceModel1, ref pemM1);
                if (mres != 0)
                    Marshal.FreeHGlobal(pem1);
                    Marshal.FreeHGlobal(pem2);
                    Marshal.FreeHGlobal(pemM1);
                    return mres;
                mres = GetFaceModel32(b2, faceRes2, ref faceModel2, ref pemM2);
                if (mres != 0)
                    Marshal.FreeHGlobal(pem1);
                    Marshal.FreeHGlobal(pem2);
                    Marshal.FreeHGlobal(pemM1);
                    Marshal.FreeHGlobal(pemM2);
                    return mres;
                int ret = FacePairMatching32(faceModel1, faceModel2, ref similscore);
                Marshal.FreeHGlobal(pem1);
                Marshal.FreeHGlobal(pem2);
                Marshal.FreeHGlobal(pemM1);
                Marshal.FreeHGlobal(pemM2);
                return ret;
                Marshal.FreeHGlobal(pem1);
                Marshal.FreeHGlobal(pem2);
                return -1;
        private Bitmap BytesToBitmap(byte[] Bytes)
            MemoryStream stream = null;
                stream = new MemoryStream(Bytes);
                System.Drawing.Image returnImage = System.Drawing.Image.FromStream(stream);
                stream.Flush();
                Bitmap bmp = (Bitmap)returnImage;
                return bmp;
            catch (ArgumentNullException ex)
                throw ex;
            catch (ArgumentException ex)
                throw ex;
            finally
                stream.Close();
        private int GetStillImageFaceDetection32(Bitmap bitmap, ref ArcStruct.AFD_FSDK_FACERES faceRes)
            IntPtr detectEngine = IntPtr.Zero;
            IntPtr pMem = Marshal.AllocHGlobal(Size);
            int retCode = AFDFunction32.AFD_FSDK_InitialFaceEngine(appId32, sdkFDKey32, pMem, Size, ref detectEngine, (int)ArcStruct.AFD_FSDK_OrientPriority.AFD_FSDK_OPF_0_HIGHER_EXT, nScale, nMaxFaceNum);
            if (retCode != 0)
                return retCode;
            ArcStruct.ASVLOFFSCREEN offInput = GetOffInput(bitmap);
            IntPtr offInputPtr = Marshal.AllocHGlobal(Marshal.SizeOf(offInput));
            Marshal.StructureToPtr(offInput, offInputPtr, false);
            faceRes = new ArcStruct.AFD_FSDK_FACERES();
            IntPtr faceResPtr = Marshal.AllocHGlobal(Marshal.SizeOf(faceRes));
            int detectResult = AFDFunction32.AFD_FSDK_StillImageFaceDetection(detectEngine, offInputPtr, ref faceResPtr);
            if (detectResult == 0)
                faceRes = (ArcStruct.AFD_FSDK_FACERES)Marshal.PtrToStructure(faceResPtr, typeof(ArcStruct.AFD_FSDK_FACERES));
                AFDFunction32.AFD_FSDK_UninitialFaceEngine(detectEngine);
                Marshal.FreeHGlobal(offInputPtr);
                Marshal.FreeHGlobal(pMem);
                return 0;
                AFDFunction32.AFD_FSDK_UninitialFaceEngine(detectEngine);
                Marshal.FreeHGlobal(offInputPtr);
                Marshal.FreeHGlobal(pMem);
                return detectResult;
        private int GetStillImageFaceDetection32(Bitmap bitmap, ref ArcStruct.AFD_FSDK_FACERES faceRes, ref IntPtr pMem)
            IntPtr detectEngine = IntPtr.Zero;
            pMem = Marshal.AllocHGlobal(Size);
            int retCode = AFDFunction32.AFD_FSDK_InitialFaceEngine(appId32, sdkFDKey32, pMem, Size, ref detectEngine, (int)ArcStruct.AFD_FSDK_OrientPriority.AFD_FSDK_OPF_0_HIGHER_EXT, nScale, nMaxFaceNum);
            if (retCode != 0)
                return retCode;
            ArcStruct.ASVLOFFSCREEN offInput = GetOffInput(bitmap);
            IntPtr offInputPtr = Marshal.AllocHGlobal(Marshal.SizeOf(offInput));
            Marshal.StructureToPtr(offInput, offInputPtr, false);
            faceRes = new ArcStruct.AFD_FSDK_FACERES();
            IntPtr faceResPtr = Marshal.AllocHGlobal(Marshal.SizeOf(faceRes));
            int detectResult = AFDFunction32.AFD_FSDK_StillImageFaceDetection(detectEngine, offInputPtr, ref faceResPtr);
            if (detectResult == 0)
                faceRes = (ArcStruct.AFD_FSDK_FACERES)Marshal.PtrToStructure(faceResPtr, typeof(ArcStruct.AFD_FSDK_FACERES));
                AFDFunction32.AFD_FSDK_UninitialFaceEngine(detectEngine);
                Marshal.FreeHGlobal(offInputPtr);
                return 0;
                AFDFunction32.AFD_FSDK_UninitialFaceEngine(detectEngine);
                Marshal.FreeHGlobal(offInputPtr);
                return detectResult;
        private int GetFaceModel32(Bitmap bitmap, ArcStruct.AFD_FSDK_FACERES faceRes, ref ArcStruct.AFR_FSDK_FaceModel faceModel, ref IntPtr pMem)
            IntPtr recognizeEngine = IntPtr.Zero;
            pMem = Marshal.AllocHGlobal(Size);
            int retCode = AFRFunction32.AFR_FSDK_InitialEngine(appId32, sdkFRKey32, pMem, Size, ref recognizeEngine);
            if (retCode != 0)
                return retCode;
            ArcStruct.AFR_FSDK_FaceInput faceinput = new ArcStruct.AFR_FSDK_FaceInput();
            faceinput.lOrient = (int)Marshal.PtrToStructure(faceRes.lfaceOrient, typeof(int));
            long longPtr = faceRes.rcFace.ToInt64();
            IntPtr rectPtr = new IntPtr(longPtr);
            ArcStruct.MRECT rect = (ArcStruct.MRECT)Marshal.PtrToStructure(rectPtr, typeof(ArcStruct.MRECT));
            faceinput.rcFace = rect;
            IntPtr faceInputPtr = Marshal.AllocHGlobal(Marshal.SizeOf(faceinput));
            Marshal.StructureToPtr(faceinput, faceInputPtr, false);
            faceModel = new ArcStruct.AFR_FSDK_FaceModel();
            IntPtr faceModelPtr = Marshal.AllocHGlobal(Marshal.SizeOf(faceModel));
            ArcStruct.ASVLOFFSCREEN offInput = GetOffInput(bitmap);
            IntPtr offInputPtr = Marshal.AllocHGlobal(Marshal.SizeOf(offInput));
            Marshal.StructureToPtr(offInput, offInputPtr, false);
            int ret = AFRFunction32.AFR_FSDK_ExtractFRFeature(recognizeEngine, offInputPtr, faceInputPtr, faceModelPtr);
            if (ret == 0)
                faceModel = (ArcStruct.AFR_FSDK_FaceModel)Marshal.PtrToStructure(faceModelPtr, typeof(ArcStruct.AFR_FSDK_FaceModel));
                Marshal.FreeHGlobal(faceModelPtr);
                byte[] featureContent = new byte[faceModel.lFeatureSize];
                Marshal.Copy(faceModel.pbFeature, featureContent, 0, faceModel.lFeatureSize);
                AFRFunction32.AFR_FSDK_UninitialEngine(recognizeEngine);
                return 0;
                AFRFunction32.AFR_FSDK_UninitialEngine(recognizeEngine);
                Marshal.FreeHGlobal(faceModelPtr);
                return ret;
        private int FacePairMatching32(ArcStruct.AFR_FSDK_FaceModel faceModel1, ArcStruct.AFR_FSDK_FaceModel faceModel2, ref float pfSimilScore)
            IntPtr recognizeEngine = IntPtr.Zero;
            IntPtr pMem = Marshal.AllocHGlobal(Size);
            int retCode = AFRFunction32.AFR_FSDK_InitialEngine(appId32, sdkFRKey32, pMem, Size, ref recognizeEngine);
            if (retCode != 0)
                return retCode;
            IntPtr firstPtr = Marshal.AllocHGlobal(Marshal.SizeOf(faceModel1));
            Marshal.StructureToPtr(faceModel1, firstPtr, false);
            IntPtr secondPtr = Marshal.AllocHGlobal(Marshal.SizeOf(faceModel2));
            Marshal.StructureToPtr(faceModel2, secondPtr, false);
            int ret = AFRFunction32.AFR_FSDK_FacePairMatching(recognizeEngine, firstPtr, secondPtr, ref pfSimilScore);
            AFRFunction32.AFR_FSDK_UninitialEngine(recognizeEngine);
            Marshal.FreeHGlobal(firstPtr);
            Marshal.FreeHGlobal(secondPtr);
            Marshal.FreeHGlobal(pMem);
            return ret;
        private ArcStruct.ASVLOFFSCREEN GetOffInput(Bitmap bitmap)
            int width = 0;
            int height = 0;
            int pitch = 0;
            byte[] imageData = readBmp(bitmap, ref width, ref height, ref pitch);
            IntPtr imageDataPtr = Marshal.AllocHGlobal(imageData.Length);
            Marshal.Copy(imageData, 0, imageDataPtr, imageData.Length);
            ArcStruct.ASVLOFFSCREEN offInput = new ArcStruct.ASVLOFFSCREEN();
            offInput.u32PixelArrayFormat = 513;
            offInput.ppu8Plane = new IntPtr[4];
            offInput.ppu8Plane[0] = imageDataPtr;
            offInput.i32Width = width;
            offInput.i32Height = height;
            offInput.pi32Pitch = new int[4];
            offInput.pi32Pitch[0] = pitch;
            Marshal.FreeHGlobal(imageDataPtr);
            return offInput;
        private byte[] readBmp(Bitmap image, ref int width, ref int height, ref int pitch)
            //将Bitmap锁定到系统内存中,获得BitmapData
            BitmapData data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            //位图中第一个像素数据的地址。它也可以看成是位图中的第一个扫描行
            IntPtr ptr = data.Scan0;
            //定义数组长度
            int soureBitArrayLength = data.Height * Math.Abs(data.Stride);
            byte[] sourceBitArray = new byte[soureBitArrayLength];
            //将bitmap中的内容拷贝到ptr_bgr数组中
            Marshal.Copy(ptr, sourceBitArray, 0, soureBitArrayLength);
            width = data.Width;
            height = data.Height;
            pitch = Math.Abs(data.Stride);
            int line = width * 3;
            int bgr_len = line * height;
            byte[] destBitArray = new byte[bgr_len];
            for (int i = 0; i < height; ++i)
                Array.Copy(sourceBitArray, i * pitch, destBitArray, i * line, line);
            pitch = line;
            image.UnlockBits(data);
            return destBitArray;
	看到了熟悉的C#的变量,只需要调用方法GetImageFaceCountFaceMatching就可以实现获取人脸数目和人脸比对,具体实现逻辑骚年们可以看看类中的具体逻辑,接下来把Struct数据类型类也发出来给大家参考 
	    ARCStruct.cs类
public int i32Width; public int i32Height; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = System.Runtime.InteropServices.UnmanagedType.SysUInt)] public System.IntPtr[] ppu8Plane; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = System.Runtime.InteropServices.UnmanagedType.I4)] public int[] pi32Pitch; public struct AFR_FSDK_FaceInput public MRECT rcFace; public int lOrient; public struct AFR_FSDK_FaceModel public IntPtr pbFeature; public int lFeatureSize; 好了,这样封装就大功告成,咋们可以免费做自己的人脸识别Demo,小西瓜也做了一个DEMO出来供大家参考,下面就是DEMO使用的具体截图