C#调用Face++ API实现人脸融合

文章目录

  • 一、人脸融合原理
  • 二、代码实现
    • 1.注册账号
    • 2.创建发送请求和反馈的类
    • 3.实现融合
    • 4.生成图片

引言:
随着AI人工智能的发展,物联网技术逐渐进入平常百姓家,而人脸融合技术更能体现AI人工智能的发展,人脸融合技术算是比较“老”的技术,在众多的如美图秀秀等修图软件面前此技术很是渺茫,本博客为什么要写关于人脸融合呢?因为在项目中用到了,也是学习新技术,用此博客来记录,方便后期再次使用。

一、人脸融合原理

C#调用Face++ API实现人脸融合_第1张图片

给定一个模板图,根据“人脸位置检测”接口获取到脸部准确位置( “top”, “left”,“width”,“height”),将要融合的图通过发送请求给第三方接口,反馈一个json格式的字符串,从字符串中提取出“result”对应的字符串,即融合成的图片base64格式的字符串,再将base64格式字符串图片格式转成图片。

二、代码实现

1.注册账号

在Face++网站注册个人Key和Secert
Web API:https://console.faceplusplus.com.cn/documents/5671787

2.创建发送请求和反馈的类

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Web;

namespace Coommon
{
    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<string, object> postParameters)
        {
            string text = string.Format("----------{0:N}", Guid.NewGuid());
            string contentType = "multipart/form-data; boundary=" + text;//multipart类型
            byte[] multipartFormData = HttpHelper4MultipartForm.GetMultipartFormData(postParameters, text);
            return HttpHelper4MultipartForm.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<string, object> postParameters, string boundary)
        {
            Stream stream = new MemoryStream();
            bool flag = false;
            foreach (KeyValuePair<string, object> current in postParameters)
            {
                if (flag)
                {
                    stream.Write(HttpHelper4MultipartForm.encoding.GetBytes("\r\n"), 0, HttpHelper4MultipartForm.encoding.GetByteCount("\r\n"));
                }
                flag = true;
                if (current.Value is HttpHelper4MultipartForm.FileParameter)
                {
                    HttpHelper4MultipartForm.FileParameter fileParameter = (HttpHelper4MultipartForm.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(HttpHelper4MultipartForm.encoding.GetBytes(s), 0, HttpHelper4MultipartForm.encoding.GetByteCount(s));
                    stream.Write(fileParameter.File, 0, fileParameter.File.Length);
                }
                else
                {
                    string s2 = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}", boundary, current.Key, current.Value);
                    stream.Write(HttpHelper4MultipartForm.encoding.GetBytes(s2), 0, HttpHelper4MultipartForm.encoding.GetByteCount(s2));
                }
            }
            string s3 = "\r\n--" + boundary + "--\r\n";
            stream.Write(HttpHelper4MultipartForm.encoding.GetBytes(s3), 0, HttpHelper4MultipartForm.encoding.GetByteCount(s3));
            stream.Position = 0L;
            byte[] array = new byte[stream.Length];
            stream.Read(array, 0, array.Length);
            stream.Close();
            return array;
        }
    }
}

3.实现融合

此处我创建了一个方法,给定两个参数:模板图路径和融合图的路径,返回第三方接口反馈的结果字符串

		/// 
        /// 调用三方接口实现图片合成
        /// 
        /// 人脸融合的模板图
        /// 人脸融合的融合图
        [HttpPost]
        public string PostSend(string tempImg,string mergeImg) {
            try
            {
                //用来存储接口参数值
                Dictionary<string, object> verifyPostParameters = new Dictionary<string, object>();
                var key = "xxxxxxxxxxxxxxxxx";//注册后得到的key
                var secret = "xxxxxxxxxxxxxxxxxxxxx";//注册后得到的secret
                //接口必须参数一
                verifyPostParameters.Add("api_key", key);
                //接口必须参数二
                verifyPostParameters.Add("api_secret", secret);
                //(模板图)
                Bitmap bmp = new Bitmap(tempImg); // 图片地址
                byte[] fileImage;
                using (Stream stream1 = new MemoryStream())
                {
                    bmp.Save(stream1, ImageFormat.Jpeg);
                    byte[] arr = new byte[stream1.Length];
                    stream1.Position = 0;
                    stream1.Read(arr, 0, (int)stream1.Length);
                    stream1.Close();
                    fileImage = arr;
                }
                //接口必须参数三 模板图的路径地址,必须以post multipart/form-data 的方式上传(此处通过调用HTTPHelper4MultipartForm的方法已实现)
                verifyPostParameters.Add("template_file", new HttpHelper4MultipartForm.FileParameter(fileImage, "1.jpg", "application/octet-stream"));
                //接口可选参数 脸部坐标位置
                verifyPostParameters.Add("template_rectangle", "415,225,402,402");
                //(融合图)
                Bitmap bmp2 = new Bitmap(mergeImg); // 图片地址
                byte[] fileImage2;
                using (Stream stream2 = new MemoryStream())
                {
                    bmp2.Save(stream2, ImageFormat.Jpeg);
                    byte[] arr2 = new byte[stream2.Length];
                    stream2.Position = 0;
                    stream2.Read(arr2, 0, (int)stream2.Length);
                    stream2.Close();
                    fileImage2 = arr2;
                }
                //接口必须参数四 融合图的路径地址,必须以post multipart/form-data 的方式上传(此处通过调用HTTPHelper4MultipartForm的方法已实现)
                verifyPostParameters.Add("merge_file", new HttpHelper4MultipartForm.FileParameter(fileImage2, "2.jpg", "application/octet-stream"));
                //调用HttpHelper4MultipartForm的MultipartFormDataPost方法实现post提交并反馈第三方提供的返回结果
                HttpWebResponse verifyResponse = HttpHelper4MultipartForm.MultipartFormDataPost("https://api-cn.faceplusplus.com/imagepp/v1/mergeface", "", verifyPostParameters);
                
                //此处获取反馈的流来读取json格式的字符串,因为图片的字符串非常的“大”,必须循环获取,此操作在HttpHelper4MultipartForm类的MultipartFormDataPost方法中已经实现,所以在调用反馈的字符串是这个地方只需将它全部读取。
                var res = verifyResponse.GetResponseStream();
                StreamReader sr = new StreamReader(res, Encoding.ASCII);
                string reslut= sr.ReadToEnd();
                sr.Close();
                res.Close();
                verifyResponse.Close();
                return reslut;
            }
            catch (WebException ex)
            {

                HttpWebResponse res = (HttpWebResponse)ex.Response;
                Stream myResponseStream = res.GetResponseStream();
                StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.Default);
                string retString = myStreamReader.ReadToEnd();
                return retString;
            }
        }

