一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Unity之人臉識別對比(一) 基于ArcFace離線Sdk的開發(fā)

 鴻蛟家平 2019-03-19
 本章主要講述unity開發(fā)中,人臉識別SDK的選擇以及調用,實現(xiàn)簡單的圖片檢測。

一 人臉識別引擎

(一)集成WebAPI

目前以百度AI,騰訊等的互聯(lián)網(wǎng)公司提供了基于WEBAPI的集成方式,可以通過HTTP的方式提交識別請求,識別結果通過JSON串的方式返回?;贖TTP的方式識別人臉是比較慢的,慢的原因在于IO性能,相對來講,離線版本的API則能夠充分利用本機的機器資源,不用往返于所謂的算法云服務器,直接在本地就能完成人臉識別和比對工作。

(二)集成SDK

以Face++和訊飛語音為例,這些公司即提供了在線識別的方式也提供了基于SDK的本地識別方式。本地識別的優(yōu)點是速度快,集成度高。而且,作為C#,我們還可以搭建自己的云識別平臺。如果采用了WEBAPI的,每一筆請求都需要再經(jīng)過WEBAPI中轉,性能上會大打折扣。
軟件的成本包括人力成本和采購成本,在考慮成本的時候,自然會想到,我們使用的引擎是否收費呢?即使收費再便宜,一旦流量上來了,也是一筆不小的開支。那么有沒有免費的呢。虹軟公司開發(fā)的人臉識別SDK即可以實現(xiàn)本地識別而且對于中小型企業(yè)基本無成本消耗。

二 引用ArcFace人臉識別離線SDK

(一)下載ArcFace人臉識別離線SDK

(1)打開虹軟官網(wǎng),登陸成功后,點擊開發(fā)者中心,點擊創(chuàng)建應用。
圖一
(2)創(chuàng)建完成后,點擊添加SDK,選擇ArcFace,然后填寫相關選項,最后確認。(沒有認證信息的需要認證一下信息,大約需要半天左右)

(3)添加完成后,點擊查看激活碼,這里的APP_ID和SDK_KEY需要記下啦,在項目中需要使用,最后點擊下載SDK。

(二)將libarcsoft_face_engine.dll,libarcsoft_face.dll文件導入Unity

(1)打開下載的壓縮包,找到bin下的x64文件夾內的libarcsoft_face.dll以及l(fā)ibarcsoft_face_engine.dll文件。

(2)Unity中新建Plugins文件夾,導入剛剛的兩個dll文件。

System.Drawing.dll文件從網(wǎng)上https://cn./system.drawing.dll.html下載一個。
注意:這里Unity的Scripting Runtime Version以及Api Compatbility Level*都改為.Net4.X的版本

(三)C#調用(官網(wǎng)的vs窗體Demo含有以下內容)

(1) 自定義方法ASFFunction.cs

using System;
using System.Runtime.InteropServices;//添加引用,調用dll
namespace Ycx_Tool.ArcFace
{
    public class ASFFunctions
    {
        /// <summary>
        /// SDK動態(tài)鏈接庫路徑
        /// </summary>
        public const string Dll_PATH = "libarcsoft_face_engine";

        /// <summary>
        /// 激活人臉識別SDK引擎函數(shù)
        /// </summary>
        /// <param name="appID">SDK對應的AppID</param>
        /// <param name="sdkKey">SDK對應的SDKKey</param>
        /// <returns>調用結果</returns>
        [DllImport(Dll_PATH,CallingConvention=CallingConvention.Cdecl)]
        public static extern int ASFActivation(string appID, string sdkKey);

        /// <summary>
        /// 初始化引擎
        /// </summary>
        /// <param name="detectMode">AF_DETECT_MODE_VIDEO 視頻模式 | AF_DETECT_MODE_IMAGE 圖片模式</param>
        /// <param name="detectFaceOrientPriority">檢測臉部的角度優(yōu)先值,推薦:ASF_OrientPriority.ASF_OP_0_HIGHER_EXT</param>
        /// <param name="detectFaceScaleVal">用于數(shù)值化表示的最小人臉尺寸</param>
        /// <param name="detectFaceMaxNum">最大需要檢測的人臉個數(shù)</param>
        /// <param name="combinedMask">用戶選擇需要檢測的功能組合,可單個或多個</param>
        /// <param name="pEngine">初始化返回的引擎handle</param>
        /// <returns>調用結果</returns>
        [DllImport(Dll_PATH,CallingConvention=CallingConvention.Cdecl)]
        public static extern int ASFInitEngine(uint detectMode, int detectFaceOrientPriority, int detectFaceScaleVal, int detectFaceMaxNum, int combinedMask, ref IntPtr pEngine);

        /// <summary>
        /// 人臉檢測
        /// </summary>
        /// <param name="pEngine">引擎handle</param>
        /// <param name="width">圖像寬度</param>
        /// <param name="height">圖像高度</param>
        /// <param name="format">圖像顏色空間</param>
        /// <param name="imgData">圖像數(shù)據(jù)</param>
        /// <param name="detectedFaces">人臉檢測結果</param>
        /// <returns></returns>
        [DllImport(Dll_PATH, CallingConvention = CallingConvention.Cdecl)]
        public static extern int ASFDetectFaces(IntPtr pEngine, int width, int height, int format, IntPtr imgData, IntPtr detectedFaces);

