• 基于双级阈值及过零率的语音激活检测(VAD)


    语音激活检测(Voice Activity Detection, VAD):也称为端点检测,目的就是要找到音频信号的开始和结束位置。

    时域方法:

    • 音量:只用音量来进行端点检测,是最简单的方法,但是会对清音造成误判。
    • 音量和过零率:以音量为主,过零率为辅,可以对清音进行较准确的检测。

    这里介绍第二种方法,结合音量和过零率的语音激活检测方法:

    •  以高阈值tu为标准,决定端点,作为初始端点;
    • 将端点前后延伸到低阈值tl处(如下图N1、N2点);
    • 再将端点前后延伸到过零率(tzc)处,以包含语音中的清音部分。

    图中 tl 的范围是完全包含了 tu 的范围。为什么还需要第一步,因为仅仅用第2步的话,噪音的部分会被计算进来。

    结合过零率找到 SUV 来做端点检测,基于如下的特征:浊音 ZCR < 静音 ZCR < 清音 ZCR。

    1. import librosa
    2. import matplotlib.pyplot as plt
    3. import numpy as np
    4. import soundfile as sf
    5. # 加载数据
    6. file_path = 'test1.wav'
    7. y, fs = librosa.load(file_path, sr=8000, mono=False)
    8. if len(y) == 2:
    9. y = y[0, :]
    10. # 分帧:每帧数据、每帧最大值、每帧幅度
    11. frame_length = 160
    12. hop_length = 80
    13. frame_datas = []
    14. frame_maxs = []
    15. frame_amps = []
    16. frame_zcrs = []
    17. for i in range(0, len(y) - frame_length, hop_length):
    18. frame_data = y[i: i + frame_length] - np.mean(y[i: i + frame_length])
    19. frame_max = np.max(frame_data)
    20. frame_amp = np.sum(np.abs(frame_data))
    21. frame_datas.append(frame_data)
    22. frame_maxs.append(frame_max)
    23. frame_amps.append(frame_amp)
    24. # 过门限率
    25. door_th = np.abs(np.min(frame_maxs)) * 2
    26. for i in range(len(frame_datas)):
    27. frame_data = frame_datas[i]
    28. frame_data = frame_data - door_th
    29. frame_zcr = np.sum(np.abs([np.sign(frame_data[j]) - np.sign(frame_data[j + 1]) for j in range(len(frame_data) - 1)])) / 2
    30. frame_zcrs.append(frame_zcr)
    31. # 基于双级阈值及过零率的语音激活检测(VAD)
    32. th = np.max(frame_amps) * 0.1
    33. tl = np.max(frame_amps) * 0.05
    34. th_zcr = np.max(frame_zcrs) * 0.2
    35. th_pairs = []
    36. temp = np.argwhere(frame_amps > th).squeeze()
    37. stop_flag = 1
    38. start = 0
    39. stop = 0
    40. for i in range(len(temp) - 1):
    41. if stop_flag == 1:
    42. start = temp[i]
    43. stop_flag = 0
    44. elif abs(temp[i] - temp[i - 1]) == 1 and (abs(temp[i] - temp[i + 1]) > 1 or i + 1 == len(temp) - 1) :
    45. stop = temp[i]
    46. stop_flag = 1
    47. th_pairs.append([start, stop])
    48. dst_data = np.zeros_like(y)
    49. for i in range(len(th_pairs)):
    50. start = th_pairs[i][0]
    51. stop = th_pairs[i][1]
    52. for i in range(start, 0, -1):
    53. if frame_amps[i] < tl:
    54. start_1 = i
    55. break
    56. for i in range(stop, len(frame_amps), 1):
    57. if frame_amps[i] < tl:
    58. stop_1 = i
    59. break
    60. for i in range(start_1, 0, -1):
    61. if frame_zcrs[i] < th_zcr:
    62. start_2 = i
    63. break
    64. for i in range(stop_1, len(frame_zcrs), 1):
    65. if frame_zcrs[i] < th_zcr:
    66. stop_2 = i
    67. break
    68. dst_data[hop_length * start_2: hop_length * stop_2 + frame_length] = \
    69. y[hop_length * start_2: hop_length * stop_2 + frame_length]
    70. # sf.write('dst_data2.wav', dst_data, fs)
    71. plt.subplot(4, 1, 1)
    72. plt.plot(y)
    73. plt.subplot(4, 1, 2)
    74. print(len([i for i in range(0, len(y) - frame_length, hop_length)]), len(frame_amps))
    75. plt.plot([i for i in range(0, len(y) - frame_length, hop_length)], frame_amps)
    76. plt.subplot(4, 1, 3)
    77. plt.plot([i for i in range(0, len(y) - frame_length, hop_length)], frame_zcrs)
    78. plt.subplot(4, 1, 4)
    79. plt.plot(dst_data)
    80. plt.show()

    参考: 语音处理/语音识别基础(六)- 语音的端点检测(EPD/VAD)

  • 相关阅读:
    MFC为“对话框中的控件添加变量”,QT中使用“ui.对象名称”来调用控件
    IntelliJ IDEA 配置启动SprintBoot项目
    rust特性
    DataFrame窗口函数操作
    PostMan 之 Mock 接口测试
    【Opencv实战】识别水果的软件叫什么?一款超好用的识别软件分享,一秒鉴定(真是活~久~见~啊)
    Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (四)
    软件测试13年从业经验的前辈,总结的5条测试就业建议....
    【GlobalMapper精品教程】029:栅格重分类案例详解
    pthread_mutex_t & pthread_cond_t 总结
  • 原文地址:https://blog.csdn.net/qq_24946843/article/details/133864693