计算机如何"听"声音?
语音识别的过程可以类比为“翻译”:
语音数字化:把语音信号“翻译”成计算机能理解的数字信号。
特征提取:从数字信号中提取“关键信息”,就像提取语音的“指纹”。
模型匹配:用预训练的模型将这些“指纹”与已知的语音模式进行匹配,找到对应的文本。
文本输出:把匹配到的文本“翻译”出来,就像把语音“翻译”成文字一样。
1 声音的数字化表示
声音在计算机中是如何表示的?
可以有多种形式表示声音:
- 波形图
- 梅尔频谱图(频域图)
- 显示色谱图(音高特征)
也有很多声音的特征来辅助分析声音: - 响度:反映声音的响亮程度
- 过零率:反映信号频率变化的快慢,对语音检测很有用
- BPM (Beats Per Minute):每分钟节拍数,反映音乐节奏的快慢
# 基础音频处理示例
# 这个程序可以分析音频文件的各种特征,包括波形、频谱和音高等
# 导入必要的库
import librosa # 音频处理的主要库
import librosa.display # 用于显示音频相关的图形
import matplotlib.pyplot as plt # 绘图库
import numpy as np # 数值计算库
from matplotlib import font_manager # 字体管理
import soundfile as sf # 音频文件读取库,支持更多音频格式
# 在运行这个程序之前,需要安装以下依赖:
# pip install soundfile numpy matplotlib librosa
# 设置中文字体,解决中文显示问题
try:
# macOS 常用中文字体,按优先级排序
plt.rcParams['font.sans-serif'] = ['PingFang HK', 'Arial Unicode MS', 'SimHei']
plt.rcParams['axes.unicode_minus'] = False # 解决负号'-'显示为方块的问题
except:
print("警告: 未找到合适的中文字体,可能会显示乱码")
def analyze_audio(audio_path):
"""
分析音频文件的主函数
参数:
audio_path: 音频文件的路径
"""
try:
# 第一步:加载音频文件
print("正在加载音频文件...")
try:
# 首先尝试使用 soundfile 加载(支持更多音频格式)
audio, sr = sf.read(audio_path)
# 如果是立体声(多声道),转换为单声道
if len(audio.shape) > 1:
audio = np.mean(audio, axis=1) # 对所有声道取平均
except Exception as e:
# 如果 soundfile 加载失败,使用 librosa 的新方法加载
# 使用 load_audio 替代已弃用的 audioread_load
audio, sr = librosa.load(audio_path, sr=None, mono=True)
print(f"注意: 使用备选方法加载音频 - {str(e)}")
# 计算音频时长(采样点数/采样率)
duration = len(audio) / sr
# 打印音频基本信息
print(f"\n音频信息:")
print(f"采样率: {sr} Hz") # 每秒采样次数
print(f"时长: {duration:.2f} 秒")
print(f"采样点数: {len(audio)}")
# 第二步:创建图形窗口
plt.figure(figsize=(15, 10)) # 设置图形大小
# 2.1 显示波形图(时域图)
plt.subplot(311) # 3行1列的第1个子图
# 创建时间轴:将采样点转换为实际时间(秒)
times = np.arange(len(audio)) / sr
plt.plot(times, audio)
plt.title('音频波形图', fontsize=12)
plt.xlabel('时间 (秒)', fontsize=10)
plt.ylabel('振幅', fontsize=10)
plt.grid(True) # 显示网格线
# 2.2 显示梅尔频谱图(频域图)
plt.subplot(312) # 3行1列的第2个子图
# 计算梅尔频谱图(模拟人耳对声音的感知)
mel_spect = librosa.feature.melspectrogram(y=audio, sr=sr)
# 转换为分贝单位
mel_spect_db = librosa.power_to_db(mel_spect, ref=np.max)
# 显示频谱图
img = librosa.display.specshow(mel_spect_db,
x_axis='time', # x轴显示时间
y_axis='mel', # y轴显示梅尔频率
sr=sr)
plt.colorbar(img, format='%+2.0f dB') # 添加颜色条,显示分贝值
plt.title('梅尔频谱图 (频率特征)', fontsize=12)
plt.xlabel('时间 (秒)', fontsize=10)
plt.ylabel('频率', fontsize=10)
# 2.3 显示色谱图(音高特征)
plt.subplot(313) # 3行1列的第3个子图
# 计算色谱图(显示音高特征)
chromagram = librosa.feature.chroma_stft(y=audio, sr=sr)
librosa.display.specshow(chromagram,
x_axis='time', # x轴显示时间
y_axis='chroma') # y轴显示音高
plt.colorbar() # 添加颜色条
plt.title('音高特征图', fontsize=12)
plt.xlabel('时间 (秒)', fontsize=10)
plt.ylabel('音高', fontsize=10)
# 调整子图布局
plt.tight_layout(pad=2.0) # 设置子图间距
plt.suptitle('音频分析结果', fontsize=14, y=1.02) # 添加总标题
# 保存和显示图形
plt.savefig('audio_analysis.png', dpi=300, bbox_inches='tight')
print("\n分析图已保存为 'audio_analysis.png'")
plt.show()
# 第三步:计算和显示音频特征
print("\n音频特征分析:")
print("-" * 40)
# 3.1 计算音频的响度(音量大小)
rms = librosa.feature.rms(y=audio)[0] # 均方根能量
print(f"平均响度: {float(np.mean(rms)):.4f}")
# 3.2 计算过零率(信号正负变化的频率)
zero_crossings = librosa.zero_crossings(audio, pad=False)
print(f"过零率: {int(sum(zero_crossings))}")
# 3.3 检测音频节奏
try:
tempo, _ = librosa.beat.beat_track(y=audio, sr=sr)
# 修复:确保我们获取数组中的单个值
tempo_value = tempo.item() if hasattr(tempo, 'item') else tempo
print(f"估计节奏: {int(tempo_value)} BPM")
except:
print("无法检测节奏")
print("-" * 40)
# 添加特征解释
print("\n特征说明:")
print("- 响度:反映声音的响亮程度")
print("- 过零率:反映信号频率变化的快慢,对语音检测很有用")
print("- BPM (Beats Per Minute):每分钟节拍数,反映音乐节奏的快慢")
except FileNotFoundError:
print(f"找不到音频文件: {audio_path}")
except Exception as e:
print(f"处理音频时出错: {str(e)}")
# 程序入口
if __name__ == "__main__":
# 设置要分析的音频文件路径
audio_path = "test.m4a" # 可以替换为其他音频文件
print(f"正在分析音频文件: {audio_path}")
analyze_audio(audio_path)
1.2、运行结果
正在分析音频文件: test.m4a
正在加载音频文件...
/Users/jayliu/Downloads/文章分享/大白话说AI/4-3-audio_basic.py:41: UserWarning: PySoundFile failed. Trying audioread instead.
audio, sr = librosa.load(audio_path, sr=None, mono=True)
/Users/jayliu/Downloads/文章分享/大白话说AI/venv/lib/python3.11/site-packages/librosa/core/audio.py:184: FutureWarning: librosa.core.audio.__audioread_load
Deprecated as of librosa version 0.10.0.
It will be removed in librosa version 1.0.
y, sr_native = __audioread_load(path, offset, duration, dtype)
注意: 使用备选方法加载音频 - Error opening 'test.m4a': Format not recognised.
音频信息:
采样率: 48000 Hz
时长: 6.65 秒
采样点数: 319424
分析图已保存为 'audio_analysis.png'
2 语音识别实例
使用python简单的语音库和google的语音转文字的库:
# 语音识别程序
import sounddevice as sd
import numpy as np
import speech_recognition as sr
from scipy.io import wavfile
def record_audio(duration=5, sample_rate=44100):
"""
录制音频
duration: 录制时长(秒)
sample_rate: 采样率
"""
print(f"开始录音,持续 {duration} 秒...")
# 使用 sounddevice 录制音频
recording = sd.rec(
int(duration * sample_rate),
samplerate=sample_rate,
channels=1,
dtype=np.int16
)
sd.wait() # 等待录音完成
print("录音完成!")
return recording, sample_rate
def save_audio(recording, sample_rate, filename="recording.wav"):
"""保存录音为 WAV 文件"""
wavfile.write(filename, sample_rate, recording)
return filename
def transcribe_audio(audio_file):
"""将音频转换为文字"""
recognizer = sr.Recognizer()
with sr.AudioFile(audio_file) as source:
audio = recognizer.record(source)
try:
# 使用Google的在线语音识别服务,免费但有限制:
# - 每天有配额限制
# - 需要网络连接
# - 可能不够稳定
text = recognizer.recognize_google(audio, language='zh-CN') # 免费API,但建议替换为付费的商业API以获得更好的服务
return text
except sr.UnknownValueError:
return "无法识别音频内容"
except sr.RequestError as e:
return f"无法连接到语音识别服务:{e}"
def main():
"""主函数"""
try:
# 安装依赖提示
print("确保已安装必要的依赖:")
print("pip install sounddevice numpy scipy SpeechRecognition")
input("按回车键开始录音...")
# 录制音频
recording, sample_rate = record_audio()
# 保存音频文件
audio_file = save_audio(recording, sample_rate)
# 识别音频内容
print("\n正在识别音频...")
text = transcribe_audio(audio_file)
print("\n识别结果:")
print(text)
except Exception as e:
print(f"发生错误: {str(e)}")
print("可能的原因:")
print("1. 麦克风未正确连接")
print("2. 系统没有麦克风访问权限")
if __name__ == "__main__":
main()
3、运行结果
确保已安装必要的依赖:
pip install sounddevice numpy scipy SpeechRecognition
按回车键开始录音...
开始录音,持续 5 秒...
录音完成!
正在识别音频...
识别结果:
hello everyone my name is