        /// <summary>
        /// 人臉信息檢測(年齡/性別/人臉3D角度)
        /// </summary>
        /// <param name="pEngine">引擎handle</param>
        /// <param name="width">圖像寬度</param>
        /// <param name="height">圖像高度</param>
        /// <param name="format">圖像顏色空間</param>
        /// <param name="imgData">圖像數(shù)據(jù)</param>
        /// <param name="detectedFaces">人臉信息,用戶根據(jù)待檢測的功能裁減選擇需要使用的人臉</param>
        /// <param name="combinedMask">只支持初始化時候指定需要檢測的功能,在proces時進一步在這個已經(jīng)指定的功能集中篩選例如初始化的時候指定檢測年齡和性別,在process的時候可以只檢測年齡,但是不能檢測除年齡和性別
        /// 之外的功能</param>
        /// <returns>調用結果</returns>
        [DllImport(Dll_PATH,CallingConvention=CallingConvention.Cdecl)]
        public static extern int ASFProcess(IntPtr pEngine, int width, int height, int format, IntPtr imgData, IntPtr detectedFaces, int combinedMask);

        /// <summary>
        /// 單人臉特征提取
        /// </summary>
        /// <param name="pEngine">引擎handle</param>
        /// <param name="width">圖像寬度</param>
        /// <param name="height">圖像高度</param>
        /// <param name="format">圖像顏色空間</param>
        /// <param name="imgData">圖像數(shù)據(jù)</param>
        /// <param name="faceInfo">單張人臉位置和角度信息</param>
        /// <param name="faceFeature">人臉特征</param>
        /// <returns>調用結果</returns>
        [DllImport(Dll_PATH, CallingConvention = CallingConvention.Cdecl)]
        public static extern int ASFFaceFeatureExtract(IntPtr pEngine,int width,int height,int format,IntPtr imgData,IntPtr faceInfo,IntPtr faceFeature);

        /// <summary>
        /// 人臉特征比對
        /// </summary>
        /// <param name="pEngine">引擎handle</param>
        /// <param name="faceFeature1">待比較人臉特征1</param>
        /// <param name="faceFeature2">帶比較人臉特征2</param>
        /// <param name="similarity">相似度(0~1)</param>
        /// <returns>調用結果</returns>
        [DllImport(Dll_PATH,CallingConvention=CallingConvention.Cdecl)]
        public static extern int ASFFaceFeatureCompare(IntPtr pEngine,IntPtr faceFeature1,IntPtr faceFeature2,ref float similarity);

        /// <summary>
        /// 獲取性別信息
        /// </summary>
        /// <param name="pEngine">引擎handle</param>
        /// <param name="GenderInfo">檢測到的性別信息</param>
        /// <returns></returns>
        [DllImport(Dll_PATH,CallingConvention =CallingConvention.Cdecl)]
        public static extern int ASFGetGender(IntPtr pEngine, IntPtr GenderInfo);

        /// <summary>
        /// 獲取年齡信息
        /// </summary>
        /// <param name="pEngine">引擎handle</param>
        /// <param name="ageInfo">檢測到的性別信息</param>
        /// <returns></returns>
        [DllImport(Dll_PATH, CallingConvention = CallingConvention.Cdecl)]
        public static extern int ASFGetAge(IntPtr pEngine, IntPtr ageInfo);

        /// <summary>
        /// 獲取3D角度信息
        /// </summary>
        /// <param name="pEngine">引擎handle</param>
        /// <param name="p3DAngleInfo">檢測到臉部3D角度信息</param>
        /// <returns>調用結果</returns>
        [DllImport(Dll_PATH,CallingConvention =CallingConvention.Cdecl)]
        public static extern int ASFGetFace3DAngle(IntPtr pEngine, IntPtr p3DAngleInfo);


        /// <summary>
        /// 銷毀引擎
        /// </summary>
        /// <param name="pEngine">引擎handle</param>
        /// <returns>調用結果</returns>
        [DllImport(Dll_PATH, CallingConvention = CallingConvention.Cdecl)]
        public static extern int ASFUninitEngine(IntPtr pEngine);

        /// <summary>
        /// 獲取版本信息
        /// </summary>
        /// <param name="pEngine">引擎handle</param>
        /// <returns>調用結果</returns>
        [DllImport(Dll_PATH, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr ASFGetVersion(IntPtr pEngine);
    }
}

(2)自定義數(shù)據(jù)類型
ImageInfo.cs

namespace Ycx_Tool.ArcFace
{
    public class ImageInfo
    {
        /// <summary>
        /// 圖片的像素數(shù)據(jù)
        /// </summary>
        public IntPtr imgData { get; set; }

        /// <summary>
        /// 圖片像素寬
        /// </summary>
        public int width { get; set; }

        /// <summary>
        /// 圖片像素高
        /// </summary>
        public int height { get; set; }

        /// <summary>
        /// 圖片格式
        /// </summary>
        public int format { get; set; }
    }
}

(3)自定義結構體

ASF_AgeInfo.cs

namespace Ycx_Tool.ArcFace
{
    /// <summary>
    /// 年齡結果結構體
    /// </summary>
    public struct ASF_AgeInfo
    {
        /// <summary>
        /// 年齡檢測結果集合
        /// </summary>
        public IntPtr ageArray;
        /// <summary>
        /// 結果集大小
        /// </summary>
        public int num;
    }
}

ASF_Face3DAngle.cs

namespace Ycx_Tool.ArcFace
{
    /// <summary>
    /// 3D人臉角度檢測結構體,可參考https://ai./bbs/forum.php?mod=viewthread&tid=1459&page=1&extra=&_dsign=fd9e1a7a
    /// </summary>
    public struct ASF_Face3DAngle
    {
        public IntPtr roll;
        public IntPtr yaw;
        public IntPtr pitch;
        /// <summary>
        /// 是否檢測成功,0成功,其他為失敗
        /// </summary>
        public IntPtr status;
        public int num;
    }
}

ASF_FaceFeature.cs

namespace Ycx_Tool.ArcFace
{
    /// <summary>
    /// 人臉特征結構體
    /// </summary>
    public struct ASF_FaceFeature
    {
        /// <summary>
        /// 特征值 byte[]
        /// </summary>
        public IntPtr feature;

