OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4767|回复: 1

《I.MX6U嵌入式Qt开发指南 V1.0》第二十五章 语音识别项目

[复制链接]

1118

主题

1129

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4672
金钱
4672
注册时间
2019-5-8
在线时间
1224 小时
发表于 2021-7-21 10:48:54 | 显示全部楼层 |阅读模式
1)实验平台:正点原子阿尔法Linux开发板
2)  章节摘自【正点原子】《I.MX6U嵌入式Qt开发指南 V1.0》
3)购买链接:https://detail.tmall.com/item.htm?id=609033604451
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/arm-linux/zdyz-i.mx6ull.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子阿尔法Linux交流群:1027879335 QQ群.png

原子哥.jpg

微信公众号.png



第二十五章 语音识别项目


我们知道AI智能音箱已经在我们生活中不少见,也许我们都玩过,智能化非常高,功能强大,与我们平常玩的那种蓝牙音箱,Wifi音箱有很大的区别,AI智能在哪里呢?语音识别技术和云端技术,主要由主控芯片,麦克风阵列,功率放大,codec,触控电路,LED阵列组成。
AI音箱对传统音箱主要有两大块的技术区别,一块是语音信号的前处理,包括回声消除、波速成型、音源定位、降噪、去混响、自动语音电平控制这块是偏硬件的控制。还有一块是智能语音交互,包括语音关键词搜索、本地语音识别、声纹识别、语音合成。
AI智能音箱的芯片方案商:联发科,全志科技,瑞芯微等等,语音识别都有现成的方案商。他们的麦克风阵列方案,有2麦,4麦,6麦,7 + 1麦等等。
写上面这些是让读者了解一下专业AI音箱方案与我们在正点原子Linux开发板想实现语音识别的差别在哪里。我们在正点原子Linux开发板上实现语音识别项目(功能),就不能与专业的AI音箱对比了。硬件资源有限,开发板只有一个麦头(咪头座),没有那些硬件控制消除回声,降噪等等。不过编者在上面调用百度语音API识别语音,识别率还是挺高的。
下面就与大家一起在正点原子Linux IMX6U开发板上实现语音识别功能吧!注意:正点原子MINI I.MX6U开发板没有音频芯片,不支持此实验,只有正点原子I.MX6U ALPHA开发板支持。
本章简介如下:
介绍百度语音技术账号申请,及简单介绍调用流程。
用Qt编写示例程序。流程如下,录制音频后,发送调用百度语音识别API接口,识别并返回结果。支持语音控制正点原子I.MX6U开发板上的LED控制,其他设备可以自行拓展。



25.1 语音识别产品申请帐号
语音识别技术产品,有讯飞,百度等厂家,我们可以购买或者免费试用他们的产品。可以直接到他们的官网上查看,有使用技术文档。下面我们以百度语音识别技术产品为例子。可以在浏览器输入搜索“百度语音识别”,就可以找到百度AI开放平台。
第二十五章 语音识别项目849.png
        点击进去就可以看到他的技术文档链接位置。如下图。
第二十五章 语音识别项目877.png
        或者直接打开https://ai.baidu.com/ai-doc/SPEECH/Ek39uxgre就可以跳转到百度AI开放平台》帮助文档》语音技术页面。如下图。
第二十五章 语音识别项目1023.png
        请仔细阅读百度语音技术的文档,里面写的非常详细,还有例子下载参考。
        编者阅读总结,想要使用百度语音识别接口,需要根据上面图中的新手指南注册百度帐号,领取免费额度及创建中文普通话应用(创建前先领取免费额度(180天免费额度,可调用约5万次左右,详细请看免费额度说明))。记住自己的密钥。请自行完成及创建百度帐号,按照百度帮助文档里的步骤,领取免费额度及创建中文普通话应用,获取密钥!程序里需要用到自己的密钥。编者提供的密钥是百度语音识别例程里的,如果开发次数超了可能就不能使用了。程序中只需要API Key与Secret Key。注意获取Access Token时有效期为30天,到期后需要在程序里重新获取新的token。
