一、前言
我目前实现了拍照保存到手机的功能
我想进一步优化,实现通过手机摄像头实时识别眼前的物体,显示对应的英文的功能。
1.项目技术栈:Unity 2022.3.53+ Vuforia 11+ 百度物体识别API + 百度翻译API
2.功能目标:使用手机摄像头识别现实中的物体,返回物体识别结果和物体英文翻译,UI 实时展示翻译结果。
二、实现思路
用户点击按钮 → 截图当前画面 → 上传到百度物体识别API → 获取中文物体名称 →
调用百度翻译API → 得到英文单词 → 在 UI 显示英文 + 中文。
三、实现代码
脚本名 | 功能说明 | 应该挂在哪个物体上 |
---|---|---|
CameraCapture.cs | 采集 AR 摄像头画面截图 | ARCamera(Vuforia 默认相机) |
BaiduAuth.cs | 获取百度 Access Token | 新建空物体 BaiduManager |
BaiduObjectRecognition.cs | 调用百度物体识别 API | 和 BaiduAuth.cs 放同一个物体即可 |
BaiduTranslate.cs | 调用百度翻译 API | 也放在同一个 BaiduManager 上 |
ARRecognitionController.cs | 管理完整识别逻辑和 UI 更新 | 新建空物体挂载 RecognitionController |
1.CameraCapture.cs
using UnityEngine;public class CameraCapture : MonoBehaviour
{public Camera arCamera;public Texture2D CaptureImage(){int captureWidth = 1280;int captureHeight = 720;RenderTexture rt = new RenderTexture(captureWidth, captureHeight, 24);arCamera.targetTexture = rt;arCamera.Render();RenderTexture.active = rt;Texture2D screenShot = new Texture2D(captureWidth, captureHeight, TextureFormat.RGB24, false);screenShot.ReadPixels(new Rect(0, 0, captureWidth, captureHeight), 0, 0);screenShot.Apply();arCamera.targetTexture = null;RenderTexture.active = null;Destroy(rt);return screenShot;}
}
2.BaiduAuth.cs
public class BaiduAuth : MonoBehaviour
{public string clientId = "你的API Key";public string clientSecret = "你的Secret Key";public string accessToken;public IEnumerator GetAccessToken(System.Action onSuccess){string url = $"https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={clientId}&client_secret={clientSecret}";UnityWebRequest www = UnityWebRequest.Get(url);yield return www.SendWebRequest();if (!www.result.Equals(UnityWebRequest.Result.ConnectionError)){var response = JsonUtility.FromJson<TokenResponse>(www.downloadHandler.text);accessToken = response.access_token;onSuccess?.Invoke();}else{Debug.LogError(www.error);}}[System.Serializable]public class TokenResponse { public string access_token; }
}
3.BaiduObjectRecognition.cs
public class BaiduObjectRecognition : MonoBehaviour
{public string accessToken;public IEnumerator RecognizeObject(Texture2D image, System.Action<string> callback){byte[] imageData = image.EncodeToJPG();string imageBase64 = System.Convert.ToBase64String(imageData);string url = $"https://aip.baidubce.com/rest/2.0/image-classify/v2/advanced_general?access_token={accessToken}";WWWForm form = new WWWForm();form.AddField("image", imageBase64);UnityWebRequest www = UnityWebRequest.Post(url, form);www.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");yield return www.SendWebRequest();if (!www.result.Equals(UnityWebRequest.Result.ConnectionError)){callback?.Invoke(www.downloadHandler.text);}else{Debug.LogError(www.error);}}
}
4.BaiduTranslate.cs
public class BaiduTranslate : MonoBehaviour
{public string appId = "你的翻译AppId";public string secretKey = "你的翻译密钥";public IEnumerator Translate(string query, System.Action<string> callback){string salt = Random.Range(10000, 99999).ToString();string sign = GetMD5(appId + query + salt + secretKey);string url = $"https://fanyi-api.baidu.com/api/trans/vip/translate?q={UnityWebRequest.EscapeURL(query)}&from=zh&to=en&appid={appId}&salt={salt}&sign={sign}";UnityWebRequest www = UnityWebRequest.Get(url);yield return www.SendWebRequest();if (!www.result.Equals(UnityWebRequest.Result.ConnectionError)){callback?.Invoke(www.downloadHandler.text);}else{Debug.LogError(www.error);}}string GetMD5(string str){using var md5 = System.Security.Cryptography.MD5.Create();byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(str);byte[] hashBytes = md5.ComputeHash(inputBytes);return System.BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();}
}
5.ARRecognitionController.cs
public class ARRecognitionController : MonoBehaviour
{public CameraCapture cameraCapture;public BaiduAuth auth;public BaiduObjectRecognition recognition;public BaiduTranslate translator;public TextMeshProUGUI resultText;public void StartRecognition(){StartCoroutine(auth.GetAccessToken(() =>{StartCoroutine(StartRecognitionFlow());}));}IEnumerator StartRecognitionFlow(){yield return new WaitForSeconds(0.3f);Texture2D img = cameraCapture.CaptureImage();if (img == null){resultText.text = "无法获取图像";yield break;}yield return recognition.RecognizeObject(img, json =>{var result = JObject.Parse(json);string chineseName = result["result"]?[0]?["keyword"]?.ToString();if (!string.IsNullOrEmpty(chineseName)){StartCoroutine(translator.Translate(chineseName, transJson =>{var transResult = JObject.Parse(transJson);string english = transResult["trans_result"]?[0]?["dst"]?.ToString();resultText.text = $"{english}\n({chineseName})";}));}else{resultText.text = "未识别出物体";}});}
}
四、unity中具体实现
1.最终ARRecognitionController上的内容参考如下:
2.UI设计(最基本的就是一个按钮,一个text)
(1)TextMeshProUGUI
a.在 Canvas 里创建一个 TextMeshPro - Text
组件
命名为 ResultText
。设置一个大点的字体、颜色醒目一些。
b.在 Canvas 创建一个 Button
命名为识别按钮
按钮点击事件绑定 RecognitionController.StartRecognition()
方法。
五、最终实现效果
操作 | 系统行为 |
---|---|
用户点击“识别”按钮 | 调用百度授权,获取 access token(如果已有可跳过) |
系统截图 AR 相机当前画面 | 使用 RenderTexture 稳定截图 |
后端自动处理,上传截图至百度物体识别 API | 返回识别出的中文关键词 |
中文词汇传给翻译 API | 得到对应英文单词 |
显示 UI 结果 | “Monitor screen 显示器屏幕” 这样显示在界面上 |
六、探索过程的一些问题
整个流程的串通其实实现的比较顺利。
一直卡在拍照的图片效果不好,百度识别不出来或者不准确上。
一个就是要处理好ar camera的摄像头像素帧,之前博客提到的gallery screenshot我没有用,直接新写了脚本。
第二个报错是百度返回 access token 无效,需要每次识别前先动态获取 access token。
第三个是照片图像老是重复,每次点击时重新采图,延时 0.3 秒防止摄像头卡帧。