Unity AR识别物体的内容语音读取+使用说明功能

因之前一直在开发项目,断断续续写了一点博客,最后统一写了一下博客记录学习内容。

可以看到我的工作一直在进行。

目录

一、识别内容语音读取

二、点击齿轮按钮弹出使用说明界面

开发步骤

[1. 创建齿轮按钮 UI](#1. 创建齿轮按钮 UI)

[2. 创建使用说明面板 UI](#2. 创建使用说明面板 UI)

[3. 编写控制脚本](#3. 编写控制脚本)

[4. Inspector 中绑定组件](#4. Inspector 中绑定组件)

[5. 使用说明示例内容](#5. 使用说明示例内容)


一、识别内容语音读取

通过手机摄像头识别一个现实世界中的物体,如显示器、鼠标等:

  1. 利用百度图像识别 API 识别出中文名称;

  2. 使用百度翻译 API 翻译成英文;

  3. 使用 Android 系统自带 TTS 播放英文读音;

  4. 在 UI 上显示识别结果,并 10 秒后自动清除。

技术 用途
Unity 2022.3 主引擎
Vuforia Engine AR识别、摄像头控制
百度 AI 平台 图像识别 + 翻译
安卓 TTS 英文读音播放
TextMeshPro 结果显示 UI
Newtonsoft.Json JSON 解析

修改之前的脚本

1.ARRecognitionController.cs

cs 复制代码
using UnityEngine;
using System.Collections;
using TMPro;
using Newtonsoft.Json.Linq;
using System.IO;

public class ARRecognitionController : MonoBehaviour
{
    public CameraCapture cameraCapture;
    public BaiduAuth auth;
    public BaiduObjectRecognition recognition;
    public BaiduTranslate translator;
    public TextMeshProUGUI resultText;
    public TTSController ttsController;



    public void StartRecognition()
    {
        StartCoroutine(auth.GetAccessToken(() =>
        {
            StartCoroutine(DelayedRecognition());
        }));
    }

    IEnumerator DelayedRecognition()
    {
        yield return new WaitForSeconds(0.3f);
        StartCoroutine(StartRecognitionFlow());
    }

    IEnumerator StartRecognitionFlow()
    {
        resultText.text = "识别中...";
        Texture2D img = cameraCapture.CaptureImage();

        if (img == null)
        {
            Debug.LogWarning("截图失败!");
            resultText.text = "无法捕获图像";
            yield break;
        }

        byte[] imageData = img.EncodeToJPG();
        string imageBase64 = System.Convert.ToBase64String(imageData);
        Debug.Log("上传图像Base64长度: " + imageBase64.Length);
        string savePath = Path.Combine(Application.persistentDataPath, "captured.jpg");
        File.WriteAllBytes(savePath, imageData);
        Debug.Log("截图已保存到: " + savePath);

        yield return recognition.RecognizeObject(img, json =>
        {
            Debug.Log("百度物体识别返回: " + json);
            var result = JObject.Parse(json);

            if (result["result"] != null && result["result"].HasValues)
            {
                string chineseName = result["result"][0]["keyword"].ToString();
                Debug.Log($"识别结果: {chineseName}");

                StartCoroutine(translator.Translate(chineseName, translationJson =>
                {
                    Debug.Log("百度翻译返回: " + translationJson);
                    var transResult = JObject.Parse(translationJson);
                    string english = transResult["trans_result"][0]["dst"].ToString();
                    Debug.Log($"翻译结果: {english}");

                    resultText.text = $"{english}\n{chineseName}";
                    ttsController.Speak(english); // 播放英文语音
                    StartCoroutine(ClearResultTextAfterDelay(10f)); //  显示 10 秒后清空
                }));
            }
            else
            {
                Debug.LogWarning("未识别出任何物体!");
                resultText.text = "未识别出物体";
                StartCoroutine(ClearResultTextAfterDelay(10f));
            }
        });
    }

    // 自动清除文本协程
    IEnumerator ClearResultTextAfterDelay(float delay)
    {
        yield return new WaitForSeconds(delay);
        resultText.text = "";
    }
}

注意:TTSController 是挂在另一个空物体上的脚本,需要通过 public TTSController ttsController; 引用并在 Inspector 拖入。

2.TTSController.cs

cs 复制代码
using UnityEngine;

public class TTSController : MonoBehaviour
{
    AndroidJavaObject ttsObject;

    void Start()
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        AndroidJavaClass unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        AndroidJavaObject context = unityPlayer.GetStatic<AndroidJavaObject>("currentActivity");

        AndroidJavaClass ttsClass = new AndroidJavaClass("android.speech.tts.TextToSpeech");
        ttsObject = new AndroidJavaObject("android.speech.tts.TextToSpeech", context, new TTSListener());
#endif
    }

    public void Speak(string message)
    {
#if UNITY_ANDROID && !UNITY_EDITOR
        if (ttsObject != null)
        {
            ttsObject.Call<int>("speak", message, 0, null, null);
        }
#endif
    }

    // 内部监听器类(可为空)
    class TTSListener : AndroidJavaProxy
    {
        public TTSListener() : base("android.speech.tts.TextToSpeech$OnInitListener") { }

        public void onInit(int status)
        {
            Debug.Log("TTS 初始化状态:" + status);
        }
    }
}

注意:Unity 编辑器中无法播放,需真机测试。

二、点击齿轮按钮弹出使用说明界面

实现:点击右上角齿轮图标,弹出一块"使用说明"界面,并且可以关闭。引导用户进行操作。

实现以下逻辑:

  • 场景右上角有一个齿轮图标(代表"设置")

  • 用户点击齿轮后,弹出一个使用说明的 UI 面板

  • 面板中包含简单的说明文字与一个关闭按钮

  • 点击关闭按钮后,面板隐藏

开发步骤

1. 创建齿轮按钮 UI

在 Canvas 下创建一个按钮(UI → Button):

  • 将其命名为 GearButton

  • 替换默认按钮图片为一个齿轮图标(建议 PNG 格式透明背景)

  • 设置位置为右上角(可以使用 Anchor Preset 设置为 Top-Right)

2. 创建使用说明面板 UI

在 Canvas 下再创建一个 Panel,命名为 InstructionsPanel

  • 设置背景颜色为半透明灰色

  • 添加一个 TextMeshPro 用于显示使用说明内容

  • 添加一个关闭按钮 CloseButton,可以是 "X" 图标(找一个图标即可)

注意:在 Hierarchy 中选中 InstructionsPanel取消勾选勾选框 ,让它在启动时默认隐藏(等同于 SetActive(false))。

3. 编写控制脚本

新建脚本 GearSettingsUI.cs,实现点击按钮的显示/隐藏逻辑:

cs 复制代码
using UnityEngine;
using UnityEngine.UI;

public class GearSettingsUI : MonoBehaviour
{
    public GameObject instructionsPanel;
    public Button gearButton;
    public Button closeButton;

    void Start()
    {
        instructionsPanel.SetActive(false); // 初始隐藏
        gearButton.onClick.AddListener(ShowInstructions);
        closeButton.onClick.AddListener(HideInstructions);
    }

    void ShowInstructions()
    {
        instructionsPanel.SetActive(true);
    }

    void HideInstructions()
    {
        instructionsPanel.SetActive(false);
    }
}

4. Inspector 中绑定组件

把对应的 UI 拖入:

  • gearButton → 齿轮按钮

  • instructionsPanel → 说明面板

  • closeButton → 面板里的关闭按钮

5. 使用说明示例内容

BodyText中写入我的内容:

  • 拖动模型旋转视角

  • 捏合手势放大缩小

  • 点击物体查看详情

  • 点击"返回"退出体验