        /// <summary>
        /// 結果集大小
        /// </summary>
        public int featureSize;
    }
}

ASF_GenderInfo.cs

namespace Ycx_Tool.ArcFace
{
    /// <summary>
    /// 性別結構體
    /// </summary>
    public struct ASF_GenderInfo
    {
        /// <summary>
        /// 性別檢測結果集合
        /// </summary>
        public IntPtr genderArray;
        /// <summary>
        /// 結果集大小
        /// </summary>
        public int num;
    }
}

ASF_ImagePixelFormat.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ycx_Tool.ArcFace
{
    public struct ASF_ImagePixelFormat
    {
        /// <summary>
        /// RGB24圖片格式
        /// </summary>
        public const int ASVL_PAF_RGB24_B8G8R8 = 0x201;
    }
}

ASF_MultiFaceInfo.cs

namespace Ycx_Tool.ArcFace
{
    /// <summary>
    /// 多人臉檢測結構體
    /// </summary>
    public struct ASF_MultiFaceInfo
    {
        /// <summary>
        /// 人臉Rect結果集
        /// </summary>
        public IntPtr faceRects;

        /// <summary>
        /// 人臉角度結果集,與faceRects一一對應  對應ASF_OrientCode
        /// </summary>
        public IntPtr faceOrients;
        /// <summary>
        /// 結果集大小
        /// </summary>
        public int faceNum;
    }
}

ASF_OrientCode.cs

namespace Ycx_Tool.ArcFace
{
    /// <summary>
    /// 人臉角度結構體
    /// </summary>
    public struct ASF_OrientCode
    {
        public const int ASF_OC_0 = 0x1;
        public const int ASF_OC_90 = 0x2;
        public const int ASF_OC_270 = 0x3;
        public const int ASF_OC_180 = 0x4;
        public const int ASF_OC_30 = 0x5;
        public const int ASF_OC_60 = 0x6;
        public const int ASF_OC_120 = 0x7;
        public const int ASF_OC_150 = 0x8;
        public const int ASF_OC_210 = 0x9;
        public const int ASF_OC_240 = 0xa;
        public const int ASF_OC_300 = 0xb;
        public const int ASF_OC_330 = 0xc;
    }
}

ASF_OrientPriority.cs

namespace Ycx_Tool.ArcFace
{
    /// <summary>
    /// 人臉檢測優(yōu)先角度結構體,推薦ASF_OP_0_HIGHER_EXT
    /// </summary>
    public struct ASF_OrientPriority
    {
        public const int ASF_OP_0_ONLY = 0x1;
        public const int ASF_OP_90_ONLY = 0x2;
        public const int ASF_OP_270_ONLY = 0x3;
        public const int ASF_OP_180_ONLY = 0x4;
        public const int ASF_OP_0_HIGHER_EXT = 0x5;
    }
}

ASF_SingleFaceInfo.cs

namespace Ycx_Tool.ArcFace
{
    /// <summary>
    /// 單人臉檢測結構體
    /// </summary>
    public struct ASF_SingleFaceInfo
    {
        /// <summary>
        /// 人臉坐標Rect結果
        /// </summary>
        public MRECT faceRect;
        /// <summary>
        /// 人臉角度
        /// </summary>
        public int faceOrient;
    }
}

ASF_VERSION.cs

namespace Ycx_Tool.ArcFace
{
    /// <summary>
    /// SDK版本信息結構體
    /// </summary>
    public struct ASF_VERSION
    {
        public string version;
        public string buildDate;
        public string copyRight;
    }
}

DetectionMode.cs

namespace Ycx_Tool.ArcFace
{
    /// <summary>
    /// 圖片檢測模式
    /// </summary>
    public struct DetectionMode
    {
        /// <summary>
        /// Video模式,一般用于多幀連續(xù)檢測
        /// </summary>
        public const uint ASF_DETECT_MODE_VIDEO = 0x00000000;

        /// <summary>
        /// Image模式,一般用于靜態(tài)圖的單次檢測
        /// </summary>
        public const uint ASF_DETECT_MODE_IMAGE = 0xFFFFFFFF;
    }
}

FaceEngineMask.cs

namespace Ycx_Tool.ArcFace
{
    /// <summary>
    /// 引擎方法類型結構體,在初始化時將用到的類型用|連接傳入,如 ASF_NONE|ASF_FACE_DETECT|ASF_FACERECOGNITION
    /// </summary>
    public struct FaceEngineMask
    {
        /// <summary>
        /// 不做方法初始化方法類型
        /// </summary>
        public const int ASF_NONE = 0x00000000;
        /// <summary>
        /// 人臉檢測方法類型常量
        /// </summary>
        public const int ASF_FACE_DETECT = 0x00000001;
        /// <summary>
        /// 人臉識別方法類型常量,包含圖片feature提取和feature比對
        /// </summary>
        public const int ASF_FACERECOGNITION = 0x00000004;
        /// <summary>
        /// 年齡檢測方法類型常量
        /// </summary>
        public const int ASF_AGE = 0x00000008;
        /// <summary>
        /// 性別檢測方法類型常量
        /// </summary>
        public const int ASF_GENDER = 0x00000010;
        /// <summary>
        /// 3D角度檢測方法類型常量
        /// </summary>
        public const int ASF_FACE3DANGLE = 0x00000020;
    }
}

MRECT.cs

namespace Ycx_Tool.ArcFace
{
    /// <summary>
    /// 人臉框信息結構體
    /// </summary>
    public struct MRECT
    {
        public int left;
        public int top;
        public int right;
        public int bottom;
    }
}

(3)內存管理類
MemoryUtil.cs

using System;
using System.Runtime.InteropServices;
namespace Ycx_Tool.ArcFace
{
    public class MemoryUtil
    {
        /// <summary>
        /// 申請內存
        /// </summary>
        /// <param name="len">內存長度(單位:字節(jié))</param>
        /// <returns>內存首地址</returns>
        public static IntPtr Malloc(int len)
        {
            return Marshal.AllocHGlobal(len);
        }

