(转载请注明出处)

使用SDK: Kinect for Windows SDK v2.0 public preview

这次探讨语音识别。之前都是一节写两部分,这次反过来了,分为上下两部分。

语音识别算是使用官方SDK的一个理由吧,不然都用OpenNI了,毕竟微软在SR(语音识别)上的成果还是不错的。

首先,您需要下载语音识别的SDK、运行时库以及您想支持的运行时语言,运行时语言里面SR代表语音识别,

TTS代表文本转语音,根据您的选择吧。本人选择下载了美国英语与大陆汉语。当然,坑爹的微软还专门为Kinect

准备Kinect运行时语言,支持语言较少,不过连日语都支持,竟然不支持汉语

或许仅仅是日语发音简单吧。

如果您和本人一样使用的是VS Express,那么请再下载WDK7.1,这个语音库需要一点点ATL支

持(貌似就COM智能指针),坑爹的微软在Express里面没有ATL库,为了获取合法ATL库需要下载这个

WDK7.1,里面有能合法使用的ALT库。我直接安装到C盘,请在项目里面包含这三个库的目录

语音平台、WDK、Kinect

有您自己的需要请自行包含其他库,最好将语音平台放到第一位。

目前语音识别应该只能识别PCM编码,处理后的数据是浮点编码,我们不能直接使用SDK默认提供的IStream。

是的,基于COM组件的通用性,我们只需继承IStream实现一个Stream类即可完成音频流的处理。

这个类主要实现Read方法即可,Seek方法在SR中也算比较重要不过Kinect还不支持,这个方法直接返回S_OK即可

实现这个类有两种办法,一种是基于前一节说的音频帧。自己用一个比较大的缓冲区(最好设计上是循环的),

获取音频帧再将数据写在里面,Read时将数据写入即可,比较麻烦。还有一个就是SDK提供例子里面使用的:

傀儡战术。

获取SDK提供的默认的IStream,Read的时候Read这个傀儡即可,数据获取完毕后进行转换即可,代码如下:

[cpp] view plain copy
  1. // IStream Read方法的实现
  2. STDMETHODIMP KinectAudioStreamWrapper::Read(void *pBuffer, ULONG cbBuffer, ULONG *pcbRead){
  3. // 参数检查
  4. if (!pBuffer || !pcbRead) return E_INVALIDARG;
  5. // 在读取前未使用 m_SpeechActive 返回S_OK
  6. if (!m_SpeechActive){
  7. *pcbRead = cbBuffer;
  8. return S_OK;
  9. }
  10. HRESULT hr = S_OK;
  11. // 目标是将浮点编码转换成16位PCM编码
  12. INT16* const p16Buffer = reinterpret_cast<INT16*>(pBuffer);
  13. // 长度倍数
  14. const int multiple = sizeof(float) / sizeof(INT16);
  15. // 检查缓冲区释放足够
  16. auto float_buffer_size = cbBuffer / multiple;
  17. if (float_buffer_size > m_uFloatBuferSize){
  18. // 不够就重新申请内存
  19. m_uFloatBuferSize = float_buffer_size;
  20. if (m_pFloatBuffer) delete[]m_pFloatBuffer;
  21. m_pFloatBuffer = new float[m_uFloatBuferSize];
  22. }
  23. // 缓冲区写入进度 字节为单位
  24. BYTE* pWriteProgress = reinterpret_cast<BYTE*>(m_pFloatBuffer);
  25. // 目前读取量
  26. ULONG bytesRead = 0;
  27. // 需要读取量
  28. ULONG bytesNeed = cbBuffer * multiple;
  29. // 循环读取
  30. while (true){
  31. // 已经不需要语音的情况下
  32. if (!m_SpeechActive){
  33. *pcbRead = cbBuffer;
  34. hr = S_OK;
  35. break;
  36. }
  37. // 从包装对象获取数据
  38. hr = m_p32BitAudio->Read(pWriteProgress, bytesNeed, &bytesRead);
  39. bytesNeed -= bytesRead;
  40. pWriteProgress += bytesRead;
  41. // 检查是否足够
  42. if (!bytesNeed){
  43. *pcbRead = cbBuffer;
  44. break;
  45. }
  46. // 不然就睡一个时间片的时间
  47. Sleep(20);
  48. }
  49. // 数据处理 float -> 16bit PCM
  50. if (!bytesNeed){
  51. for (UINT i = 0; i < cbBuffer / multiple; i++) {
  52. float sample = m_pFloatBuffer[i];
  53. // 区间保证
  54. //sample = max(min(sample, 1.f), -1.f);
  55. if (sample > 1.f) sample = 1.f;
  56. if (sample < -1.f) sample = -1.f;
  57. // 数据转换
  58. float sampleScaled = sample * (float)SHRT_MAX;
  59. p16Buffer[i] = (sampleScaled > 0.f) ? (INT16)(sampleScaled + 0.5f) : (INT16)(sampleScaled - 0.5f);
  60. }
  61. }
  62. return hr;
  63. }