第二十五章 语音识别项目1338.png
        更多参考请查看百度AI接入指南。
        注意,帮助文档里提及SDK包,有LinuxC++SDK包支持,但是目前仅支持 X64(x86-64) CPU架构的 Linux 操作系统。LinuxSDK 仅支持在线语音识别,固定长语音模式。简单的说就是还不支持ARM架构的SDK包。
25.2 百度语音识别流程及示例简介
在百度AI帮助文档里可以看见如下重要信息。
第二十五章 语音识别项目1582.png
        请认真阅读调用流程,了解操作过程,对下面理解编者编写Qt调用百度语音API的例子会有一定的帮助。
        总结:调用流程需要仔细阅读,百度提供了示例Demo代码,可以看到里面支持很多种编程语言编写的API请求相关示例demo代码。没有直接C++相关的代码。C语言是C++语言的子集,我们可以直接参考C语言编写的例子(请自行查阅及参考百度提供的C语言编写的API请求相关示例demo代码)来编写Qt调用语音识别API。(备注:其他语言编写的例子不在我们教程范围。)识别的音频格式支持如上,我们可以知道一些重要的信息是支持采样率16000、8000的固定值,16bit深的单声道,音频长度最长60秒。格式支持wav,恰好正点原子Linux I.MX6U开发板系统支持wav格式播放及录制(详细请看【正点原子】I.MX6U用户快速体验V1.x.pdf测试音频部分)。
        备注:由于百度语音识别的API例子放在github(开源网站),国外网站的原因,可能打开失败,请多次尝试,如果一直无法访问,那么我们直接往下看使用编者编写Qt的示例吧。不能访问的话,编者也没办法的。
25.3 百度短语音识别API接口
源码路径为4/02_asr_demo/asr/asr.h,内容如下。asr是语音识别功能demo,(asr译作自动语音识别技术即automatic speech recognition)
   
  1. /******************************************************************
  2.     Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
  3.     * @projectName   asr
  4.     * @brief         asr.h
  5.     * [url=home.php?mod=space&uid=90321]@Author[/url]        Deng Zhimao
  6.     * [url=home.php?mod=space&uid=55957]@EMAIL[/url]         <a href="mailto:1252699831@qq.com">1252699831@qq.com</a>
  7.     * [url=home.php?mod=space&uid=28414]@net[/url]            <a href="www.openedv.com" target="_blank">www.openedv.com</a>
  8.     * @date           2021-06-03
  9.     *******************************************************************/
  10. 1   #ifndef ASR_H
  11. 2   #define ASR_H
  12. 3
  13. 4   #include <QWidget>
  14. 5
  15. 6   #include <QNetworkAccessManager>
  16. 7   #include <QNetworkReply>
  17. 8
  18. 9   #include <QJsonDocument>
  19. 10  #include <QJsonParseError>
  20. 11  #include <QJsonObject>
  21. 12  #include <QJsonArray>
  22. 13  #include <QHostInfo>
  23. 14
  24. 15  #include <QFile>
  25. 16
  26. 17  class Asr : public QWidget
  27. 18  {
  28. 19      Q_OBJECT
  29. 20
  30. 21  public:
  31. 22      Asr(QWidget *parent = nullptr);
  32. 23      ~Asr();
  33. 24
  34. 25      /* 请求网络 */
  35. 26      void requestNetwork(QString, QByteArray);
  36. 27
  37. 28      /* 获取识别结果 */
  38. 29      void getTheResult(QString fileName);
  39. 30
  40. 31  private:
  41. 32      /* 存储获取tokenUrl地址 */
  42. 33      QString tokenUrl;
  43. 34
  44. 35      /* 存储serverapi地址 */
  45. 36      QString serverApiUrl;
  46. 37
  47. 38      /* 最终需要访问token的地址 */
  48. 39      QString accessToken;
  49. 40
  50. 41      /* 获取token的接口*/
  51. 42      const QString token_org = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%1&client_secret=%2&";
  52. 43
  53. 44      /* 填写网页上申请的appkey 如 g_api_key="g8eBUMSokVB1BHGmgxxxxxx" */
  54. 45      const QString api_key = "kVcnfD9iW2XVZSMaLMrtLYIz";
  55. 46
  56. 47      /* 填写网页上申请的APP SECRET 如 $secretKey="94dc99566550d87f8fa8ece112xxxxx" */
  57. 48      const QString secret_key = "O9o1O213UgG5LFn0bDGNtoRN3VWl2du6";
  58. 49
  59. 50      /* 百度服务器API接口,发送语音可返回识别结果 */
  60. 51      const QString server_api = "http://vop.baidu.com/server_api?dev_pid=1537&cuid=%1&token=%2";
  61. 52
  62. 53      /* 网络管理 */
  63. 54      QNetworkAccessManager *networkAccessManager;
  64. 55
  65. 56      QString getJsonValue(QByteArray ba, QString key);
  66. 57
  67. 58      QFile file;
  68. 59
  69. 60  private slots:
  70. 61
  71. 62      /* 准备读取响应返回来的数据 */
  72. 63      void readyReadData();
  73. 64
  74. 65      /* 响应完成处理 */
  75. 66      void replyFinished();
  76. 67
  77. 68  signals:
  78. 69      void asrReadyData(QString);
  79. 70
  80. 71  };
  81. 72  #endif // ASR_H