        /// <summary>
        /// 釋放ptr托管的內存
        /// </summary>
        /// <param name="ptr">托管指針</param>
        public static void Free(IntPtr ptr)
        {
            Marshal.FreeHGlobal(ptr);
        }

        /// <summary>
        /// 將字節(jié)數(shù)組的內容拷貝到托管內存中
        /// </summary>
        /// <param name="source">元數(shù)據(jù)</param>
        /// <param name="startIndex">元數(shù)據(jù)拷貝起始位置</param>
        /// <param name="destination">托管內存</param>
        /// <param name="length">拷貝長度</param>
        public static void Copy(byte[] source, int startIndex, IntPtr destination, int length)
        {
            Marshal.Copy(source, startIndex, destination, length);
        }

        /// <summary>
        /// 將托管內存的內容拷貝到字節(jié)數(shù)組中
        /// </summary>
        /// <param name="source">托管內存</param>
        /// <param name="destination">目標字節(jié)數(shù)組</param>
        /// <param name="startIndex">拷貝起始位置</param>
        /// <param name="length">拷貝長度</param>
        public static void Copy(IntPtr source, byte[] destination, int startIndex, int length)
        {
            Marshal.Copy(source, destination, startIndex, length);
        }

        /// <summary>
        /// 將ptr托管的內存轉化為結構體對象
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <param name="ptr">托管指針</param>
        /// <returns>轉化后的對象</returns>
        public static T PtrToStructure<T>(IntPtr ptr)
        {
            return Marshal.PtrToStructure<T>(ptr);
        }

        /// <summary>
        /// 將結構體對象復制到ptr托管的內存
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="ptr"></param>
        public static void StructureToPtr<T>(T t, IntPtr ptr)
        {
            Marshal.StructureToPtr(t, ptr, false);
        }

        /// <summary>
        /// 獲取類型的大小
        /// </summary>
        /// <typeparam name="T">泛型</typeparam>
        /// <returns>類型的大小</returns>
        public static int SizeOf<T>()
        {
            return Marshal.SizeOf<T>();
        }
    }
}

(4)圖片處理類
ImageUtil.cs

using System;
using System.Drawing;
using System.Drawing.Imaging;
using UnityEngine;
using System.IO;
namespace Ycx_Tool.ArcFace
{
    public class ImageUtil
    {
        /// <summary>
        /// 獲取Image
        /// </summary>
        /// <returns></returns>
        public static Image GetImage(string path)
        {
            Image image;
            FileInfo file = new FileInfo(path);
            long maxSize = 1024 * 1024 * 2;
            if (file.Length > maxSize)
            {
                Debug.Log("圖像文件最大為2MB,請壓縮后在導入!");
                return null;
            }
            image = Image.FromFile(path);
            image = ScaleImage(image, 256, 256);
            return image;
        }
        /// <summary>
        /// 獲取圖片信息
        /// </summary>
        /// <param name="image">圖片</param>
        /// <returns>成功或失敗</returns>
        public static ImageInfo ReadBMP(Image image)
        {
            ImageInfo imageInfo = new ImageInfo();
            //將Image轉換為Format24bppRgb格式的BMP
            Bitmap bm = new Bitmap(image);
            BitmapData data = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            try
            {
                //位圖中第一個像素數(shù)據(jù)的地址。它也可以看成是位圖中的第一個掃描行
                IntPtr ptr = data.Scan0;

                //定義數(shù)組長度
                int soureBitArrayLength = data.Height * Math.Abs(data.Stride);
                byte[] sourceBitArray = new byte[soureBitArrayLength];

                //將bitmap中的內容拷貝到ptr_bgr數(shù)組中
                MemoryUtil.Copy(ptr, sourceBitArray, 0, soureBitArrayLength);

                //填充引用對象字段值
                imageInfo.width = data.Width;
                imageInfo.height = data.Height;
                imageInfo.format = ASF_ImagePixelFormat.ASVL_PAF_RGB24_B8G8R8;

                //獲取去除對齊位后度圖像數(shù)據(jù)
                int line = imageInfo.width * 3;
                int pitch = Math.Abs(data.Stride);
                int bgr_len = line * imageInfo.height;
                byte[] destBitArray = new byte[bgr_len];

                /*
                 * 圖片像素數(shù)據(jù)在內存中是按行存儲,一般圖像庫都會有一個內存對齊,在每行像素的末尾位置
                 * 每行的對齊位會使每行多出一個像素空間(三通道如RGB會多出3個字節(jié),四通道RGBA會多出4個字節(jié))
                 * 以下循環(huán)目的是去除每行末尾的對齊位,將有效的像素拷貝到新的數(shù)組
                 */
                for (int i = 0; i < imageInfo.height; ++i)
                {
                    Array.Copy(sourceBitArray, i * pitch, destBitArray, i * line, line);
                }

                imageInfo.imgData = MemoryUtil.Malloc(destBitArray.Length);
                MemoryUtil.Copy(destBitArray, 0, imageInfo.imgData, destBitArray.Length);

                return imageInfo;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                bm.UnlockBits(data);
            }

            return null;
        }

        /// <summary>
        /// 用矩形框標記圖片指定區(qū)域
        /// </summary>
        /// <param name="image">圖片</param>
        /// <param name="startX">矩形框左上角X坐標</param>
        /// <param name="startY">矩形框左上角Y坐標</param>
        /// <param name="width">矩形框寬度</param>
        /// <param name="height">矩形框高度</param>
        /// <returns>標記后的圖片</returns>
        public static Image MarkRect(Image image, int startX, int startY, int width, int height)
        {
            Image clone = (Image)image.Clone();
            System.Drawing.Graphics g =System.Drawing.Graphics.FromImage(clone);
            try
            {
                Brush brush = new SolidBrush(System.Drawing.Color.Red);
                Pen pen = new Pen(brush, 2);
                pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                g.DrawRectangle(pen, new Rectangle(startX, startY, width, height));
                return clone;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                g.Dispose();
            }

            return null;
        }