请注意,语音识别引擎初始化时要获取一定的音频数据才能完成,很可能花上几秒甚至十几秒来初始化,这很蛋疼,

不知道微软怎么想的。为此,我们增加一个变量表示SR是否处于激活状态,没被激活时,返回假数据欺骗SR引擎即可。

这样几乎就无需花时间等待初始化了。

我们这里语音识别使用的方法是载入静态SRGS语法文件,当然可以载入动态语法,不过详细的请翻阅官方文档。

至于SRGS的语法可以翻看W3C的文档,也可以看微软的文档。

好,让我们写一个SRGS语法文件吧,SRGS是基于xml的,后缀名就使用xml吧。我这里使用的是汉语,

毕竟文字处理上,汉语优势很大,几个字就能表示一个句子。经本人测试,汉语里面可以识别英语,但是识别率

[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <grammar version="1.0" xml:lang="zh-CN" mode="voice" root="根语音" xmlns="http://www.w3.org/2001/06/grammar" tag-format="semantics/1.0">
  3. <rule id="根语音" scope="public">
  4. <one-of>
  5. <item>前进</item>
  6. </one-of>
  7. <one-of>
  8. <item>后退</item>
  9. </one-of>
  10. </rule>
  11. </grammar>

这样差不多就是最简单的SRGS文件吧,重要的有:

开头, xml的标准,使用utf8即可

grammar标签是主标签,里面xml:lang属性选择您的语言,大陆汉语就是zh-CN了。还有就是root,表示根标签的名字,

SR引擎就从这里识别基本短语,其他的照写即可。

每个规则使用rule标签,多选一使用one-of标签,基本短语使用item,规则引用使用ruleref,tag标签能使用字符串或者

貌似js的脚本标上自己想要的数据,还有token标签,这些可以查看文档了解。

我们的目标实现下面短语:

1.我在XX YY发现了ZZ AA BB

比如我在脚(XX)上(YY)发现了两(ZZ)枚(AA)高爆穿甲弹(BB)

XX表示地点,这个信息很重要

YY表示相对方位,这个信息不重要

ZZ表示数量,这个信息很重要

AA表示量词,几乎没用

BB表示物品,这个信息很重要

[html] view plain copy
  1. <rule id="发现东西">
  2. <example> 我在脚上发现两枚穿甲弹 </example>
  3. <item>我在</item>
  4. <ruleref uri="#地点"/>
  5. <ruleref uri="#相对位置"/>
  6. <item>发现</item>
  7. <item repeat="0-1">了</item>
  8. <ruleref uri="#数量"/>
  9. <ruleref uri="#量词"/>
  10. <ruleref uri="#目标物体"/>
  11. </rule>
  12. <rule id="地点">
  13. <example> 脚 </example>
  14. <example> 房子 </example>
  15. <one-of>
  16. <item>脚</item>
  17. <item>房子</item>
  18. <item>船</item>
  19. <item>头</item>
  20. </one-of>
  21. </rule>
  22. <rule id="相对位置">
  23. <example> 上 </example>
  24. <one-of>
  25. <item>上</item>
  26. <item>上面</item>
  27. <item>里面</item>
  28. <item>旁边</item>
  29. <item>附近</item>
  30. </one-of>
  31. </rule>
  32. <rule id="数量">
  33. <example> 两 </example>
  34. <one-of>
  35. <item>一</item>
  36. <item>二</item>
  37. <item>两</item>
  38. <item>三</item>
  39. <item>四</item>
  40. <item>五</item>
  41. <item>六</item>
  42. <item>七</item>
  43. <item>八</item>
  44. <item>九</item>
  45. <item>十</item>
  46. </one-of>
  47. </rule>
  48. <rule id="量词">
  49. <example> 枚 </example>
  50. <one-of>
  51. <item>枚</item>
  52. <item>个</item>
  53. <item>块</item>
  54. <item>片</item>
  55. <item>辆</item>
  56. <item>架</item>
  57. <item>次</item>
  58. <item>部</item>
  59. <item>台</item>
  60. <item>把</item>
  61. </one-of>
  62. </rule>
  63. <rule id="目标物体">
  64. <example> 坦克 </example>
  65. <one-of>
  66. <item>高爆穿甲弹</item>
  67. <item>穿甲弹</item>
  68. <item>坦克</item>
  69. <item>铅笔</item>
  70. <item>电脑</item>
  71. <item>苹果</item>
  72. <item>锤子</item>
  73. <item>手机</item>
  74. <item>阿姆斯特朗回旋加速喷气式阿姆斯特朗炮</item>
  75. </one-of>
  76. </rule>

这部分就差不多了,再在“根语言”里面更新:

[html] view plain copy
  1. <rule id="根语音" scope="public">
  2. <one-of>
  3. <item>
  4. <ruleref uri="#发现东西"/>
  5. </item>
  6. </one-of>
  7. </rule>

如果再增加一个,"战况"

[html] view plain copy
  1. <rule id="根语音" scope="public">
  2. <one-of>
  3. <item>
  4. <ruleref uri="#发现东西"/>
  5. </item>
  6. <item>
  7. <ruleref uri="#战况"/>
  8. </item>
  9. </one-of>
  10. </rule>
[html] view plain copy
  1. </pre><p></p><pre>

就这样写。

在实际使用时,会遇到非常多的同义词,或者选择支很多。如果把识别的字符串进行比较的话很吃力,我们就可以用tag标签

于是在“数量” 那里可以这样写:out = 10;就能对外输出10,

[html] view plain copy
  1. <rule id="数量">
  2. <example> 两 </example>
  3. <one-of>
  4. <item>一<tag>out=1;</tag></item>
  5. <item>二<tag>out=2;</tag></item>
  6. <item>两<tag>out=2;</tag></item>
  7. <item>三<tag>out=3;</tag></item>
  8. <item>四<tag>out=4;</tag></item>
  9. <item>五<tag>out=5;</tag></item>
  10. <item>六<tag>out=6;</tag></item>
  11. <item>七<tag>out=7;</tag></item>
  12. <item>八<tag>out=8;</tag></item>
  13. <item>九<tag>out=9;</tag></item>
  14. <item>十<tag>out=10;</tag></item>
  15. </one-of>
  16. </rule>

也能使用字符串。但是数据处理是数字才方便,不是么

类似地,我们将“发现东西”更新至:

[html] view plain copy
  1. <rule id="发现东西">
  2. <example> 我在脚上发现两枚穿甲弹 </example>
  3. <item>我在</item>
  4. <ruleref uri="#地点"/>
  5. <tag> out.地点 = rules.地点; </tag>
  6. <ruleref uri="#相对位置"/>
  7. <item>发现</item>
  8. <item repeat="0-1">了</item>
  9. <ruleref uri="#数量"/>
  10. <tag> out.数量 = rules.数量; </tag>
  11. <ruleref uri="#量词"/>
  12. <ruleref uri="#目标物体"/>
  13. <tag> out.物体 = rules.目标物体; </tag>
  14. </rule>

毕竟是脚本,看就能看懂。 out.A = rules.B,AB不一定相同,但是B一定和前面引用的id一样

现在我们增加一个短语:“战况” 比如

我方击毁敌方厕所

也是很简单,我就将代码直接放在这了:

[html] view plain copy
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <grammar version="1.0" xml:lang="zh-CN" mode="voice" root="根语音" xmlns="http://www.w3.org/2001/06/grammar" tag-format="semantics/1.0">
  3. <rule id="根语音" scope="public">
  4. <one-of>
  5. <item>
  6. <ruleref uri="#发现东西"/>
  7. <tag> out.发现东西 = rules.发现东西; </tag>
  8. </item>
  9. <item>
  10. <ruleref uri="#战况"/>
  11. <tag> out.战况 = rules.战况; </tag>
  12. </item>
  13. </one-of>
  14. </rule>
  15. <rule id="战况">
  16. <example> 我们击毁了敌方厕所 </example>
  17. <example> 他们击穿我方的装甲 </example>
  18. <ruleref uri="#人物对象"/>
  19. <tag> out.主语 = rules.人物对象; </tag>
  20. <ruleref uri="#战况动词"/>
  21. <tag> out.谓语 = rules.战况动词; </tag>
  22. <item repeat="0-1">了</item>
  23. <ruleref uri="#人物对象"/>
  24. <tag> out.对象 = rules.人物对象; </tag>
  25. <item repeat="0-1">的</item>
  26. <ruleref uri="#战况名词"/>
  27. <tag> out.宾语 = rules.战况名词; </tag>
  28. </rule>
  29. <rule id="人物对象">
  30. <example> 我们 </example>
  31. <example> 他们 </example>
  32. <one-of>
  33. <item>我们<tag>out=0;</tag></item>
  34. <item>他们<tag>out=1;</tag></item>
  35. <item>我方<tag>out=0;</tag></item>
  36. <item>敌方<tag>out=1;</tag></item>
  37. </one-of>
  38. </rule>
  39. <rule id="战况动词">
  40. <example> 击毁 </example>
  41. <example> 击败 </example>
  42. <one-of>
  43. <item>击毁<tag>out=0;</tag></item>
  44. <item>击败<tag>out=1;</tag></item>
  45. <item>击穿<tag>out=2;</tag></item>
  46. </one-of>
  47. </rule>
  48. <rule id="战况名词">
  49. <example> 装甲 </example>
  50. <example> 计算机 </example>
  51. <one-of>
  52. <item>装甲<tag>out=0;</tag></item>
  53. <item>厕所<tag>out=1;</tag></item>
  54. <item>计算机<tag>out=2;</tag></item>
  55. <item>电脑<tag>out=2;</tag></item>
  56. <item>核弹发射井<tag>out=3;</tag></item>
  57. </one-of>
  58. </rule>
  59. <rule id="发现东西">
  60. <example> 我在脚上发现两枚穿甲弹 </example>
  61. <item>我在</item>
  62. <ruleref uri="#地点"/>
  63. <tag> out.地点 = rules.地点; </tag>
  64. <ruleref uri="#相对位置"/>
  65. <item>发现</item>
  66. <item repeat="0-1">了</item>
  67. <ruleref uri="#数量"/>
  68. <tag> out.数量 = rules.数量; </tag>
  69. <ruleref uri="#量词"/>
  70. <ruleref uri="#目标物体"/>
  71. <tag> out.物体 = rules.目标物体; </tag>
  72. </rule>
  73. <rule id="地点">
  74. <example> 脚 </example>
  75. <example> 房子 </example>
  76. <one-of>
  77. <item>脚<tag>out=0;</tag></item>
  78. <item>房子<tag>out=1;</tag></item>
  79. <item>船<tag>out=2;</tag></item>
  80. <item>头<tag>out=3;</tag></item>
  81. </one-of>
  82. </rule>
  83. <rule id="相对位置">
  84. <example> 上 </example>
  85. <one-of>
  86. <item>上</item>
  87. <item>上面</item>
  88. <item>里面</item>
  89. <item>旁边</item>
  90. <item>附近</item>
  91. </one-of>
  92. </rule>
  93. <rule id="数量">
  94. <example> 两 </example>
  95. <one-of>
  96. <item>一<tag>out=1;</tag></item>
  97. <item>二<tag>out=2;</tag></item>
  98. <item>两<tag>out=2;</tag></item>
  99. <item>三<tag>out=3;</tag></item>
  100. <item>四<tag>out=4;</tag></item>
  101. <item>五<tag>out=5;</tag></item>
  102. <item>六<tag>out=6;</tag></item>
  103. <item>七<tag>out=7;</tag></item>
  104. <item>八<tag>out=8;</tag></item>
  105. <item>九<tag>out=9;</tag></item>
  106. <item>十<tag>out=10;</tag></item>
  107. </one-of>
  108. </rule>
  109. <rule id="量词">
  110. <example> 枚 </example>
  111. <one-of>
  112. <item>枚</item>
  113. <item>个</item>
  114. <item>块</item>
  115. <item>片</item>
  116. <item>辆</item>
  117. <item>架</item>
  118. <item>次</item>
  119. <item>部</item>
  120. <item>台</item>
  121. <item>把</item>
  122. </one-of>
  123. </rule>
  124. <rule id="目标物体">
  125. <example> 坦克 </example>
  126. <one-of>
  127. <item>高爆穿甲弹<tag>out=0;</tag></item>
  128. <item>穿甲弹<tag>out=1;</tag></item>
  129. <item>坦克<tag>out=2;</tag></item>
  130. <item>铅笔<tag>out=3;</tag></item>
  131. <item>电脑<tag>out=4;</tag></item>
  132. <item>苹果<tag>out=5;</tag></item>
  133. <item>锤子<tag>out=6;</tag></item>
  134. <item>手机<tag>out=7;</tag></item>
  135. <item>阿姆斯特朗回旋加速喷气式阿姆斯特朗炮<tag>out=8;</tag></item>
  136. </one-of>
  137. </rule>
  138. </grammar>

这次就到这里了,这次的SRGS范例希望帮助各位,下一节再写C++部分代码吧。

  • 本文已收录于以下专栏:
  • Kinect for Windows SDK v2.0 开发笔记

Kinect for Windows SDK v2.0 开发笔记 (七)语音识别(上)相关推荐

  1. Kinect for Windows SDK v2.0 开发笔记 (十) 高清面部帧(1) FACS 介绍

    转载于:https://blog.csdn.net/dustpg/article/details/38892783 使用SDK: Kinect for Windows SDK v2.0 public ...

  2. Kinect for Windows SDK v2.0 开发笔记 (十三) 高清面部帧(4) 面部模型构建器

     (转载请注明出处) 使用SDK: Kinect for Windows SDK v2.0 public preview1409 同前面,因为SDK未完成,不附上函数/方法/接口的超链接. 这次让 ...

  3. Kinect for Windows SDK v2.0 开发笔记 (十二) 高清面部帧(3) 面部模型(2D)

     (转载请注明出处) 使用SDK: Kinect for Windows SDK v2.0 public preview1409 同前面,因为SDK未完成,不附上函数/方法/接口的超链接. 是的, ...

  4. Kinect for Windows SDK v2.0 开发笔记 (五)骨骼帧与笑面男

    (转载请注明出处) 使用SDK: Kinect for Windows SDK v2.0 public preview 这次说说这骨骼帧的获取.嗯,Kinect买来就为这个啊.不然其他数据,买其他产品 ...

  5. kinect for windows SDK 2.0下载和kinect 2安装调试

    kinect v2价格便宜.功能强大,很适合用来做三维重构开发研究.下面,简单记录一下Kinect2及其开源包kinect for windows SDK 2.0的安装与调试.我买的设备是xbox o ...

  6. [译]Kinect for Windows SDK开发入门(八):骨骼追踪进阶 上

    前7篇文件我们介绍了Kinect SDK中各种传感器的各种基本知识,我们用实验的方式演示了这些基本对象和方法的如何使用,这些都是Kinect开发最基本的知识.了解了这些基本知识后,就可以开发出一个基于 ...

  7. Kinect for Windows SDK开发入门

    Kinect for Windows SDK开发入门(一):开发环境配置 首先来看一下Kinect设备: 1. Kinect设备 黑色的Kinect设备如下图:基座和感应器之间有一个电动的马达,通过程 ...

  8. [译]Kinect for Windows SDK开发入门(二):基础知识 上

    上篇文章介绍了Kinect开发的环境配置,这篇文章和下一篇文章将介绍Kinect开发的基本知识,为深入研究Kinect for Windows SDK做好基础. 每一个Kinect应用都有一些基本元素 ...

  9. 深度相机(八)--OpenNI及与Kinect for windows SDK的比较

     OpenNI(开放自然交互)是一个多语言,跨平台的框架,它定义了编写应用程序,并利用其自然交互的API.OpenNI API由一组可用来编写通用自然交互应用的接口组成.OpenNI的主要目的是要 ...

  10. 【计算机视觉】深度相机(八)--OpenNI及与Kinect for windows SDK的比较

    OpenNI(开放自然交互)是一个多语言,跨平台的框架,它定义了编写应用程序,并利用其自然交互的API.OpenNI API由一组可用来编写通用自然交互应用的接口组成.OpenNI的主要目的是要形成一 ...

最新文章

  1. 子窗体更新父窗体控件内容
  2. MimbleWimble 系列之Pedersen 承诺
  3. 如何去设计一个自适应的网页设计或HTMl5
  4. python月薪是多少-2019年 Python就业市场行情好不好, 薪资多少?
  5. 学生用的笔记本电脑什么样的好_大学生用的学生党笔记本什么牌子好,听听学姐的...
  6. kmeans中的k的含义_聚类的Python实现(二):确定分群数K
  7. springboot 使用idea打包 遇到问题
  8. sql server 修改表结构语法大全
  9. 放松时刻——C#分割字符串
  10. 机器学习中的数学--数学知识复习
  11. mysql数据库二进制_Mysql数据库简单安装(二进制)
  12. php是视频还是图片格式,php 视频、音频和图片文件上传,该如何解决
  13. 让go语言调用外部程序时支持管道符
  14. 谷歌浏览器的笔记在哪里_selenium学习笔记之启动谷歌浏览器
  15. JavaSE思维导图总结
  16. ubuntu下鼠标右键新建文档
  17. java实现wps函数IRR,Excel表格技巧—如何用IRR函数算内部收益率
  18. 用c语言输入年份 月份 显示天数,java输入月份,年份,显示对应月份的天数,...
  19. python如何用opencv把一个视频按每10秒一小段切割
  20. C盘空间不够?教你简单扩容C盘空间

热门文章

  1. 2021学习 - OEM,ODM,OBM,JDM和白牌化
  2. Email-FTP-RTSP协议实践研究
  3. 共模电压和差模电压两种理解方式
  4. TCP通信协议基本操作
  5. 利润表三点式审阅:以御银股份为例
  6. ping 不通 华为三层交换机vlan_华为三层交换机VLAN间路由怎么设置
  7. 阿里云ECS centos8连接可视化界面
  8. Base64转MultipartFile
  9. 腾讯视频获取 MP4格式源并下载
  10. 桌面计算机密码修改频率,教大家如何更改电脑的显示频率