一、前言
我目前實現了拍照保存到手機的功能
我想進一步優化,實現通過手機攝像頭實時識別眼前的物體,顯示對應的英文的功能。
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 秒防止攝像頭卡幀。