        /// <summary>
        /// 用矩形框標記圖片指定區(qū)域,添加年齡和性別標注
        /// </summary>
        /// <param name="image">圖片</param>
        /// <param name="startX">矩形框左上角X坐標</param>
        /// <param name="startY">矩形框左上角Y坐標</param>
        /// <param name="width">矩形框寬度</param>
        /// <param name="height">矩形框高度</param>
        /// <param name="age">年齡</param>
        /// <param name="gender">性別</param>
        /// <returns>標記后的圖片</returns>
        public static Image MarkRectAndString(Image image, int startX, int startY, int width, int height, int age, int gender)
        {
            Image clone = (Image)image.Clone();
            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(clone);
            try
            {
                Brush brush = new SolidBrush(System.Drawing.Color.Red);
                Pen pen = new Pen(brush, 2);
                pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dash;
                g.DrawRectangle(pen, new Rectangle(startX < 1 ? 0 : startX, startY < 1 ? 0 : startY, width, height));
                string genderStr = "";
                if (gender >= 0)
                {
                    if (gender == 0)
                    {
                        genderStr = "男";
                    }
                    else if (gender == 1)
                    {
                        genderStr = "女";
                    }
                }
                g.DrawString(string.Format("Age:{0}   Gender:{1}", age, genderStr), new System.Drawing.Font(FontFamily.GenericSerif, 12), brush, startX < 1 ? 0 : startX, (startY - 20) < 1 ? 0 : startY - 20);

                return clone;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                g.Dispose();
            }

            return null;
        }

        /// <summary>
        /// 按指定寬高縮放圖片
        /// </summary>
        /// <param name="image">原圖片</param>
        /// <param name="dstWidth">目標圖片寬</param>
        /// <param name="dstHeight">目標圖片高</param>
        /// <returns></returns>
        public static Image ScaleImage(Image image, int dstWidth, int dstHeight)
        {
            System.Drawing.Graphics g = null;
            try
            {
                //按比例縮放           
                float scaleRate = 0.0f;
                if (image.Width >= dstWidth && image.Height >= dstHeight)
                {
                    int widthDis = image.Width - dstWidth;
                    int heightDis = image.Height - dstHeight;
                    if (widthDis > heightDis)
                    {
                        scaleRate = dstWidth * 1f / image.Width;
                    }
                    else
                    {
                        scaleRate = dstHeight * 1f / image.Height;
                    }
                }
                else if (image.Width >= dstWidth && image.Height < dstHeight)
                {
                    scaleRate = dstWidth * 1f / image.Width;
                }
                else if (image.Width < dstWidth && image.Height >= dstHeight)
                {
                    scaleRate = dstHeight * 1f / image.Height;
                }
                else
                {
                    int widthDis = dstWidth - image.Width;
                    int heightDis = dstHeight - image.Height;
                    if (widthDis > heightDis)
                    {
                        scaleRate = dstHeight * 1f / image.Height;
                    }
                    else
                    {
                        scaleRate = dstWidth * 1f / image.Width;
                    }
                }
                int width = (int)(image.Width * scaleRate);
                int height = (int)(image.Height * scaleRate);

                //將寬度調整為4的整數(shù)倍
                if (width % 4 != 0)
                {
                    width = width - width % 4;
                }

                Bitmap destBitmap = new Bitmap(width, height);
                g = System.Drawing.Graphics.FromImage(destBitmap);
                g.Clear(System.Drawing.Color.Transparent);

                //設置畫布的描繪質量         
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                g.DrawImage(image, new Rectangle((width - width) / 2, (height - height) / 2, width, height), 0, 0, image.Width, image.Height, GraphicsUnit.Pixel);

                //設置壓縮質量     
                EncoderParameters encoderParams = new EncoderParameters();
                long[] quality = new long[1];
                quality[0] = 100;
                EncoderParameter encoderParam = new EncoderParameter(Encoder.Quality, quality);
                encoderParams.Param[0] = encoderParam;

                return destBitmap;
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
            finally
            {
                if (g != null)
                {
                    g.Dispose();
                }
            }

            return null;
        }

        /// <summary>
        /// 剪裁圖片
        /// </summary>
        /// <param name="src">原圖片</param>
        /// <param name="left">左坐標</param>
        /// <param name="top">頂部坐標</param>
        /// <param name="right">右坐標</param>
        /// <param name="bottom">底部坐標</param>
        /// <returns>剪裁后的圖片</returns>
        public static Image CutImage(Image src, int left, int top, int right, int bottom)
        {
            try
            {
                Bitmap srcBitmap = new Bitmap(src);
                Bitmap dstBitmap = srcBitmap.Clone(new Rectangle(left, top, right - left, bottom - top), PixelFormat.DontCare);
                return dstBitmap;
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            return null;
        }
    }
}

(5)人臉識別類
FaceUtil.cs

using System;
using System.Drawing;
namespace Ycx_Tool.ArcFace
{
    public class FaceUtil
    {

        /// <summary>
        /// 人臉檢測(PS:檢測RGB圖像的人臉時,必須保證圖像的寬度能被4整除,否則會失敗)
        /// </summary>
        /// <param name="pEngine">引擎Handle</param>
        /// <param name="imageInfo">圖像數(shù)據(jù)</param>
        /// <returns>人臉檢測結果</returns>
        public static ASF_MultiFaceInfo DetectFace(IntPtr pEngine, ImageInfo imageInfo)
        {
            ASF_MultiFaceInfo multiFaceInfo = new ASF_MultiFaceInfo();
            IntPtr pMultiFaceInfo = MemoryUtil.Malloc(MemoryUtil.SizeOf<ASF_MultiFaceInfo>());
            int retCode = ASFFunctions.ASFDetectFaces(pEngine, imageInfo.width, imageInfo.height, imageInfo.format, imageInfo.imgData, pMultiFaceInfo);
            multiFaceInfo = MemoryUtil.PtrToStructure<ASF_MultiFaceInfo>(pMultiFaceInfo);
            return multiFaceInfo;
        }

