入手树莓派也有两年有余了,其实有很多有趣的想法,比如智能小车,智能感知,智能捕捉等等,也买了不少传感器件,组装小车的配件都买了,买组件的激情到是很高,但缺少了去实现动力(是懒吧),也就一直尘封着,偶尔翻出来见见光之后就又再次封装了起来!

  偶尔的一次看到了 百度语音-永久免费智能语音开放平台 感觉挻有趣的,于是决定搞起,至于动力,也许看过 树莓派之 RGB LED 跑马灯 就会明白,就不在累述,也是分享中的其中一个示例,此示例整体来说实现相对比较容易,百度语音也已为 Python 提供了在线访问的 RestApi SDK,所以需要我们自己来实现的内容相对还是比较少的。同时小米也推出了自己的 水滴平台 [水滴平台为可以落地的小米全生态硬件产品提供语音服务,使用它可以为硬件设备提供功能,使用户能够以更直观的方式使用语音与设备进行交互。] 我也算是个米粉,这里就不多说了,有兴趣的同学可以了解一下 ^_^ 。

  软件工程师的工作不是写程序, 而是合理使用工具解决问题,对此个人是比较认同的,术业有专攻,我们只需专注于做自己想做的一块,其余的就由专业的人去完成。于 Python 而言,其提供了很强大类库供我们去使用以及去定制化自己需要的!

  说了这么多,先让我们了解一下此次示例使用的元件 树莓派、USB 声卡、百度语音 API、开发语言是 Python (由于没有 USB 声卡,只好在笔记本上进行了演示,查看资料说树莓派端对 pyaudio 并不兼容,可以用 arecord 进行录音,目前为止还未在树莓派上做测试,当前也就只有按照 Win10 测试过程来讲了)。

  首先需要配置 百度语音 SDK 类库,执行 sudo pip install baidu-aip ,具体使用可以查看官方 在线语音识别 Python SDK 文档 ;执行 sudo apt-get install python-wave* 安装 wave 类库,执行 sudo pip install pyaudio 安装 pyaudio 类库 (Windows系统f需要使用 pip 执行),相关环境安装好后,就可以编写代码啦。
 
  本示例分为语音识别和语音合成以及本地录音功能,先了解一下文件目录结构:

1
2
3
4
5
|——test.py # 测试文件
|——speech # 语音 API 包目录
| |——__init__.py # 语音 API 导出类
| |——rpi_record.py # 本地录音 API
| |——rpi_speech.py # 百度语音识别、语音合成功能封装

 
  来看一下 rpi_speech.py 文件,下面代码中的常量APP_ID 在百度云控制台中创建,常量 API_KEY 与 SECRET_KEY 是在创建完毕应用后,系统分配给用户的,均为字符串,用于标识用户,为访问做签名验证,可在 AI 服务控制台中的 应用列表 中查看,如果还没有应用则需要先创建新应用,具体示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
