百度AI:人脸检测与匹配接口封装(C#)

FrCore.cs

/* ----------------------------------------------------------
 * 文件名称:FrCore.cs
 * 作者:秦建辉
 * 
 * 微信:splashcn
 * 
 * 博客:http://www.firstsolver.com/wordpress/
 * 
 * 开发环境:
 *      Visual Studio V2017
 *      .NET Framework 4
 *      
 * 版本历史:
 *      V1.1    2018年09月20日
 *              接口增强
 *      
 *      V1.0    2018年03月27日
 *              人脸识别抽象类定义
------------------------------------------------------------ */
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;

namespace Com.FirstSolver.FR
{
    /// <summary>
    /// 人脸识别通用接口
    /// </summary>
    public abstract class FrCore : IDisposable
    {
        /// <summary>
        /// 厂家名称
        /// </summary>
        public abstract string Company { get; }

        /// <summary>
        /// 作者名称
        /// </summary>
        public virtual string Author { get { return "秦建辉"; } }

        /// <summary>
        /// 最多处理人脸的数目
        /// </summary>
        public abstract int MaxFaceNum { get; }

        /// <summary>
        /// 错误描述
        /// </summary>
        public string ErrorMessage { get; protected set; }

        /// <summary>
        /// 参数字典
        /// </summary>
        public Dictionary<string, object> Addons = new Dictionary<string, object>();

        /// <summary>
        /// 初始化接口
        /// </summary>
        /// <returns>
        ///     0:初始化接口成功
        ///     其它:错误编号
        /// </returns>
        public abstract int Initialize();

        /// <summary>
        /// 关闭接口
        /// </summary>
        public virtual void Close() { Dispose(); }

        /// <summary>
        /// 释放资源
        /// </summary>
        public virtual void Dispose() { ErrorMessage = null; }

        /// <summary>
        /// 人脸位置信息检测
        /// </summary>
        /// <param name="image">图像数据</param>
        /// <param name="faces">输出:人脸位置信息</param>
        /// <returns>
        ///     0:操作成功
        ///     其它:错误编号
        /// </returns>
        public abstract int Detect(byte[] image, out Int32Rect[] faces);

        /// <summary>
        /// 人脸细节信息检测
        /// </summary>
        /// <param name="image">图像数据</param>
        /// <param name="faces">输出:人脸细节信息</param>
        /// <returns>
        ///     0:操作成功
        ///     其它:错误编号
        /// </returns>
        public abstract int DetectDetails(byte[] image, out Newtonsoft.Json.Linq.JArray faces);

        /// <summary>
        /// 人脸匹配
        /// </summary>
        /// <param name="imagea">源图像</param>
        /// <param name="facetypea">源图像人脸类型</param>
        /// <param name="imageb">目标图像</param>
        /// <param name="facetypeb">目标图像人脸类型</param>
        /// <param name="score">输出:图像相似度</param>
        /// <returns>
        ///     0:操作成功
        ///     其它:错误编号
        /// </returns>
        public abstract int Match(byte[] imagea, string facetypea, byte[] imageb, string facetypeb, out float score);

        /// <summary>
        /// 网址编码
        /// </summary>
        /// <param name="str">要编码的字符串</param>
        /// <param name="e">字符编码方案</param>
        /// <param name="uppercase">是否输出大写字母</param>
        /// <returns>编码字符串</returns>
        public static string UrlEncode(string str, Encoding e, bool uppercase = false)
        {
            if (uppercase)
            {
                return Regex.Replace(System.Web.HttpUtility.UrlEncode(str, e), @"%[0-9a-f]{2}", m => m.Value.ToUpper());
            }
            else
            {
                return System.Web.HttpUtility.UrlEncode(str, e);
            }
        }

        /// <summary>
        /// 将字节数组转换为16进制编码字符串
        /// </summary>
        /// <param name="buffer">要转换的字节数组</param>
        /// <param name="uppercase">是否输出大写字母</param>
        /// <returns>16进制编码字符串</returns>
        public static string ToHexString(byte[] buffer, bool uppercase = false)
        {
            StringBuilder sb = new StringBuilder();
            if (uppercase)
            {
                foreach (byte b in buffer) sb.Append(b.ToString("X2"));
            }
            else
            {
                foreach (byte b in buffer) sb.Append(b.ToString("x2"));
            }

            return sb.ToString();
        }
    }
}

BaiduFr.cs

/* ----------------------------------------------------------
 * 文件名称:BaiduFr.cs
 * 作者:秦建辉
 * 
 * 微信:splashcn
 * 
 * 博客:http://www.firstsolver.com/wordpress/
 * 
 * 开发环境:
 *      Visual Studio V2017
 *      .NET Framework 4
 *      Newtonsoft.Json 11.0.2
 *      
 * 版本历史:
 *      V1.1    2018年09月20日
 *              接口增强
 *              
 *      V1.0    2018年03月27日
 *              百度人脸识别类实现
 * 
 * 说明:
 *      人脸检测V3:https://aip.baidubce.com/rest/2.0/face/v3/detect
 *      人脸比对V3:https://aip.baidubce.com/rest/2.0/face/v3/match
------------------------------------------------------------ */
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Windows;

namespace Com.FirstSolver.FR
{
    public class BaiduFr : FrCore
    {
        /// <summary>
        /// 厂家名称
        /// </summary>
        public override string Company { get { return "百度"; } }

        /// <summary>
        /// 最多处理人脸的数目
        /// </summary>
        public override int MaxFaceNum { get { return 10; } }

        /// <summary>
        /// 应用标识
        /// </summary>
        private const string API_KEY = "Vnrv8o6lmHm3jAYsB62tZBod";

        /// <summary>
        /// 应用密钥
        /// </summary>
        private const string API_SECRET = "VmYQyST8kq3s0HcrGcdRHcLbxeGwNQDe";

        /// <summary>
        /// 访问授权码
        /// </summary>
        public string AccessToken { get; private set; }

        /// <summary>
        /// 人脸识别接口初始化
        /// </summary>
        /// <returns>
        ///     0-成功
        ///     其它-失败
        /// </returns>
        public override int Initialize()
        {
            ErrorMessage = null;

            // 获取授权码,授权服务地址:https://aip.baidubce.com/oauth/2.0/token
            StringBuilder sb = new StringBuilder();
            sb.Append("https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=").Append(API_KEY).Append("&client_secret=").Append(API_SECRET);

            try
            {
                if (!(WebRequest.Create(sb.ToString()) is HttpWebRequest httpWebRequest))
                {
                    return -1;
                }

                using (HttpWebResponse response = httpWebRequest.GetResponse() as HttpWebResponse)
                {
                    using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                    {
                        AccessToken = JObject.Parse(sr.ReadToEnd())["access_token"].ToString();
                        return 0;
                    }
                }
            }
            catch (Exception e)
            {
                ErrorMessage = e.Message;
                return -2;
            }
        }

        /// <summary>
        /// 获取人脸检测结果
        /// </summary>
        /// <param name="url">人脸检测访问接口</param>
        /// <param name="options">人脸检测参数</param>
        /// <returns>人脸检测结果</returns>
        public static JObject DoHttpPost(string url, string options)
        {
            if (!(WebRequest.Create(url) is HttpWebRequest httpWebRequest)) return null;

            httpWebRequest.Method = "POST";
            httpWebRequest.KeepAlive = true;
            httpWebRequest.ContentType = "application/json"; // 内容类型

            byte[] Args = Encoding.UTF8.GetBytes(options);
            httpWebRequest.ContentLength = Args.Length;
            using (Stream requestStream = httpWebRequest.GetRequestStream())
            {
                requestStream.Write(Args, 0, Args.Length);
            }

            using (HttpWebResponse response = httpWebRequest.GetResponse() as HttpWebResponse)
            {
                using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                {
                    return JObject.Parse(sr.ReadToEnd());
                }
            }
        }

        /// <summary>
        /// 创建人脸检测调用参数
        /// </summary>
        /// <param name="image">图像数据</param>
        /// <returns>人脸检测调用参数</returns>
        private string CreateFaceDetectParameters(byte[] image)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("{\"image\":\"").Append(Convert.ToBase64String(image)).Append("\",\"image_type\":\"BASE64\"");
            foreach (KeyValuePair<string, object> item in Addons)
            {
                if (item.Value != null)
                {
                    sb.Append(",\"").Append(item.Key).Append("\":\"").Append(item.Value.ToString()).Append("\"");
                }
            }
            sb.Append("}");

            return sb.ToString();
        }

        public override int Detect(byte[] image, out Int32Rect[] faces)
        {
            ErrorMessage = null;
            faces = null;

            try
            {
                string options = CreateFaceDetectParameters(image);
                string url = "https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=" + AccessToken;
                while (true)
                {
                    var result = DoHttpPost(url, options);
                    var error_code = (int)result["error_code"];
                    if (error_code == 0)
                    {
                        if ((int)result["result"]["face_num"] == 0)
                        {
                            ErrorMessage = "未检测出人脸";
                            return -1;
                        }

                        JArray FaceJArray = result["result"]["face_list"] as JArray;
                        List<Int32Rect> FaceCollection = new List<Int32Rect>();
                        foreach (dynamic item in FaceJArray)
                        {
                            var location = item["location"];
                            FaceCollection.Add(new Int32Rect((int)location["left"], (int)location["top"], (int)location["width"], (int)location["height"]));
                        }

                        faces = FaceCollection.ToArray();
                        return 0; // 成功
                    }
                    else if (error_code == 18)
                    {   // Open api qps request limit reached
                        continue;
                    }
                    else
                    {
                        ErrorMessage = result["error_msg"].ToString();
                        return -1; // 人脸检测失败
                    }
                }
            }
            catch (System.Exception e)
            {
                ErrorMessage = e.Message;
                return -2; // 异常
            }
        }

        public override int DetectDetails(byte[] image, out JArray faces)
        {
            ErrorMessage = null;
            faces = null;

            try
            {
                string options = CreateFaceDetectParameters(image);
                string url = "https://aip.baidubce.com/rest/2.0/face/v3/detect?access_token=" + AccessToken;
                while (true)
                {
                    var result = DoHttpPost(url, options);
                    var error_code = (int)result["error_code"];
                    if (error_code == 0)
                    {
                        if ((int)result["result"]["face_num"] == 0)
                        {
                            ErrorMessage = "未检测出人脸";
                            return -1;
                        }

                        faces = result["result"]["face_list"] as JArray;
                        return 0; // 成功
                    }
                    else if (error_code == 18)
                    {   // Open api qps request limit reached
                        continue;
                    }
                    else
                    {
                        ErrorMessage = result["error_msg"].ToString();
                        return -1; // 人脸检测失败
                    }
                }
            }
            catch (System.Exception e)
            {
                ErrorMessage = e.Message;
                return -2; // 异常
            }
        }

        /// <summary>
        /// 创建人脸匹配调用参数
        /// </summary>
        /// <param name="imagea">人脸图像A</param>
        /// <param name="facetypea">图像A人脸类型</param>
        /// <param name="imageb">人脸图像B</param>
        /// <param name="facetypeb">图像B人脸类型</param>
        /// <returns>人脸匹配调用参数</returns>
        private string CreateFaceMatchParameters(byte[] imagea, string facetypea, byte[] imageb, string facetypeb)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("[{\"image\":\"").Append(Convert.ToBase64String(imagea)).Append("\",\"image_type\":\"BASE64\"").Append(",\"face_type\":\"").Append(facetypea).Append("\"}");
            sb.Append(",{\"image\":\"").Append(Convert.ToBase64String(imageb)).Append("\",\"image_type\":\"BASE64\"").Append(",\"face_type\":\"").Append(facetypeb).Append("\"}]");

            return sb.ToString();
        }

        public override int Match(byte[] imagea, string facetypea, byte[] imageb, string facetypeb, out float score)
        {
            ErrorMessage = null;
            score = float.MinValue;

            try
            {
                string options = CreateFaceMatchParameters(imagea, facetypea, imageb, facetypeb);
                string url = "https://aip.baidubce.com/rest/2.0/face/v3/match?access_token=" + AccessToken;
                while (true)
                {
                    var result = DoHttpPost(url, options);
                    var error_code = (int)result["error_code"];
                    if (error_code == 0)
                    {
                        score = (float)result["result"]["score"];
                        return 0; // 成功
                    }
                    else if (error_code == 18)
                    {   // Open api qps request limit reached
                        continue;
                    }
                    else
                    {
                        ErrorMessage = result["error_msg"].ToString();
                        return -1; // 人脸匹配失败
                    }
                }
            }
            catch (System.Exception e)
            {
                ErrorMessage = e.Message;
                return -2; // 异常
            }
        }
    }
}

Comments are closed.