        /// <summary>
        /// 人臉檢測
        /// </summary>
        /// <param name="pEngine">引擎Handle</param>
        /// <param name="image">圖像</param>
        /// <returns></returns>
        public static ASF_MultiFaceInfo DetectFace(IntPtr pEngine, string path)
        {
            ASF_MultiFaceInfo multiFaceInfo = new ASF_MultiFaceInfo();
            Image image=ImageUtil.GetImage(path);
            if (image != null)
            {
                image = ImageUtil.ScaleImage(image, image.Width, image.Height);
                ImageInfo imageInfo = ImageUtil.ReadBMP(image);
                multiFaceInfo = DetectFace(pEngine, imageInfo);
                MemoryUtil.Free(imageInfo.imgData);
                return multiFaceInfo;
            }
            else
            {
                return multiFaceInfo;
            }
        }

        /// <summary>
        /// 提取人臉特征
        /// </summary>
        /// <param name="pEngine">引擎Handle</param>
        /// <param name="imageInfo">圖像數(shù)據(jù)</param>
        /// <param name="multiFaceInfo">人臉檢測結果</param>
        /// <returns>保存人臉特征結構體指針</returns>
        public static IntPtr ExtractFeature(IntPtr pEngine, ImageInfo imageInfo, ASF_MultiFaceInfo multiFaceInfo, out ASF_SingleFaceInfo singleFaceInfo)
        {
            singleFaceInfo = new ASF_SingleFaceInfo();
            singleFaceInfo.faceRect = MemoryUtil.PtrToStructure<MRECT>(multiFaceInfo.faceRects);
            singleFaceInfo.faceOrient = MemoryUtil.PtrToStructure<int>(multiFaceInfo.faceOrients);
            IntPtr pSingleFaceInfo = MemoryUtil.Malloc(MemoryUtil.SizeOf<ASF_SingleFaceInfo>());
            MemoryUtil.StructureToPtr(singleFaceInfo, pSingleFaceInfo);

            IntPtr pFaceFeature = MemoryUtil.Malloc(MemoryUtil.SizeOf<ASF_FaceFeature>());
            int retCode = ASFFunctions.ASFFaceFeatureExtract(pEngine, imageInfo.width, imageInfo.height, imageInfo.format, imageInfo.imgData, pSingleFaceInfo, pFaceFeature);
            Console.WriteLine("FR Extract Feature result:" + retCode);

            if (retCode != 0)
            {
                //釋放指針
                MemoryUtil.Free(pSingleFaceInfo);
                MemoryUtil.Free(pFaceFeature);
                ASF_FaceFeature emptyFeature = new ASF_FaceFeature();
                IntPtr pEmptyFeature = MemoryUtil.Malloc(MemoryUtil.SizeOf<ASF_FaceFeature>());
                MemoryUtil.StructureToPtr(emptyFeature, pEmptyFeature);
                return pEmptyFeature;
            }

            //人臉特征feature過濾
            ASF_FaceFeature faceFeature = MemoryUtil.PtrToStructure<ASF_FaceFeature>(pFaceFeature);
            byte[] feature = new byte[faceFeature.featureSize];
            MemoryUtil.Copy(faceFeature.feature, feature, 0, faceFeature.featureSize);

            ASF_FaceFeature localFeature = new ASF_FaceFeature();
            localFeature.feature = MemoryUtil.Malloc(feature.Length);
            MemoryUtil.Copy(feature, 0, localFeature.feature, feature.Length);
            localFeature.featureSize = feature.Length;
            IntPtr pLocalFeature = MemoryUtil.Malloc(MemoryUtil.SizeOf<ASF_FaceFeature>());
            MemoryUtil.StructureToPtr(localFeature, pLocalFeature);

            //釋放指針
            MemoryUtil.Free(pSingleFaceInfo);
            MemoryUtil.Free(pFaceFeature);

            return pLocalFeature;
        }

        /// <summary>
        /// 提取人臉特征
        /// </summary>
        /// <param name="pEngine">引擎Handle</param>
        /// <param name="image">圖像</param>
        /// <returns>保存人臉特征結構體指針</returns>
        public static IntPtr ExtractFeature(IntPtr pEngine, Image image, out ASF_SingleFaceInfo singleFaceInfo)
        {
            image = ImageUtil.ScaleImage(image, image.Width, image.Height);
            ImageInfo imageInfo = ImageUtil.ReadBMP(image);
            ASF_MultiFaceInfo multiFaceInfo = DetectFace(pEngine, imageInfo);
            singleFaceInfo = new ASF_SingleFaceInfo();
            IntPtr pFaceModel = ExtractFeature(pEngine, imageInfo, multiFaceInfo, out singleFaceInfo);
            MemoryUtil.Free(imageInfo.imgData);
            return pFaceModel;
        }

