Unity 百度AI实现无绿幕拍照抠像功能(详解版)

打印 上一主题 下一主题

主题 592|帖子 592|积分 1776

目录

一、前言
1.抠像效果
2.去哪找百度ai抠图
3.基础流程跳过 
二、获取AccessToken
1.什么是Token
2.为什么要获取Token
3.如何获取token
4.剖析json
5.完整代码
三、抠像
1.准备地点
2.建立链接,和根本配置
3.图片格式转换
4.开始上传
5.获取回复
6.剖析json
7.纯净代码
四、作者的碎碎念


一、前言

1.抠像效果

抠像效果一般,边沿还是会生硬,然后用羽化来过渡。(如图1所示)
   
     图1 抠像    这是网上找的图,侵权删。
2.去哪找百度ai抠图

在百度,这个功能叫人像分割,链接如下。
人像分割技能_人像分割算法_人像分割-百度AI开放平台
3.基础流程跳过 

接下来注册账号之类的,咱就跳过了哈。
过程:
1.注册百度的账号
2.实名认证
3.领百度送的,对应功能的利用次数(我测试的时候送1w次,有用期一年)。
4.创建应用(这个不需要你有做好的程序,只需要走一下游程就行),这里走流程的意义就是,百度有许多功能,你需要什么功能选一下,然后我们给你一个账户和暗码,这样你才气调用这些功能。
5.你就获得了一组账户和暗码(如图2所示)
   
     图2 账号和暗码      api Key和Secret Key
  api Key:api的英文是Application Programming Interface,应用程序编程接口的缩写,到这里就是我们获取了可以用来实现人像分割这个功能的用户名。
  Secret Key:就是秘钥,上面用户名的暗码。
  
  上面两个Key,只要你自己不去更新,一般是不会改变的
  但是,如果你的调用行为百度以为很奇怪,也会临时给你封了。
    备注:百度ai有许多功能,假如百度ai是一个手机,手机里面装了许多个app,但是你登录每一个app都需要不同的用户名和暗码。
  这里就是,我们通过百度这个总的账号,去选择了自己想要的功能,然后百度给你生成一个用户名和暗码,你通过这个可以利用你选好的功能。
  二、获取AccessToken

1.什么是Token

不知道大家去过东北澡堂子没有,进去的时候,会被发一个手牌。(如图3所示)
   
     图3 手牌    然后你只要带着这个手牌,就可以在澡堂子里吃饭,消费等,末了出来的时候,带着手牌去结账就行了。不同的手牌会有不同的权限,好比平凡宾客,贵宾,vip,超级vip什么的。手牌上面还会有号码,号码就类似身份证号一样,大家都不一样,用来辨认。
   弄这个手牌的目的大致有两种:
  1.澡堂子里有许多水,一直带着手机很麻烦,但不带手机,又会不知道你是哪一个宾客。
  2.手机不能直观的看出来你是哪种宾客,但是牌子可以。
  Token和这个手牌根本是一样的,你先把自己的账号和暗码上交,根据你购买的套餐,会给你一串序列号,在肯定的时间内,你只要提交序列号就可以用你购买的功能,百度也知道是哪个账号购买的。
2.为什么要获取Token

我们可以直接用账号和暗码访问,我们也能利用token访问,但是,因为是用互联网通报消息,如果用账号和暗码,那你每一次提出哀求都要提供账户和暗码,这样不是很安全,黑客一拦截一个准,所以,换成token,就减少了提交用户和暗码的次数,就安全许多。
可以简单这么理解一下,至于过细的,大家可以自行百度,但总之,有这么一个流程。
3.如何获取token