实现步骤:
(1)创建 Dictionary verifyPostParameters = new Dictionary();用来存储第三方接口所需的参数和值
(2)赋值 给所需的参数赋值:

var key = “xxxxxxxxxxxxxxxxx”;//注册后得到的key
var secret = “xxxxxxxxxxxxxxxxxxxxx”;//注册后得到的secret
verifyPostParameters.Add(“api_key”, key);//必须参数
verifyPostParameters.Add(“api_secret”, secret);//必须参数
verifyPostParameters.Add(“template_file”, new HttpHelper4MultipartForm.FileParameter(fileImage, “1.jpg”, “application/octet-stream”));//必须参数(模板图片文件) 需要post multipart/form-data 的方式上传
verifyPostParameters.Add(“template_rectangle”, “415,225,402,402”);//接口可选参数 脸部坐标位置
可以通过 接口"人脸位置检测"获取到脸部位置 https://www.faceplusplus.com.cn/face-detection/
verifyPostParameters.Add(“merge_file”, new HttpHelper4MultipartForm.FileParameter(fileImage2, “2.jpg”, “application/octet-stream”));//必须参数(融合图片文件) 需要post multipart/form-data 的方式上传

(3)调用 HttpHelper4MultipartForm类的MultipartFormDataPost实现发送请求和反馈结果

	HttpWebResponse verifyResponse = HttpHelper4MultipartForm.MultipartFormDataPost("https://api-cn.faceplusplus.com/imagepp/v1/mergeface", "", verifyPostParameters);

(4)获取 读取反馈的流,得到json格式字符串,其中包含base64格式的图片字符串。
此处需注意要通过循环读取反馈的字符串,不然读取到的字符串不完整,出现一系列的报错。(此处已在HttpHelper4MultipartForm类中循环)

			var res = verifyResponse.GetResponseStream();
                StreamReader sr = new StreamReader(res, Encoding.ASCII);
                string reslut= sr.ReadToEnd();

4.生成图片

	//模板图
   var tempImg = Server.MapPath(@"~\Image\Template\1.jpg");
   //融合图
   var mergeImg = system.SourceFolder + "\\" + imgname + ".jpg";
   //调用三方接口生成字符串
   string postset = PostSend(tempImg, mergeImg);
   //将得到的json格式字符串转换得到图片字符串
   JObject read = JsonConvert.DeserializeObject<JObject>(postset);
   string resul = read["result"].ToString();//图片字符串
   string err = read["error_message"].ToString();//错误信息
   string id = read["request_id"].ToString();//所用时间
   Bitmap Phon = ToImage(resul);//生成的图片
	/// 
    /// 将Base64字符串转换为图片
    /// 
    /// base64格式图片字符串
    private Bitmap ToImage(string base64)
    {
    		try
            {
                byte[] bytes = Convert.FromBase64String(base64);
                MemoryStream ms = new MemoryStream();
                ms.Write(bytes, 0, bytes.Length);
                Bitmap bmp = new Bitmap(ms);
                return bmp;
            }
            catch (Exception ex)
            {

                throw ex;
            }
    }

实现步骤:
(1)得到 模板图和融合图的图片文件路径地址;
(2)调用 生成反馈的字符串方法;

	string postset = PostSend(tempImg, mergeImg);

(3)转换 将得到的json格式字符串转换成json,得到图片字符串和错误信息字符串,及其他反馈参数字符串;

	JObject read = JsonConvert.DeserializeObject<JObject>(postset);
   string resul = read["result"].ToString();//图片字符串
   string err = read["error_message"].ToString();//错误信息
   string id = read["request_id"].ToString();//所用时间

(4)调用 转换成图片的方法;

	Bitmap Phon = ToImage(resul);//生成的图片

帮助文档:
Merge Face API (V1): https://console.faceplusplus.com.cn/documents/20813963
注册帮助文档:https://console.faceplusplus.com.cn/documents/5671787
人脸位置检测: https://www.faceplusplus.com.cn/face-detection/
HttpHelper4MultipartForm类参考:https://console.faceplusplus.com.cn/documents/6329752

你可能感兴趣的:(.NET,C#,Face++,API,人脸融合)