        /// <summary>
        /// 年齡檢測
        /// </summary>
        /// <param name="pEngine">引擎Handle</param>
        /// <param name="imageInfo">圖像數(shù)據(jù)</param>
        /// <param name="multiFaceInfo">人臉檢測結果</param>
        /// <returns>年齡檢測結構體</returns>
        public static ASF_AgeInfo AgeEstimation(IntPtr pEngine, ImageInfo imageInfo, ASF_MultiFaceInfo multiFaceInfo, out int retCode)
        {
            retCode = -1;
            IntPtr pMultiFaceInfo = MemoryUtil.Malloc(MemoryUtil.SizeOf<ASF_MultiFaceInfo>());
            MemoryUtil.StructureToPtr(multiFaceInfo, pMultiFaceInfo);

            if (multiFaceInfo.faceNum == 0)
            {
                return new ASF_AgeInfo();
            }

            //人臉信息處理
            retCode = ASFFunctions.ASFProcess(pEngine, imageInfo.width, imageInfo.height, imageInfo.format, imageInfo.imgData, pMultiFaceInfo, FaceEngineMask.ASF_AGE);
            if (retCode == 0)
            {
                //獲取年齡信息
                IntPtr pAgeInfo = MemoryUtil.Malloc(MemoryUtil.SizeOf<ASF_AgeInfo>());
                retCode = ASFFunctions.ASFGetAge(pEngine, pAgeInfo);
                Console.WriteLine("Get Age Result:" + retCode);
                ASF_AgeInfo ageInfo = MemoryUtil.PtrToStructure<ASF_AgeInfo>(pAgeInfo);

                //釋放內存
                MemoryUtil.Free(pMultiFaceInfo);
                MemoryUtil.Free(pAgeInfo);
                return ageInfo;
            }
            else
            {
                return new ASF_AgeInfo();
            }
        }

        /// <summary>
        /// 性別檢測
        /// </summary>
        /// <param name="pEngine">引擎Handle</param>
        /// <param name="imageInfo">圖像數(shù)據(jù)</param>
        /// <param name="multiFaceInfo">人臉檢測結果</param>
        /// <returns>保存性別檢測結果結構體</returns>
        public static ASF_GenderInfo GenderEstimation(IntPtr pEngine, ImageInfo imageInfo, ASF_MultiFaceInfo multiFaceInfo, out int retCode)
        {
            retCode = -1;
            IntPtr pMultiFaceInfo = MemoryUtil.Malloc(MemoryUtil.SizeOf<ASF_MultiFaceInfo>());
            MemoryUtil.StructureToPtr(multiFaceInfo, pMultiFaceInfo);

            if (multiFaceInfo.faceNum == 0)
            {
                return new ASF_GenderInfo();
            }

            //人臉信息處理
            retCode = ASFFunctions.ASFProcess(pEngine, imageInfo.width, imageInfo.height, imageInfo.format, imageInfo.imgData, pMultiFaceInfo, FaceEngineMask.ASF_GENDER);
            if (retCode == 0)
            {
                //獲取性別信息
                IntPtr pGenderInfo = MemoryUtil.Malloc(MemoryUtil.SizeOf<ASF_GenderInfo>());
                retCode = ASFFunctions.ASFGetGender(pEngine, pGenderInfo);
                Console.WriteLine("Get Gender Result:" + retCode);
                ASF_GenderInfo genderInfo = MemoryUtil.PtrToStructure<ASF_GenderInfo>(pGenderInfo);

                //釋放內存
                MemoryUtil.Free(pMultiFaceInfo);
                MemoryUtil.Free(pGenderInfo);

                return genderInfo;
            }
            else
            {
                return new ASF_GenderInfo();
            }
        }