这个可以在百度的官方文档中找到。在百度,这部分官方的名称叫做鉴权认证机制。
https://ai.baidu.com/ai-doc/REFERENCE/Ck3dwjhhu
想看官方的可以看官方的,或者看我的也可以。
   获取token需要三个东西:
  1.往哪个网站发哀求
  (上面的官方链接里有写,往https://aip.baidubce.com/oauth/2.0/token?发哀求)
  2.用户名(前言里获取过)
  3.暗码(前言里获取过)
  在代码里,我们可以先把他们写出来。
我们的目的是获取token,我们可以再建一个字符串用来接token。(如图4所示)
   
     图4 常用字符   
  1. void Start()
  2. {
  3.      GetToken();
  4. }
  5. public void GetToken()
  6. {
  7.      //声明一个客户端,就是自己
  8.      HttpClient client = new HttpClient();
  9.      //建立一个字典,把我们需要的信息都放进去
  10.      //但是建立字典的类型是KeyValuePair,因为我们后面要传递数据
  11.      List<KeyValuePair<String, String>> paraList = new List<KeyValuePair<string, string>>();
  12.      paraList.Add(new KeyValuePair<string, string>("client_id", client_id));
  13.      paraList.Add(new KeyValuePair<string, string>("client_secret", client_secret));
  14.      paraList.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
  15.                                                                  //这里本来要放httpContent,但是这个方法可以把
  16.      //接受网络的回复                                               //keyValuePair转换成httpContent
  17.      HttpResponseMessage response = client.PostAsync(token_url, new FormUrlEncodedContent(paraList)).Result;
  18.      //最后接受回复,转换成string
  19.      string resultJson = response.Content.ReadAsStringAsync().Result;
  20.      //打印一下string
  21.      Debug.Log(resultJson);
  22. }
复制代码
打印效果为:
   
     图5 打印效果    你会得到一大堆数据,其中有一个部分是access_token,我们要的就是这部分,这部分就是token。
4.剖析json

得到数据后,这个数据是json格式的数据,如果你会剖析json数据,就可以自己解决了。
如果解决不了,你也可以采用string的手法直接弄出来。
up很懒,用了一个叫LitJson.dll,里面直接有剖析的方法。
  1.         //先读取json格式的文本
  2.         JsonReader json = new JsonReader(resultJson);
  3.         //把上面读取的文本转换成可以直接调用的数据格式
  4.         JsonData jsonData = JsonMapper.ToObject<JsonData>(json);
  5.         //直接获取名称是access_token后面的数据        
  6.         jsonData["access_token"].ToString();
复制代码
5.完整代码

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Net.Http;
  4. using LitJson;
  5. using UnityEngine;
  6. public class GetAccessToken : MonoBehaviour
  7. {
  8.     //网址
  9.     string token_url = "https://aip.baidubce.com/oauth/2.0/token?";
  10.     //用户名
  11.     string client_id = "填自己的id";
  12.     //密码
  13.     string client_secret = "填自己的密码";
  14.     //token
  15.     public string token;
  16.     void Start()
  17.     {
  18.         token = GetToken();
  19.         Debug.Log("获得token:" + token);
  20.     }
  21.     public string GetToken()
  22.     {
  23.         HttpClient client = new HttpClient();
  24.         List<KeyValuePair<String, String>> paraList = new List<KeyValuePair<string, string>>();
  25.         paraList.Add(new KeyValuePair<string, string>("client_id", client_id));
  26.         paraList.Add(new KeyValuePair<string, string>("client_secret", client_secret));
  27.         paraList.Add(new KeyValuePair<string, string>("grant_type", "client_credentials"));
  28.         HttpResponseMessage response = client.PostAsync(token_url, new FormUrlEncodedContent(paraList)).Result;
  29.         string resultJson = response.Content.ReadAsStringAsync().Result;
  30.         //Debug.Log(resultJson);
  31.         JsonReader json = new JsonReader(resultJson);
  32.         JsonData jsonData = JsonMapper.ToObject<JsonData>(json);
  33.             
  34.         return jsonData["access_token"].ToString();
  35.     }
  36. }
复制代码
三、抠像

官方文档:https://ai.baidu.com/ai-doc/BODY/Fk3cpyxua
可以自己去研究,也可以往下看我的。
起首从官方那里拿到网址:

然后准备一下中途要用的方法(这些方法均不是重点,都不讲了)
方法1:图片从Texture转换到Texture2D
  1.     //Texture转Texture2D
  2.     private Texture2D TextureToTexture2D(Texture texture)
  3.     {
  4.         width = texture.width;
  5.         height = texture.height;
  6.         Texture2D texture2D = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false);
  7.         RenderTexture currentRT = RenderTexture.active;
  8.         RenderTexture renderTexture = RenderTexture.GetTemporary(texture.width, texture.height, 32);
  9.         Graphics.Blit(texture, renderTexture);
  10.         RenderTexture.active = renderTexture;
  11.         texture2D.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
  12.         texture2D.Apply();
  13.         RenderTexture.active = currentRT;
  14.         RenderTexture.ReleaseTemporary(renderTexture);
  15.         return texture2D;
  16.     }
复制代码
方法2:图片从Texture2D转换为Base64
  1.     //texture2D转base64
  2.     public string TextureToBase64(Texture2D texture2D)
  3.     {
  4.         byte[] bytes;
  5.         bytes = texture2D.EncodeToPNG();
  6.         return Convert.ToBase64String(bytes);
  7.     }
复制代码
方法3:Base64转texture2D
  1.     //base转texture2D
  2.     public Texture2D Base64ToTexture2d(string base64)
  3.     {
  4.         byte[] bytes = Convert.FromBase64String(base64);
  5.         Texture2D tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
  6.         tex.LoadImage(bytes);
  7.         return tex;
  8.     }
复制代码
1.准备地点

在前面给出地点的基础上,加上我们前面获取的token
  1. //host地址
  2. string host = "https://aip.baidubce.com/rest/2.0/image-classify/v1/body_seg?“+”access_token=" + token;
复制代码
2.建立链接,和根本配置

  1. //设置编码格式是默认
  2. Encoding encoding = Encoding.Default;
  3. //发送请求到前面配好的网址
  4. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host);
  5. //这是前面要求的
  6. request.Method = "post";
  7. //一直保持链接
  8. request.KeepAlive = true;
复制代码
3.图片格式转换

这里假设我们有一个RawImage,名字叫photo,末了转换成buffer
  1. //获取图片并转换成texture2D
  2. Texture2D texture2D = TextureToTexture2D(photo.texture);
  3. //再转换成base64
  4. string base64 = TextureToBase64(texture2D);
  5. //转换成url格式
  6. string str = "image=" + HttpUtility.UrlEncode(base64);
  7. //转换成byte格式
  8. byte[] buffer = encoding.GetBytes(str);
复制代码
4.开始上传

  1. //获取长度
  2. request.ContentLength = buffer.Length;
  3. //发送请求
  4. request.GetRequestStream().Write(buffer, 0, buffer.Length);
复制代码
5.获取回复

  1. HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  2. StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.Default);
  3. string result = reader.ReadToEnd();
  4. Debug.Log("人像分割:" + result);
复制代码
6.剖析json

  1. JsonReader jr = new JsonReader(result);
  2. JsonData data = JsonMapper.ToObject<JsonData>(jr);
  3. //拿到的扣好的数据
  4. string picData = data["foreground"].ToString();
  5. Texture2D tex = Base64ToTexture2d(picData);
复制代码
7.纯净代码

  1. IEnumerator IBody_seg()
  2. {
  3.      string host = "https://aip.baidubce.com/rest/2.0/image-classify/v1/body_seg?“+”access_token=" + token;
  4.      Encoding encoding = Encoding.Default;
  5.      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(host);
  6.      request.Method = "post";
  7.      request.KeepAlive = true;
  8.      yield return null;
  9.      Texture2D texture2D = TextureToTexture2D(photo.texture);
  10.      string base64 = TextureToBase64(texture2D);
  11.      string str = "image=" + HttpUtility.UrlEncode(base64);
  12.      byte[] buffer = encoding.GetBytes(str);
  13.      request.ContentLength = buffer.Length;
  14.      request.GetRequestStream().Write(buffer, 0, buffer.Length);
  15.      yield return null;
  16.      HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  17.      StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.Default);
  18.      string result = reader.ReadToEnd();
  19.      Debug.Log("人像分割:" + result);
  20.      yield return null;
  21.      JsonReader jr = new JsonReader(result);
  22.      JsonData data = JsonMapper.ToObject<JsonData>(jr);
  23.      string picData = data["foreground"].ToString();
  24.      Texture2D tex = Base64ToTexture2d(picData);
  25.     //如果你有个image,可以使用图片
  26.      pic.sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), new Vector2(0, 0));
  27.      pic2.sprite = pic.sprite;
  28. }
复制代码
四、作者的碎碎念

如果有什么疑问,可以在批评区发出来讨论一下,我看见了会回复。
照片是直接在网上找的,侵权立删。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

自由的羽毛

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表