复制代码

        第45行,请填写读者自己在网页上申请的API Key。以防万一示例中的API Key过期不可用!
        第47行,请填写读者在网页上申请的Secret Key。以防万一示例中的Secret Key过期不可用!
        其他地址由来是见百度给出的Demo示例,及百度的帮助文档。这里就不详细说了。原理与上一章原子云API接口相似。不过百度语音识别需要通过自己的帐号,指定地址获取访问的Token源地址,然后将得到的Access Token地址与语音识别服务器地址拼接,发送语音到服务器,就可以返回识别的结果了。详细请参考源码4/02_asr_demo/asr/asr.cpp。
25.4 录制wav音频
在12.5小节,已经介绍过开发板如何录制音频文件了,详细请看12.5小节,就不详细介绍了,注意需要修改的地方如下。因为百度语音识别支持采样率16000、8000的固定值,16bit深的单声道,音频长度最长60秒。格式支持wav,pcm等格式。我们需要修改录制音频格式为wav格式,通道为单声道,采样率为16000,源码如下,已用红色字体标出。录制的音频文件保存为本地16k.wav文件。
源码路径为4/02_asr_demo/audiorecorder/audiorecorder.cpp。
   
  1. /******************************************************************
  2.     Copyright &#169; Deng Zhimao Co., Ltd. 1990-2021. All rights reserved.
  3.     * @projectName   audiorecorder
  4.     * @brief         audiorecorder.cpp
  5.     * @author        Deng Zhimao
  6.     * @email         <a href="mailto:1252699831@qq.com">1252699831@qq.com</a>
  7.     * @net            <a href="www.openedv.com" target="_blank">www.openedv.com</a>
  8.     * @date           2021-06-04
  9.     *******************************************************************/
  10. 1   #include "audiorecorder.h"
  11. 2   #include <QDebug>
  12. 3   #include <QUrl>
  13. 4   #include <QDateTime>
  14. 5   #include <QDir>
  15. 6   #include <QCoreApplication>
  16. 7  
  17. 8   static qreal getPeakValue(const QAudioFormat &format);
  18. 9   static QVector<qreal> getBufferLevels(const QAudioBuffer &buffer);
  19. 10
  20. 11  template <class T>
  21. 12  static QVector<qreal> getBufferLevels(const T *buffer, int frames, int channels);
  22. 13
  23. 14  AudioRecorder::AudioRecorder(QWidget *parent)
  24. 15  {
  25. 16      Q_UNUSED(parent);
  26. 17
  27. 18      /* 录制音频的类 */
  28. 19      m_audioRecorder = new QAudioRecorder(this);
  29. 20
  30. 21      /* 用于探测缓冲区的数据 */
  31. 22      m_probe = new QAudioProbe(this);
  32. 23
  33. 24      /* 信号槽连接,更新录音level显示 */
  34. 25      connect(m_probe, &QAudioProbe::audioBufferProbed,
  35. 26              this, &AudioRecorder::processBuffer);
  36. 27
  37. 28      /* 设置探测的对象 */
  38. 29      m_probe->setSource(m_audioRecorder);
  39. 30
  40. 31      /* 扫描本地声卡设备 */
  41. 32      devicesVar.append(QVariant(QString()));
  42. 33      for (auto &device: m_audioRecorder->audioInputs()) {
  43. 34          devicesVar.append(QVariant(device));
  44. 35          //qDebug()<<"本地声卡设备:"<<device<<endl;
  45. 36      }
  46. 37
  47. 38      /* 音频编码 */
  48. 39      codecsVar.append(QVariant(QString()));
  49. 40      for (auto &codecName: m_audioRecorder->supportedAudioCodecs()) {
  50. 41          codecsVar.append(QVariant(codecName));
  51. 42          //qDebug()<<"音频编码:"<<codecName<<endl;
  52. 43      }
  53. 44
  54. 45      /* 容器/支持的格式 */
  55. 46      containersVar.append(QVariant(QString()));
  56. 47      for (auto &containerName: m_audioRecorder->supportedContainers()) {
  57. 48          containersVar.append(QVariant(containerName));
  58. 49          //qDebug()<<"支持的格式:"<<containerName<<endl;
  59. 50      }
  60. 51
  61. 52      /* 采样率 */
  62. 53      sampleRateVar.append(QVariant(0));
  63. 54      /* 百度语音识别只支持8000、 16000采样率 */
  64. 55      sampleRateVar.append(QVariant(8000));
  65. 56      sampleRateVar.append(QVariant(16000));
  66. 57      for (int sampleRate: m_audioRecorder->supportedAudioSampleRates()) {
  67. 58          sampleRateVar.append(QVariant(sampleRate));
  68. 59          //qDebug()<<"采样率:"<<sampleRate<<endl;
  69. 60      }
  70. 61
  71. 62
  72. 63      /* 通道 */
  73. 64      channelsVar.append(QVariant(-1));
  74. 65      channelsVar.append(QVariant(1));
  75. 66      channelsVar.append(QVariant(2));
  76. 67      channelsVar.append(QVariant(4));
  77. 68
  78. 69      /* 质量 */
  79. 70      qualityVar.append(QVariant(int(QMultimedia::LowQuality)));
  80. 71      qualityVar.append(QVariant(int(QMultimedia::NormalQuality)));
  81. 72      qualityVar.append(QVariant(int(QMultimedia::HighQuality)));
  82. 73
  83. 74      /* 比特率 */
  84. 75      bitratesVar.append(QVariant(0));
  85. 76      bitratesVar.append(QVariant(32000));
  86. 77      bitratesVar.append(QVariant(64000));
  87. 78      bitratesVar.append(QVariant(96000));
  88. 79      bitratesVar.append(QVariant(128000));
  89. 80
  90. 81      /* 录音类信号槽连接 */
  91. 82      connect(m_audioRecorder, &QAudioRecorder::durationChanged,
  92. 83              this, &AudioRecorder::updateProgress);
  93. 84  }
  94. 85
  95. 86  AudioRecorder::~AudioRecorder()
  96. 87  {
  97. 88  }
  98. 89
  99. 90
  100. 91  void AudioRecorder::startRecorder()
  101. 92  {
  102. 93      /* 备注:录音需要设置成16000 采样率和通道数为1,
  103. 94       * 保存为wav文件需要设置成audio/x-wav(container文件格式) */
  104. 95
  105. 96      /* 如果录音已经停止,则开始录音 */
  106. 97      if (m_audioRecorder->state() == QMediaRecorder::StoppedState) {
  107. 98          /* 设置默认的录音设备 */
  108. 99          m_audioRecorder->setAudioInput(devicesVar.at(0).toString());
  109. 100
  110. 101         /* 下面的是录音设置 */
  111. 102         QAudioEncoderSettings settings;
  112. 103         settings.setCodec(codecsVar.at(0).toString());
  113. 104         settings.setSampleRate(sampleRateVar[2].toInt());
  114. 105         settings.setBitRate(bitratesVar[0].toInt());
  115. 106         settings.setChannelCount(channelsVar[1].toInt());
  116. 107         settings.setQuality(QMultimedia::EncodingQuality(
  117. 108                                 qualityVar[0].toInt()));
  118. 109
  119. 110         /* 以恒定的质量录制,可选恒定的比特率 */
  120. 111         settings.setEncodingMode(QMultimedia::ConstantQualityEncoding);
  121. 112
  122. 113         /* I.MX6ULL第20个支持的格式为 audio/x-wav */
  123. 114         QString container = containersVar.at(20).toString();
  124. 115
  125. 116         /* 使用配置 */
  126. 117         m_audioRecorder->setEncodingSettings(settings,
  127. 118                                              QVideoEncoderSettings(),
  128. 119                                              container);
  129. 120         /* 录音保存为16k.wav文件 */
  130. 121         m_audioRecorder->setOutputLocation(QUrl::fromLocalFile(tr("./16k.wav")));
  131. 122
  132. 123         /* 开始录音 */
  133. 124         m_audioRecorder->record();
  134. 125     }
  135. 126 }
  136. 127
  137. 128 void AudioRecorder::stopRecorder()
  138. 129 {
  139. 130     /* 停止录音 */
  140. 131     m_audioRecorder->stop();
  141. 132 }
  142. 133
  143. 134
  144. 135 void AudioRecorder::updateProgress(qint64 duration)
  145. 136 {
  146. 137     Q_UNUSED(duration);
  147. 138
  148. 139     if (m_audioRecorder->error()
  149. 140             != QMediaRecorder::NoError)
  150. 141         return;
  151. 142
  152. 143     /* 打印录制时长 */
  153. 144     //qDebug()<<duration / 1000<<endl;
  154. 145 }
  155. 146
  156. 147
  157. 148 void AudioRecorder::clearAudioLevels()
  158. 149 {
  159. 150     //...
  160. 151 }
  161. 152
  162. 153 // This function returns the maximum possible sample value for a given audio format
  163. 154 qreal getPeakValue(const QAudioFormat& format)
  164. 155 {
  165. 156     // Note: Only the most common sample formats are supported
  166. 157     if (!format.isValid())
  167. 158         return qreal(0);
  168. 159
  169. 160     if (format.codec() != "audio/pcm")
  170. 161         return qreal(0);
  171. 162
  172. 163     switch (format.sampleType()) {
  173. 164     case QAudioFormat::Unknown:
  174. 165         break;
  175. 166     case QAudioFormat::Float:
  176. 167         if (format.sampleSize() != 32) // other sample formats are not supported
  177. 168             return qreal(0);
  178. 169         return qreal(1.00003);
  179. 170     case QAudioFormat::SignedInt:
  180. 171         if (format.sampleSize() == 32)
  181. 172             return qreal(INT_MAX);
  182. 173         if (format.sampleSize() == 16)
  183. 174             return qreal(SHRT_MAX);
  184. 175         if (format.sampleSize() == 8)
  185. 176             return qreal(CHAR_MAX);
  186. 177         break;
  187. 178     case QAudioFormat::UnSignedInt:
  188. 179         if (format.sampleSize() == 32)
  189. 180             return qreal(UINT_MAX);
  190. 181         if (format.sampleSize() == 16)
  191. 182             return qreal(USHRT_MAX);
  192. 183         if (format.sampleSize() == 8)
  193. 184             return qreal(UCHAR_MAX);
  194. 185         break;
  195. 186     }
  196. 187
  197. 188     return qreal(0);
  198. 189 }
  199. 190
  200. 191 // returns the audio level for each channel
  201. 192 QVector<qreal> getBufferLevels(const QAudioBuffer& buffer)
  202. 193 {
  203. 194     QVector<qreal> values;
  204. 195
  205. 196     if (!buffer.format().isValid() || buffer.format().byteOrder() != QAudioFormat::LittleEndian)
  206. 197         return values;
  207. 198
  208. 199     if (buffer.format().codec() != "audio/pcm")
  209. 200         return values;
  210. 201
  211. 202     int channelCount = buffer.format().channelCount();
  212. 203     values.fill(0, channelCount);
  213. 204     qreal peak_value = getPeakValue(buffer.format());
  214. 205     if (qFuzzyCompare(peak_value, qreal(0)))
  215. 206         return values;
  216. 207
  217. 208     switch (buffer.format().sampleType()) {
  218. 209     case QAudioFormat::Unknown:
  219. 210     case QAudioFormat::UnSignedInt:
  220. 211         if (buffer.format().sampleSize() == 32)
  221. 212             values = getBufferLevels(buffer.constData<quint32>(), buffer.frameCount(), channelCount);
  222. 213         if (buffer.format().sampleSize() == 16)
  223. 214             values = getBufferLevels(buffer.constData<quint16>(), buffer.frameCount(), channelCount);
  224. 215         if (buffer.format().sampleSize() == 8)
  225. 216             values = getBufferLevels(buffer.constData<quint8>(), buffer.frameCount(), channelCount);
  226. 217         for (int i = 0; i < values.size(); ++i)
  227. 218             values<i> = qAbs(values.at(i) - peak_value / 2) / (peak_value / 2);
  228. 219         break;
  229. 220     case QAudioFormat::Float:
  230. 221         if (buffer.format().sampleSize() == 32) {
  231. 222             values = getBufferLevels(buffer.constData<float>(), buffer.frameCount(), channelCount);
  232. 223             for (int i = 0; i < values.size(); ++i)
  233. 224                 values<i> /= peak_value;
  234. 225         }
  235. 226         break;
  236. 227     case QAudioFormat::SignedInt:
  237. 228         if (buffer.format().sampleSize() == 32)
  238. 229             values = getBufferLevels(buffer.constData<qint32>(), buffer.frameCount(), channelCount);
  239. 230         if (buffer.format().sampleSize() == 16)
  240. 231             values = getBufferLevels(buffer.constData<qint16>(), buffer.frameCount(), channelCount);
  241. 232         if (buffer.format().sampleSize() == 8)
  242. 233             values = getBufferLevels(buffer.constData<qint8>(), buffer.frameCount(), channelCount);
  243. 234         for (int i = 0; i < values.size(); ++i)
  244. 235             values<i> /= peak_value;
  245. 236         break;
  246. 237     }
  247. 238
  248. 239     return values;
  249. 240 }
  250. 241
  251. 242 template <class T>
  252. 243 QVector<qreal> getBufferLevels(const T *buffer, int frames, int channels)
  253. 244 {
  254. 245     QVector<qreal> max_values;
  255. 246     max_values.fill(0, channels);
  256. 247
  257. 248     for (int i = 0; i < frames; ++i) {
  258. 249         for (int j = 0; j < channels; ++j) {
  259. 250             qreal value = qAbs(qreal(buffer[i * channels + j]));
  260. 251             if (value > max_values.at(j))
  261. 252                 max_values.replace(j, value);
  262. 253         }
  263. 254     }
  264. 255
  265. 256     return max_values;
  266. 257 }
  267. 258
  268. 259 void AudioRecorder::processBuffer(const QAudioBuffer& buffer)
  269. 260 {
  270. 261     /* 根据通道数目需要显示count个level */
  271. 262     int count = buffer.format().channelCount();
  272. 263     /* 打印通道数 */
  273. 264     Q_UNUSED(count);
  274. 265     // qDebug()<<"通道数"<<count<<endl;
  275. 266
  276. 267     /* 设置level的值 */
  277. 268     QVector<qreal> levels = getBufferLevels(buffer);
  278. 269     for (int i = 0; i < levels.count(); ++i) {
  279. 270         /* 打印音量等级 */
  280. 271         // qDebug()<<"音量等级"<<levels.at(i)<<endl;
  281. 272     }
  282. 273 }</i></i></i>
