Face++提供的 人脸识别 SDK 和 公开的API 可以实现精确的人脸识别,返回多达106个识别点,是目前市面上非常理想的人脸识别产品。这里记录一下 通过Unity 使用c# 调用Face++的detect API的过程。
首先申请Face++账号,创建应用、绑定BundleID(BundleID 与 unity 中PlaySetting的Package Name 保持一致)等必备条件,具体步骤 在Face++的官网上有详细流程点击打开链接,对于Detect API的调用参数介绍等点击打开链接。
调用代码:静态类 HttpHelper4MultipartForm
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using UnityEngine;
namespace MgLiveCOM_Eyes
{
public static class HttpHelper4MultipartForm
{
public class FileParameter
{
public byte[] File
{
get;
set;
}
public string FileName
{
get;
set;
}
public string ContentType
{
get;
set;
}
public FileParameter(byte[] file) : this(file, null)
{
}
public FileParameter(byte[] file, string filename) : this(file, filename, null)
{
}
public FileParameter(byte[] file, string filename, string contenttype)
{
this.File = file;
this.FileName = filename;
this.ContentType = contenttype;
}
}
private static readonly Encoding encoding = Encoding.UTF8;
///
/// MultipartForm请求
///
/// 服务地址
///
/// 参数
///
public static HttpWebResponse MultipartFormDataPost(string postUrl, string userAgent, Dictionary postParameters)
{
string text = string.Format("----------{0:N}", Guid.NewGuid());
string contentType = "multipart/form-data; boundary=" + text;//multipart类型
Debug.Log("contentType " + contentType);
byte[] multipartFormData = GetMultipartFormData(postParameters, text);
return PostForm(postUrl, userAgent, contentType, multipartFormData);
}
private static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, byte[] formData)
{
HttpWebRequest httpWebRequest = WebRequest.Create(postUrl) as HttpWebRequest;
if (httpWebRequest == null)
{
throw new NullReferenceException("request is not a http request");
}
httpWebRequest.Method = "POST";//post方式
httpWebRequest.SendChunked = false;
httpWebRequest.KeepAlive = true;
httpWebRequest.Proxy = null;
httpWebRequest.Timeout = Timeout.Infinite;
httpWebRequest.ReadWriteTimeout = Timeout.Infinite;
httpWebRequest.AllowWriteStreamBuffering = false;
httpWebRequest.ProtocolVersion = HttpVersion.Version11;
httpWebRequest.ContentType = contentType;
httpWebRequest.CookieContainer = new CookieContainer();
httpWebRequest.ContentLength = (long)formData.Length;
try
{
using (Stream requestStream = httpWebRequest.GetRequestStream())
{
int bufferSize = 4096;
int position = 0;
while (position < formData.Length)
{
bufferSize = Math.Min(bufferSize, formData.Length - position);
byte[] data = new byte[bufferSize];
Array.Copy(formData, position, data, 0, bufferSize);
requestStream.Write(data, 0, data.Length);
position += data.Length;
}
requestStream.Close();
}
}
catch (Exception ex)
{
return null;
}
HttpWebResponse result;
try
{
result = (httpWebRequest.GetResponse() as HttpWebResponse);
}
catch (WebException arg_9C_0)
{
result = (arg_9C_0.Response as HttpWebResponse);
}
return result;
}
public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
return true;
}
///
/// 从表单中获取数据
///
///
///
///
private static byte[] GetMultipartFormData(Dictionary postParameters, string boundary)
{
Stream stream = new MemoryStream();
bool flag = false;
foreach (KeyValuePair current in postParameters)
{
if (flag)
{
stream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));
}
flag = true;
if (current.Value is FileParameter)
{
FileParameter fileParameter = (FileParameter)current.Value;
string s = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n", new object[]
{
boundary,
current.Key,
fileParameter.FileName ?? current.Key,
fileParameter.ContentType ?? "application/octet-stream"
});
stream.Write(encoding.GetBytes(s), 0, encoding.GetByteCount(s));
stream.Write(fileParameter.File, 0, fileParameter.File.Length);
Debug.Log("s1 " + s);
}
else
{
string s2 = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\";\r\n\r\n{2}", boundary, current.Key, current.Value);
Debug.Log("s2 " + s2);
stream.Write(encoding.GetBytes(s2), 0, encoding.GetByteCount(s2));
}
}
string s3 = "\r\n--" + boundary + "--\r\n";
Debug.Log("s3 " + s3);
stream.Write(encoding.GetBytes(s3), 0, encoding.GetByteCount(s3));
stream.Position = 0L;
byte[] array = new byte[stream.Length];
stream.Read(array, 0, array.Length);
stream.Close();
Debug.Log("array " + array.Length);
return array;
}
}
}
具体调用类:Test
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using MgLiveCOM_Eyes;
using System.IO;
using System;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Text;
public class Test : MonoBehaviour {
//参数字典
Dictionary verifyPostParameters = new Dictionary();
public void TestFunc()
{
verifyPostParameters.Add("api_key", "MyKey");
verifyPostParameters.Add("api_secret", "MySecret");
verifyPostParameters.Add("return_landmark", "1");
verifyPostParameters.Add("return_attributes", "gender,age,smiling,headpose,facequality,blur,eyestatus,emotion,ethnicity,beauty,mouthstatus,eyegaze,skinstatus");
byte[] fileImage = GetPictureData(Application.dataPath + "/Images/test0.jpg");
//string base64S = ToBase64();
// 使用参数 image _base64
//verifyPostParameters.Add("image_base64", base64S);
// 使用参数 image_file
verifyPostParameters.Add("image_file", new HttpHelper4MultipartForm.FileParameter(fileImage, "1.jpg", "application/octet-stream"));
// 使用参数 image_url
// verifyPostParameters.Add("image_url", "http://yutoar-test.oss-cn-shenzhen.aliyuncs.com/test/girl.jpg");
// test
ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;
HttpWebResponse verifyResponse = HttpHelper4MultipartForm.MultipartFormDataPost("https://api-cn.faceplusplus.com/facepp/v3/detect", "", verifyPostParameters);
if (verifyResponse != null)
{
StreamReader sr = new StreamReader(verifyResponse.GetResponseStream(), Encoding.UTF8);
string sReturn = sr.ReadToEnd().Trim();
Debug.Log(" " + sReturn);
sr.Close();
}
else
Debug.Log("返回数据为空!");
}
//转化图片为字节数组
private byte[] GetPictureData(string imagePath)
{
FileStream fs = new FileStream(imagePath,FileMode.Open);
byte[] byData = new byte[fs.Length];
fs.Read(byData,0,byData.Length);
fs.Close();
return byData;
}
///
/// 将图片数据转换为Base64字符串
///
///
///
private string ToBase64()
{
byte[] bytes = GetPictureData(Application.dataPath + "/Images/test1.jpg");
string base64 = Convert.ToBase64String(bytes);
return base64;
}
public bool MyRemoteCertificateValidationCallback(System.Object sender,
X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
bool isOk = true;
// If there are errors in the certificate chain,
// look at each error to determine the cause.
if (sslPolicyErrors != SslPolicyErrors.None)
{
for (int i = 0; i < chain.ChainStatus.Length; i++)
{
if (chain.ChainStatus[i].Status == X509ChainStatusFlags.RevocationStatusUnknown)
{
continue;
}
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
bool chainIsValid = chain.Build((X509Certificate2)certificate);
if (!chainIsValid)
{
isOk = false;
break;
}
}
}
return isOk;
}
}
具体代码如上,与官网给出的代码差不多,直接使用官网代码在静态类的 PostForm的catch中会抛出异常,返回空,异常信息如下 “The authentication or decryption has failed”,
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
然后增加一个方法:
public bool MyRemoteCertificateValidationCallback(System.Object sender,
X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
bool isOk = true;
// If there are errors in the certificate chain,
// look at each error to determine the cause.
if (sslPolicyErrors != SslPolicyErrors.None)
{
for (int i = 0; i < chain.ChainStatus.Length; i++)
{
if (chain.ChainStatus[i].Status == X509ChainStatusFlags.RevocationStatusUnknown)
{
continue;
}
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
bool chainIsValid = chain.Build((X509Certificate2)certificate);
if (!chainIsValid)
{
isOk = false;
break;
}
}
}
return isOk;
}
最后在调用post请求之前 添加这句代码
ServicePointManager.ServerCertificateValidationCallback = MyRemoteCertificateValidationCallback;
就可以正常调用API啦~
从返回的HttpWebResponse 类型数据中 取出返回信息:
StreamReader sr = new StreamReader(verifyResponse.GetResponseStream(), Encoding.UTF8);
string sReturn = sr.ReadToEnd().Trim();
完结~