百度语音功能封装
"""
import sys
# 引入百度 Speech SDK
from aip import AipSpeech
# 定义常量
APP_ID = '你的 App ID'
API_KEY = '你的 Api Key'
SECRET_KEY = '你的 Secret Key'
def speech(file_path):
"""
语音识别
---
*file_path 音频路径*
原始语音的录音格式目前只支持评测 8k/16k 采样率 16bit 位深的单声道语音
压缩格式支持:pcm(不压缩)、wav、amr
系统支持语言种类:中文(zh)、粤语(ct)、英文(en)
"""
print(file_path, "开始语音识别")
file_stream = _get_file_content(file_path)
result = speechs(file_stream)
print("语音识别结束")
return result
def speechs(file_stream):
"""
语音识别
---
*file_stream 音频流*
原始语音的录音格式目前只支持评测 8k/16k 采样率 16bit 位深的单声道语音
压缩格式支持:pcm(不压缩)、wav、amr
系统支持语言种类:中文(zh)、粤语(ct)、英文(en)
"""
"""
初始化AipSpeech对象
"""
baiduAipSpeech = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
# 在线请求百度语音识别
result = baiduAipSpeech.asr(file_stream, "wav", 16000, {'lan': 'zh'})
return result
def _get_file_content(file_path):
"""
读取文件
"""
with open(file_path, 'rb') as fp:
return fp.read()
def synthesis(text, file_path):
"""
语音合成
----
*text 需要合成语音的文字*
*file_path 保存语音合成文件路径*
"""
"""
初始化AipSpeech对象
"""
baiduAipSpeech = AipSpeech(APP_ID, API_KEY, SECRET_KEY)
print("开始语音合成")
result = baiduAipSpeech.synthesis(
text, 'zh', 1, {"spd": 5, "per": 4, "pit": 5})
print("语音合成结束")
# 识别正确返回语音二进制 错误则返回dict 参照下面错误码
if not isinstance(result, dict):
with open(file_path, 'wb') as f:
f.write(result)
print(file_path, ",语音合成保存成功")
return True
print(result, ",语音保存失败")
return False

 
  接下来是 rpi_record.py 文件,本地录音 API,本示例是使用 pyaudio 类库实现的,具体示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
本地录音 API
"""
import base64
import datetime
import os
import sys
import time
import wave
import numpy as np
from pyaudio import PyAudio, paInt16
class RpiApiRecord():
"""
本地录音 API
---
原始语音的录音格式目前只支持评测 8k/16k 采样率 16bit 位深的单声道语音
压缩格式支持:pcm(不压缩)、wav、amr
系统支持语言种类:中文(zh)、粤语(ct)、英文(en)
"""
__NUM_SAMPLES = 2000 # pyAudio内部缓存的块的大小
__SAMPLING_RATE = 16000 # 取样频率
__LEVEL = 2000 # 声音保存的阈值
def __init__(self, compressed_fromat=".wav"):
"""
*compressed_fromat 压缩格式支持:pcm(不压缩)、wav、amr*
"""
self.__compressed_fromat = compressed_fromat
def __save_wave_file(self, file_patch, data):
"""将data中的数据保存到名为filename的WAV文件中"""
wf = wave.open(file_patch, 'wb')
wf.setnchannels(1)
wf.setsampwidth(2)
wf.setframerate(self.__SAMPLING_RATE)
wf.writeframes(b"".join(data))
wf.close()
def record(self, total_time=5):
"""
开启声音输入
----
*total_time 录音时长,单位秒,默认5秒*
返回结果:音频路径
"""
save_buffer = []
first = True
begin_time = 0
temp = 0
pa = PyAudio()
stream = pa.open(format=paInt16, channels=1, rate=self.__SAMPLING_RATE, input=True,
frames_per_buffer=self.__NUM_SAMPLES)
while True:
if first:
# 读入NUM_SAMPLES个取样
string_auto_data = stream.read(self.__NUM_SAMPLES)
# 将读入的数据转换为数组
audio_data = np.fromstring(string_auto_data, dtype=np.long)
temp = np.max(audio_data)
print(temp)
if temp > self.__LEVEL and first:
first = False
temp = 0
print("检测到信号,五秒后开始")
for i in range(1, 6, 1):
print(i, "s")
time.sleep(1)
print('开始录音,计时', total_time, '秒')
begin_time = time.time()
if first:
continue
# NUM_SAMPLES 取样
string_auto_data = stream.read(self.__NUM_SAMPLES)
save_buffer.append(string_auto_data)
time_count = time.time() - begin_time
print("录音进行中,第", time_count, "s")
if time_count > total_time:
"""
压缩格式支持
pcm(不压缩)、wav、amr
"""
file_path = sys.path[0] + "\\" + datetime.datetime.now().strftime(
"%Y-%m-%d_%H_%M_%S") + self.__compressed_fromat
self.__save_wave_file(file_path, save_buffer)
save_buffer = []
first = True
print(file_path, "保存成功正在进行语音识别")
return file_path

 
  然后就是导出类文件 __init__.py,具体示例代码如下:

1
2
3
4
5
6
7
8
9
10
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
音频 API
"""
from .rpi_record import RpiApiRecord
from .rpi_speech import speech, speechs
__version__ = "0.0.0.1"

 
  最后就是见证奇迹的时刻了,是不是有些激动,创建 test.py 文件,具体示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import datetime
import sys
from speech import RpiApiRecord, rpi_speech
def test_speech():
"""
百度语音识别功能
----
*返回:语音识别的结果*
"""
file_path = sys.path[0] + "\\2017-09-22_09_37_45.wav"
"""调用百度语音识别接口,接收语音识别结果"""
result = rpi_speech.speech(file_path)
print(result)
return result
def test_speechs():
"""
测试本地录音,百度语音识别功能
----
*返回:语音识别的结果*
"""
# 初始化 本地录音PAI RpiApiRecord
api_record = RpiApiRecord(".wav")
"""接收本地录音存放地址"""
file_path = api_record.record(10)
"""调用百度语音识别接口,接收语音识别结果"""
result = rpi_speech.speech(file_path)
print(result)
return result
def test_synthesis():
"""
测试百度语音合成功能
----
*返回:语音合成文件路径*
"""
"""保存语音合成文件路径"""
file_path = sys.path[0] + "\\" + datetime.datetime.now().strftime(
"%Y-%m-%d_%H_%M_%S") + ".wav"
result = rpi_speech.synthesis("你好吗,最近过得怎么样呢,嘿嘿!", file_path)
print("语音合成结果:", result)
return file_path
def test_synthesis_speech():
"""
百度语音合成后,使用百度语音识别
"""
file_path = test_synthesis()
"""调用百度语音识别接口,接收语音识别结果"""
result = rpi_speech.speech(file_path)
print(result)
if __name__ == "__main__":
print("进入 main 方法")
# test_speech()
test_speechs()
# test_synthesis()
# test_synthesis_speech() # 这个示例并没有成功,总是返回错误码:3301(请上传清晰的音频),不知道是不是因为百度对音频做了处理
print("离开 main 方法")

 
  最基础的语音识别是不是感觉挻容易实现,其实可以在此基础上做些扩展,比如当前我想的,可以通过声音定位声源,测试声距,通过测定声源位置,启动并驱动电机,使摄像头捕捉人像并跟踪,同时摄像头也可以识别出人脸等,是不是很有画面感呢!再者还可以实现人机对话,声音感知等等,越想是不是越激动啦,过程还是需要自己动手去实现,乐趣更多的还是在实践的过程中 ^_^。
 
参考文档:

文中图片引用: