百度AI开放平台接入
作者:追风剑情 发布于:2021-8-9 17:39 分类:Unity3d
using System; using System.Collections; using System.Collections.Generic; using System.Net.Http; using UnityEngine; using UnityEngine.Networking; /// <summary> /// 百度AI开放平台 /// 人像分割 https://ai.baidu.com/tech/body/seg /// 在线文档 https://ai.baidu.com/ai-doc/BODY/Fk3cpyxua /// 错误码查询 https://ai.baidu.com/ai-doc/IMAGERECOGNITION/Rk3bcxhio /// /// 人像动漫化 https://ai.baidu.com/tech/imageprocess/selfie_anime /// 在线文档 https://ai.baidu.com/ai-doc/IMAGEPROCESS/Mk4i6olx5 /// </summary> public class BaiduAISDK : MonoBehaviour { //人像分割请求地址 public const string BODY_SEG_URL = "https://aip.baidubce.com/rest/2.0/image-classify/v1/body_seg"; public const string BODY_SEG_APP_ID = ""; public const string BODY_SEG_APP_KEY = ""; public const string BODY_SEG_APP_SECRET = ""; public AccessTokenResult bodySegAccessTokenResult; //人像分割完成 public Action<Texture2D, Texture2D, Texture2D> BodySegCompleted; //未检测到人像 public Action OnNotFoundPersionError; //人像分割失败 public Action BodySegError; //是否从人像分割图中裁剪出人物图片 public bool IsClipPersion = false; //是否将人像上下居中显示 public bool IsVeticallyMiddle = false; //人像动漫化请求地址 public const string SELFIE_ANIME_URL = "https://aip.baidubce.com/rest/2.0/image-process/v1/selfie_anime"; public const string SELFIE_ANIME_APP_ID = ""; public const string SELFIE_ANIME_APP_KEY = ""; public const string SELFIE_ANIME_APP_SECRET = ""; public AccessTokenResult selfieAnimeAccessTokenResult; //人像动漫化完成 public Action<Texture2D> SelfieAnimeCompleted; //人像动漫化失败 public Action SelfieAnimeError; //证书验证 public class AcceptCertificateHandler : CertificateHandler { //负责拒绝或接受在 https 请求上接收到的证书 protected override bool ValidateCertificate(byte[] certificateData) { return true; } } private void Start() { Debug.Log("*** request body_seg access token..."); bodySegAccessTokenResult = GetAccessToken(BODY_SEG_APP_KEY, BODY_SEG_APP_SECRET); if (string.IsNullOrEmpty(bodySegAccessTokenResult.access_token)) Debug.LogError("request body_seg access token failure"); Debug.Log("*** request selfie_anime access token..."); selfieAnimeAccessTokenResult = GetAccessToken(SELFIE_ANIME_APP_KEY, SELFIE_ANIME_APP_SECRET); if (string.IsNullOrEmpty(selfieAnimeAccessTokenResult.access_token)) Debug.LogError("request selfie_anime access token failure"); } //base64转Texture2D private Texture2D Base64ToTexture(string base64, int width, int height) { byte[] imgBytes = Convert.FromBase64String(base64); Texture2D new_tex = new Texture2D(width, height, TextureFormat.RGBA32, false); new_tex.LoadImage(imgBytes); new_tex.Apply(); return new_tex; } //去掉背景RGB值 private void StripBackground(Texture2D tex) { Color32[] colors = tex.GetPixels32(); for (int i = 0; i < colors.Length; i++) { Color32 c = colors[i]; //人像边缘附近的alpha值介于0到1 //根据文档上的说明,前景的alpha值大于0.5 if (c.a <= 0.5f) { c.a = c.r = c.g = c.b = 0; colors[i] = c; } } tex.SetPixels32(colors); tex.Apply(); } //生成一张Alpha图 private Texture2D GenerateAlphaTexture(Texture2D tex) { Color32[] colors = tex.GetPixels32(); for (int i = 0; i < colors.Length; i++) { Color32 c = colors[i]; c.r = c.g = c.b = c.a; colors[i] = c; } Texture2D alpha_tex = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false); alpha_tex.SetPixels32(colors); alpha_tex.Apply(); return alpha_tex; } //生成裁剪后的人像图 private Texture2D ClipPersionTexture(Texture2D tex, BodySegResult result) { if (result.person_info == null || result.person_info.Length == 0) return null; var rect = result.person_info[0]; Debug.LogFormat("person_num={0}", result.person_num); Debug.LogFormat("(left={0}, top={1}, width={2}, height={3})", (int)rect.left, (int)rect.top, (int)rect.width, (int)rect.height); //默认返回的人体框top不准确,这里进行重新定位 rect.top = CalculatePersionTop(tex, result); //Texture的原点坐标在左下角 int x = (int)rect.left; int y = tex.height - (int)rect.top - (int)rect.height; y = Mathf.Clamp(y, 0, tex.height - 1); int width = (int)rect.width; int height = (int)rect.height; Color[] colors = tex.GetPixels(x, y, width, height); Texture2D new_tex = new Texture2D(width, height, TextureFormat.RGBA32, false); new_tex.SetPixels(colors); new_tex.Apply(); return new_tex; } //计算人像top private int CalculatePersionTop(Texture2D tex, BodySegResult result) { int top = 0; if (result.person_info == null || result.person_info.Length == 0) return top; var rect = result.person_info[0]; //从上到下扫描图片 int y = tex.height - (int)rect.top; for (; y > 0; y--) { for (int x = 0; x < tex.width; x++) { Color c = tex.GetPixel(x, y); //根据百度返回的人体区域Alpha通道概率分数重新定位人体区域top if (c.a >= rect.score) { top = tex.height - y; goto FOUND; } } } FOUND: return top; } //计算人像bottom private int CalculatePersionBottom(Texture2D tex, BodySegResult result) { int bottom = 0; if (result.person_info == null || result.person_info.Length == 0) return bottom; var rect = result.person_info[0]; //从下到上扫描图片 int topY = tex.height - (int)rect.top; int y = tex.height - (int)rect.top - (int)rect.height; y = Mathf.Clamp(y, 0, tex.height); for (; y < topY; y++) { for (int x = 0; x < tex.width; x++) { Color c = tex.GetPixel(x, y); if (c.a >= rect.score) { bottom = y; goto FOUND; } } } FOUND: return bottom; } //将人像上下居中 private Texture2D VeticallyMiddleTexture(Texture2D tex, BodySegResult result) { int top = CalculatePersionTop(tex, result); int bottom = CalculatePersionBottom(tex, result); int middleX = 0; int middleY = (top + bottom) / 2; //提取人像区域color int x = 0; int y = bottom; int width = tex.width; int height = tex.height - top - bottom; Color[] colors = tex.GetPixels(x, y, width, height); Debug.LogFormat("top={0}, bottom={1}, middleX={2}, middleY={3}, width={4}, height={5}", top, bottom, middleX, middleY, width, height); //将人像上下居中 Texture2D new_tex = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false); new_tex.SetPixels(middleX, middleY, width, height, colors); Color transparent = new Color(0, 0, 0, 0); SetPixelRows(new_tex, middleY + height, tex.height, transparent); SetPixelRows(new_tex, 0, middleY, transparent); new_tex.Apply(); return new_tex; } private void SetPixelRows(Texture2D tex, int startY, int endY, Color color) { for (int i = startY; i <= endY; i++) SetPixelRow(tex, i, color); } private void SetPixelRow(Texture2D tex, int y, Color color) { for (int x=0; x < tex.width; x++) { if (y < tex.height) tex.SetPixel(x, y, color); } } // 合并Alpha通道 public Texture2D CombineAlphaTexture(Texture2D rgbTex, Texture2D alphaTex) { Texture2D newTex = new Texture2D(rgbTex.width, rgbTex.height, TextureFormat.RGBA32, false); for (int y=0; y<rgbTex.height; y++) { for (int x = 0; x < rgbTex.width; x++) { Color c = rgbTex.GetPixel(x, y); Color alpha = alphaTex.GetPixel(x, y); c.a = alpha.a; newTex.SetPixel(x, y, c); } } newTex.Apply(); return newTex; } //获取 Access Token public AccessTokenResult GetAccessToken(string appKey, string secretKey) { String authHost = "https://aip.baidubce.com/oauth/2.0/token"; HttpClient client = new HttpClient(); List<KeyValuePair<String, String>> paraList = new List<KeyValuePair<string, string>>(); paraList.Add(new KeyValuePair<string, string>("grant_type", "client_credentials")); paraList.Add(new KeyValuePair<string, string>("client_id", appKey)); paraList.Add(new KeyValuePair<string, string>("client_secret", secretKey)); HttpResponseMessage response = client.PostAsync(authHost, new FormUrlEncodedContent(paraList)).Result; String result = response.Content.ReadAsStringAsync().Result; Debug.Log(result); var token = JsonUtility.FromJson<AccessTokenResult>(result); return token; } //人像分割 public void AsyncBodySeg(Texture2D tex) { if (tex == null) return; StartCoroutine(Post(BODY_SEG_URL, bodySegAccessTokenResult.access_token, "foreground", tex, //完成 (json) => { var result = JsonUtility.FromJson<BodySegResult>(json); if (!string.IsNullOrEmpty(result.error_msg)) { BodySegError?.Invoke(); return; } if (result.person_num == 0) { OnNotFoundPersionError?.Invoke(); return; } Texture2D new_tex = Base64ToTexture(result.foreground, tex.width, tex.height); Debug.LogFormat("Respose image size: width={0}, height={1}", new_tex.width, new_tex.height); Texture2D persion_tex; if (IsClipPersion) { new_tex = ClipPersionTexture(new_tex, result); persion_tex = new_tex; } else { persion_tex = ClipPersionTexture(new_tex, result); } if (IsVeticallyMiddle) { new_tex = VeticallyMiddleTexture(new_tex, result); } Texture2D alpha_tex = GenerateAlphaTexture(new_tex); BodySegCompleted?.Invoke(new_tex, alpha_tex, persion_tex); }, //失败 () => { BodySegError?.Invoke(); })); //注意:分割后的图片会将背景区的alpha设为0,同时会保留背景区的RGB值。 } //人像动漫化 public void AsyncSelfieAnime(Texture2D tex) { if (tex == null) return; StartCoroutine(Post(SELFIE_ANIME_URL, selfieAnimeAccessTokenResult.access_token, "anime", tex, //完成 (json) => { var result = JsonUtility.FromJson<SelfieAnimeResult>(json); if (!string.IsNullOrEmpty(result.error_msg)) { SelfieAnimeError?.Invoke(); return; } Texture2D new_tex = Base64ToTexture(result.image, tex.width, tex.height); SelfieAnimeCompleted?.Invoke(new_tex); }, //失败 () => { SelfieAnimeError?.Invoke(); })); //注意:返回的图片没有alpha通道 } //POST 请求 private IEnumerator Post(string url, string accessToken, string type, Texture2D tex, Action<string> completedCallback, Action errorCallback) { yield return null; byte[] bytes = tex.EncodeToPNG(); //byte[] bytes = tex.EncodeToJPG(); string base64 = Convert.ToBase64String(bytes); //创建表单 WWWForm form = new WWWForm(); form.AddField("type", type); form.AddField("image", base64); url = string.Format("{0}?access_token={1}", url, accessToken); //执行请求 UnityWebRequest request = UnityWebRequest.Post(url, form); //使用https需要设置certificateHandler request.certificateHandler = new AcceptCertificateHandler(); request.useHttpContinue = false; request.chunkedTransfer = false; request.timeout = 10; request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer(); request.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded"); request.SendWebRequest(); while (!request.isDone) { Debug.LogFormat("上传进度: {0}", request.uploadProgress); yield return new WaitForSeconds(0.1f); } if (request.isHttpError || request.isNetworkError || request.responseCode != 200) { Debug.LogErrorFormat("上传出错\n{0}", request.error); errorCallback?.Invoke(); yield break; //跳出协程 } Debug.Log("上传成功!"); string json = request.downloadHandler.text; //-------常见错误------- //{"error_code":18,"error_msg":"Open api qps request limit reached"} //原因: 请求次数已达上限 //解决方法: 控制台领取免费额度,或者充值。 //{"error_code":6,"error_msg":"No permission to access data"} //没有请求权限 //解决方法: 控制台领取免费额度,或者充值。 //--------End----------- Debug.Log(json); completedCallback?.Invoke(json); } //Access Token 返回结果 public class AccessTokenResult { public string refresh_token; public string expires_in; public string scope; public string session_key; public string access_token; public string session_secret; public string error = string.Empty; public string error_description = string.Empty; } //人像分割返回结果 public class BodySegResult { //分割结果图片,base64编码之后的二值图像,需二次处理方能查看分割效果 public string labelmap; /* 分割后人像前景的scoremap,归一到0-255,不用进行二次处理,直接解码保存图片即可。 Base64编码后的灰度图文件,图片中每个像素点的灰度值 = 置信度 * 255, 置信度为原图对应像素点位于人体轮廓内的置信度,取值范围[0, 1] */ public string scoremap; /* 分割后的人像前景抠图,透明背景,Base64编码后的png格式图片,不用进行二次处理, 直接解码保存图片即可。将置信度大于0.5的像素抠出来, 并通过image matting技术消除锯齿 */ public string foreground; //检测到的人体框数目 public int person_num; //人体框信息 public PersonRect[] person_info; [Serializable] public class PersonRect { //人体区域的高度,注意当值为0时 数据类型为int public float height; //人体区域离左边界的距离,注意当值为0时 数据类型为int public float left; //人体区域离上边界的距离,注意当值为0时 数据类型为int public float top; //人体区域的宽度,注意当值为0时 数据类型为int public float width; //人体框的概率分数,取值0-1,,注意当值为0时 数据类型为int //alpha值>=score的区域即为人像区域 public float score; } public int error_code; public string error_msg; } //人像动漫化返回 public class SelfieAnimeResult { //唯一的log id,用于问题定位 public UInt64 log_id; //处理后图片的Base64编码 public string image; public int error_code; public string error_msg; } }
标签: Unity3d
日历
最新文章
随机文章
热门文章
分类
存档
- 2024年11月(3)
- 2024年10月(5)
- 2024年9月(3)
- 2024年8月(3)
- 2024年7月(11)
- 2024年6月(3)
- 2024年5月(9)
- 2024年4月(10)
- 2024年3月(11)
- 2024年2月(24)
- 2024年1月(12)
- 2023年12月(3)
- 2023年11月(9)
- 2023年10月(7)
- 2023年9月(2)
- 2023年8月(7)
- 2023年7月(9)
- 2023年6月(6)
- 2023年5月(7)
- 2023年4月(11)
- 2023年3月(6)
- 2023年2月(11)
- 2023年1月(8)
- 2022年12月(2)
- 2022年11月(4)
- 2022年10月(10)
- 2022年9月(2)
- 2022年8月(13)
- 2022年7月(7)
- 2022年6月(11)
- 2022年5月(18)
- 2022年4月(29)
- 2022年3月(5)
- 2022年2月(6)
- 2022年1月(8)
- 2021年12月(5)
- 2021年11月(3)
- 2021年10月(4)
- 2021年9月(9)
- 2021年8月(14)
- 2021年7月(8)
- 2021年6月(5)
- 2021年5月(2)
- 2021年4月(3)
- 2021年3月(7)
- 2021年2月(2)
- 2021年1月(8)
- 2020年12月(7)
- 2020年11月(2)
- 2020年10月(6)
- 2020年9月(9)
- 2020年8月(10)
- 2020年7月(9)
- 2020年6月(18)
- 2020年5月(4)
- 2020年4月(25)
- 2020年3月(38)
- 2020年1月(21)
- 2019年12月(13)
- 2019年11月(29)
- 2019年10月(44)
- 2019年9月(17)
- 2019年8月(18)
- 2019年7月(25)
- 2019年6月(25)
- 2019年5月(17)
- 2019年4月(10)
- 2019年3月(36)
- 2019年2月(35)
- 2019年1月(28)
- 2018年12月(30)
- 2018年11月(22)
- 2018年10月(4)
- 2018年9月(7)
- 2018年8月(13)
- 2018年7月(13)
- 2018年6月(6)
- 2018年5月(5)
- 2018年4月(13)
- 2018年3月(5)
- 2018年2月(3)
- 2018年1月(8)
- 2017年12月(35)
- 2017年11月(17)
- 2017年10月(16)
- 2017年9月(17)
- 2017年8月(20)
- 2017年7月(34)
- 2017年6月(17)
- 2017年5月(15)
- 2017年4月(32)
- 2017年3月(8)
- 2017年2月(2)
- 2017年1月(5)
- 2016年12月(14)
- 2016年11月(26)
- 2016年10月(12)
- 2016年9月(25)
- 2016年8月(32)
- 2016年7月(14)
- 2016年6月(21)
- 2016年5月(17)
- 2016年4月(13)
- 2016年3月(8)
- 2016年2月(8)
- 2016年1月(18)
- 2015年12月(13)
- 2015年11月(15)
- 2015年10月(12)
- 2015年9月(18)
- 2015年8月(21)
- 2015年7月(35)
- 2015年6月(13)
- 2015年5月(9)
- 2015年4月(4)
- 2015年3月(5)
- 2015年2月(4)
- 2015年1月(13)
- 2014年12月(7)
- 2014年11月(5)
- 2014年10月(4)
- 2014年9月(8)
- 2014年8月(16)
- 2014年7月(26)
- 2014年6月(22)
- 2014年5月(28)
- 2014年4月(15)
友情链接
- Unity官网
- Unity圣典
- Unity在线手册
- Unity中文手册(圣典)
- Unity官方中文论坛
- Unity游戏蛮牛用户文档
- Unity下载存档
- Unity引擎源码下载
- Unity服务
- Unity Ads
- wiki.unity3d
- Visual Studio Code官网
- SenseAR开发文档
- MSDN
- C# 参考
- C# 编程指南
- .NET Framework类库
- .NET 文档
- .NET 开发
- WPF官方文档
- uLua
- xLua
- SharpZipLib
- Protobuf-net
- Protobuf.js
- OpenSSL
- OPEN CASCADE
- JSON
- MessagePack
- C在线工具
- 游戏蛮牛
- GreenVPN
- 聚合数据
- 热云
- 融云
- 腾讯云
- 腾讯开放平台
- 腾讯游戏服务
- 腾讯游戏开发者平台
- 腾讯课堂
- 微信开放平台
- 腾讯实时音视频
- 腾讯即时通信IM
- 微信公众平台技术文档
- 白鹭引擎官网
- 白鹭引擎开放平台
- 白鹭引擎开发文档
- FairyGUI编辑器
- PureMVC-TypeScript
- 讯飞开放平台
- 亲加通讯云
- Cygwin
- Mono开发者联盟
- Scut游戏服务器引擎
- KBEngine游戏服务器引擎
- Photon游戏服务器引擎
- 码云
- SharpSvn
- 腾讯bugly
- 4399原创平台
- 开源中国
- Firebase
- Firebase-Admob-Unity
- google-services-unity
- Firebase SDK for Unity
- Google-Firebase-SDK
- AppsFlyer SDK
- android-repository
- CQASO
- Facebook开发者平台
- gradle下载
- GradleBuildTool下载
- Android Developers
- Google中国开发者
- AndroidDevTools
- Android社区
- Android开发工具
- Google Play Games Services
- Google商店
- Google APIs for Android
- 金钱豹VPN
- TouchSense SDK
- MakeHuman
- Online RSA Key Converter
- Windows UWP应用
- Visual Studio For Unity
- Open CASCADE Technology
- 慕课网
- 阿里云服务器ECS
- 在线免费文字转语音系统
- AI Studio
- 网云穿
- 百度网盘开放平台
- 迅捷画图
- 菜鸟工具
- [CSDN] 程序员研修院
- 华为人脸识别
- 百度AR导航导览SDK
- 海康威视官网
- 海康开放平台
- 海康SDK下载
- git download
交流QQ群
-
Flash游戏设计: 86184192
Unity游戏设计: 171855449
游戏设计订阅号