复制代码

        4/02_asr_demo/audiorecorder/audiorecorder.cpp主要提供了一个startRecorder()和stopRecorder()的接口,录音保存的文件为可执行程序当前路径下的16k.wav文件。startRecorder()和stopRecorder()分别是开始录音和停止录音。
        第54~56行,增加8000和16000的支持项。
        第104行,设置为下标为2的项,也就是16000采样率。
        第106行,设置通道数下标为1的项,也就是单通道。
        第114行,设置文件容器/格式,为audio/x-wav格式(项的下标为20)。设置此格式会保存wav后缀的文件。
25.5 语音界面UI开发
项目路径为4/02_asr_demo/02_asr_demo/02_asr_demo.pro,先看项目界面。项目界面如下,界面简洁大气,界面中间用了一个立体的素材,点击后可以旋转,给人一种智能化的感觉,点击时还会有音效提示,文本提示“请点击,开始说话…”,点击后,提示“正在听您说话,请继续…”,录制8s左右的音频,等待返回识别结果即可。编写设计完成的效果不错!请自行查阅源码,掌握了本教程前面第七章的内容,就可以理解这个界面是如何设计的。
第二十五章 语音识别项目15390.png
25.6 语音识别项目综合测试
打开4/02_asr_demo/02_asr_demo/02_asr_demo.pro项目,此项目为语音识别UI界面。
打开项目如下图。
第二十五章 语音识别项目15477.png
        项目文件夹下内容解释:
        02_asr_demo项目下:
asr文件夹为语音识别的应用程序,主要用来与将录制的音频发送到百度云语音识别服务器上,然后返回识别结果。
aduiorecorder文件夹为录制wav音频的文件夹。主要是用来录制wav音频。
led文件夹为I.MX6U开发板控制LED的接口程序。
Headers文件夹为界面设计的头文件。
Sources文件夹为界面设计的源文件。
25.6.1 Ubuntu上运行
Ubuntu运行后界面如下,注意,Ubuntu需要联网!Ubuntu上理论上是能录制音频识别返回结果的,但是教程主要写正点原子I.MX6U开发板上的语音识别项目。限于编者手上没有可用电脑麦克风,估计读者也没有,电脑配置麦克风输入后可以自行测试。运行之后可以看到下面的界面。Windows不作讲解!请到下面小节使用正点原子I.MX6U ALPHA开发板运行体验识别效果!
第二十五章 语音识别项目15877.png
25.6.2 ALPHA开发板上运行
本例适用于正点原子I.MX6U ALPHA开发板!请使用正点原子I.MX6U的出厂系统进行测试!
请使用正点原子的I.MX6U的出厂时的系统测试!
请使用正点原子的I.MX6U的出厂时的系统测试!
请使用正点原子的I.MX6U的出厂时的系统测试!
重要的事情是说三遍!