        /// <summary>
        /// 人臉3D角度檢測
        /// </summary>
        /// <param name="pEngine">引擎Handle</param>
        /// <param name="imageInfo">圖像數(shù)據(jù)</param>
        /// <param name="multiFaceInfo">人臉檢測結果</param>
        /// <returns>保存人臉3D角度檢測結果結構體</returns>
        public static ASF_Face3DAngle Face3DAngleDetection(IntPtr pEngine, ImageInfo imageInfo, ASF_MultiFaceInfo multiFaceInfo, out int retCode)
        {
            IntPtr pMultiFaceInfo = MemoryUtil.Malloc(MemoryUtil.SizeOf<ASF_MultiFaceInfo>());
            MemoryUtil.StructureToPtr(multiFaceInfo, pMultiFaceInfo);

            if (multiFaceInfo.faceNum == 0)
            {
                retCode = -1;
                return new ASF_Face3DAngle();
            }

            //人臉信息處理
            retCode = ASFFunctions.ASFProcess(pEngine, imageInfo.width, imageInfo.height, imageInfo.format, imageInfo.imgData, pMultiFaceInfo, FaceEngineMask.ASF_FACE3DANGLE);
            if (retCode == 0)
            {
                //獲取人臉3D角度
                IntPtr pFace3DAngleInfo = MemoryUtil.Malloc(MemoryUtil.SizeOf<ASF_Face3DAngle>());
                retCode = ASFFunctions.ASFGetFace3DAngle(pEngine, pFace3DAngleInfo);
                Console.WriteLine("Get Face3D Angle Result:" + retCode);
                ASF_Face3DAngle face3DAngle = MemoryUtil.PtrToStructure<ASF_Face3DAngle>(pFace3DAngleInfo);

                //釋放內存
                MemoryUtil.Free(pMultiFaceInfo);
                MemoryUtil.Free(pFace3DAngleInfo);

                return face3DAngle;
            }
            else
            {
                return new ASF_Face3DAngle();
            }
        }
    }
}

(6)功能封裝
SDKUtil.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Drawing;
namespace Ycx_Tool.ArcFace
{
    public class SDKUtil
    {
        public static IntPtr _PEngine = IntPtr.Zero;
        /// <summary>
        /// 初始化SDK
        /// </summary>
        /// <param name="appid"></param>
        /// <param name="sdkkey"></param>
        /// <returns></returns>
        public static void Init_Sdk(string appid,string sdkkey)
        {
            try
            {
                var ret_0 = ASFFunctions.ASFActivation(appid, sdkkey);
                Debug.Log("SDK激活成功");
            }
            catch (Exception e)
            {
                Debug.Log("SDK激活失敗" + e.Message);
                return;
            }
            try
            {
                //初始化引擎
                uint detectMode = DetectionMode.ASF_DETECT_MODE_IMAGE;
                //檢測臉部的角度優(yōu)先值
                int detectFaceOrientPriority = ASF_OrientPriority.ASF_OP_0_HIGHER_EXT;
                //人臉在圖片中所占比例,如果需要調整檢測人臉尺寸請修改此值,有效數(shù)值為2-32
                int detectFaceScaleVal = 16;
                //最大需要檢測的人臉個數(shù)
                int detectFaceMaxNum = 5;
                //引擎初始化時需要初始化的檢測功能組合
                int combinedMask = FaceEngineMask.ASF_FACE_DETECT | FaceEngineMask.ASF_FACERECOGNITION | FaceEngineMask.ASF_AGE | FaceEngineMask.ASF_GENDER | FaceEngineMask.ASF_FACE3DANGLE;
                var ret_1 = ASFFunctions.ASFInitEngine(detectMode,detectFaceOrientPriority, detectFaceScaleVal, detectFaceMaxNum, combinedMask, ref _PEngine);
                Debug.Log("引擎初始化成功");

            }
            catch (Exception e)
            {
                Debug.Log("引擎初始化失敗" + e.Message);
                return;
            }
        }
        /// <summary>
        /// 選擇圖片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// <param name="path"></param>
        public static ImageInfo ChooseImg(string path)
        {
            if (_PEngine == IntPtr.Zero)
            {
                Debug.Log("請先初始化引擎");
                return null;
            }
           ImageInfo  imageInfo = ImageUtil.ReadBMP(ImageUtil.GetImage(path));
           return imageInfo;
        }
        /// <summary>
        /// 人臉檢測
        /// </summary>
        /// <param name="image_Info"></param>
        public static void Face_Detect(ImageInfo image_Info)
        {
            if (_PEngine == IntPtr.Zero)
            {
                Debug.Log("請先初始化引擎");
                return;
            }
            if (image_Info == null)
            {
                Debug.Log("請先選擇圖片");
                return;
            }
            ASF_MultiFaceInfo multiFaceInfo = FaceUtil.DetectFace(_PEngine, image_Info);
            if (multiFaceInfo.faceNum < 1)
            {
                Debug.Log("未檢測到人臉");
            }
            else
            {
                Debug.Log("檢測到" + multiFaceInfo.faceNum + "人");
            }
        }
        /// <summary>
        /// 人臉對別
        /// </summary>
        /// <param name="imageInfo_0"></param>
        /// <param name="imageInfo_1"></param>
        public static string Face_Compare(string image_0_path, string image_1_path)
        {
            string result = "";
            if (_PEngine == IntPtr.Zero)
            {
                Debug.Log("請先初始化引擎");
                result = "請先初始化引擎";
                return result;
            }
            if (image_0_path == null || image_1_path == null)
            {
                Debug.Log("圖片不能為空");
                result = "圖片不能為空";
                return result;
            }
            ASF_SingleFaceInfo singleFaceInfo = new ASF_SingleFaceInfo();
            IntPtr feature_0 = FaceUtil.ExtractFeature(_PEngine, Image.FromFile(image_0_path), out singleFaceInfo);
            IntPtr feature_1 = FaceUtil.ExtractFeature(_PEngine, Image.FromFile(image_1_path), out singleFaceInfo);
            float similarity = 0f;
            ASFFunctions.ASFFaceFeatureCompare(_PEngine, feature_0, feature_1, ref similarity);
            Debug.Log("兩張臉的相似度為:" + similarity);
            result = similarity.ToString();
            return result;
        }
        /// <summary>
        /// 人臉對別
        /// </summary>
        /// <param name="imageInfo_0"></param>
        /// <param name="imageInfo_1"></param>
        public static string Face_Compare(IntPtr image_0_path, IntPtr image_1_path)
        {
            string result = "";
            if (_PEngine == IntPtr.Zero)
            {
                Debug.Log("請先初始化引擎");
                result = "請先初始化引擎";
                return result;
            }
            float similarity = 0f;
            ASFFunctions.ASFFaceFeatureCompare(_PEngine, image_0_path, image_1_path, ref similarity);
            Debug.Log("兩張臉的相似度為:" + similarity);
            result = similarity.ToString();
            return result;
        }
    }
}

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    国产精品午夜福利在线观看| 日本午夜免费观看视频| 国产精品美女午夜视频| 亚洲一区二区三区中文久久| 日韩黄片大全免费在线看| 亚洲中文字幕日韩在线| 91日韩欧美国产视频| 日本高清加勒比免费在线| 欧美黄色黑人一区二区| 久久精品久久久精品久久| 欧美日韩有码一二三区| 色好吊视频这里只有精| 麻豆视频传媒入口在线看| 久久中文字幕中文字幕中文| 亚洲国产性感美女视频| 日本加勒比系列在线播放| 欧美日韩亚洲国产精品| 永久福利盒子日韩日韩| 日韩精品一级片免费看| 麻豆亚州无矿码专区视频| 亚洲中文在线观看小视频| 中文久久乱码一区二区| 91超精品碰国产在线观看| 99视频精品免费视频播放| 国产成人一区二区三区久久| 亚洲专区一区中文字幕| 久久永久免费一区二区| 都市激情小说在线一区二区三区 | 少妇丰满a一区二区三区| 欧美三级精品在线观看| 亚洲国产一级片在线观看| 激情综合网俺也狠狠地| 日本不卡在线视频中文国产| 最好看的人妻中文字幕| 丁香六月婷婷基地伊人| 中文日韩精品视频在线| 欧美激情视频一区二区三区| 亚洲欧洲一区二区综合精品| 国产精品福利一级久久| 国产欧美日韩综合精品二区| 欧美一区二区日韩一区二区|