开始录音前,需要根据正点原子I.MX6U用户快速体验手册,第3.15小节进行测试板子的录音功能。确保能正常录音,再交叉编译此Qt应用程序到开发板上运行。如何交叉编译Qt应用程序到开发板,请看【正点原子】I.MX6U 出厂系统Qt交叉编译环境搭建V1.x版本。
在正点原子I.MX6U开发板上运行此录音程序,需要先配置是麦克风(板子上的麦头)。
麦头录音,则在板子上运行开启麦头录音的脚本。
/home/root/shell/audio/mic_in_config.sh
        交叉编译到开发板上运行效果如下。下面的图都是开发板上的截图。
        程序初始化时。(注意开发板先插上网线联网!确保能上网!)
第二十五章 语音识别项目16464.png
        点击中间的图标后,注意,请在点击1.5~2s后再说话,点击时有音效提醒,避免把音效录进去。整个录音过程是8s左右。
第二十五章 语音识别项目16525.png
        识别返回结果的过程很快,识别率也挺高,如下图,编者说了一句“正点原子”,语音识别返回“正点原子”的结果。注意,识别是中文标准普通话。请尽量说一些日常话语,避免说生僻语句,特殊的方言等。识别常见问题请查看百度AI开发平台的帮助文档。
第二十五章 语音识别项目16707.png
        再点击,再次进行语音识别,话语中,包含“开灯”,那么即可点亮板子上的LED。点亮后,再次进行语音识别,话语中包含“关灯”,即可熄灭板子上的LED。
        “开灯”识别结果。
第二十五章 语音识别项目16795.png
        “关灯”识别结果。
第二十五章 语音识别项目16808.png
        本示例仅供学习参考使用,如需要用到开发上,请购买百度或其他开放平台的语音识别产品。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

0

主题

201

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2552
金钱
2552
注册时间
2019-12-5
在线时间
352 小时
发表于 2021-7-21 17:30:26 | 显示全部楼层
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-25 18:49

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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