python pyaudio对音频进行端点检测,检测出说话区间

news2024/12/29 11:28:00

python pyaudio对音频进行端点检测,检测出说话区间

主要采用过零率和语音能量来进行检测,并设置双阈值。
代码如下:

# -*- coding: utf-8 -*-
import wave
import os
import matplotlib.pyplot as plt
import numpy as np


# 判断是否变号
def sgn(data):
    if data >= 0:
        return 1
    else:
        return 0


# 计算每一帧的能量,设定每 256 个采样点为一帧,一帧就是一个语音块
def calEnergy(wave_data):
    energy = []
    sum = 0
    for i in range(len(wave_data)):
        sum = sum + (int(wave_data[i]) * int(wave_data[i]))
        if (i + 1) % 256 == 0:
            energy.append(sum)
            sum = 0
        elif i == len(wave_data) - 1:
            energy.append(sum)

    return energy


# 计算过零率
def calZeroCrossingRate(wave_data):
    zeroCrossingRate = []
    sum = 0
    for i in range(len(wave_data)):
        # 判断当前索引 i 是否是 256 的倍数,为了避免从音频数据的开头和上一帧最后一个采样点计算过零率
        if i % 256 == 0:
            continue
        sum = sum + np.abs(sgn(wave_data[i]) - sgn(wave_data[i - 1]))
        if (i + 1) % 256 == 0:
            zeroCrossingRate.append(float(sum) / 255)
            sum = 0
        elif i == len(wave_data) - 1:
            zeroCrossingRate.append(float(sum) / 255)

    return zeroCrossingRate


"""
当使用双门限法进行语音端点检测时,可以按照以下步骤实现:
计算语音信号的短时能量和过零率。可以使用算法或库函数来计算短时能量和过零率。
初始化参数。设定较高和较低能量阈值、过零率阈值等参数。
根据能量阈值进行初步检测。遍历短时能量序列,当能量超过较高能量阈值时,标记为起始点;
当能量低于较低能量阈值时,标记为结束点。
根据过零率阈值进行进一步检测。遍历起始点和结束点之间的时间窗口,在时间窗口内计算过零率,
并判断是否超过过零率阈值。若超过阈值,说明该点为语音信号的起始或结束点;
若未超过阈值,说明该点为语音信号的过渡点。
根据检测到的起始和结束点,得到语音信号的分段结果。
"""


# 利用短时能量,短时过零率,使用双门限法进行端点检测
def endPointDetect(wave_data, energy, zeroCrossingRate):
    sum = 0
    energyAverage = 0
    # 短时能量平均数
    for en in energy:
        sum = sum + en
    energyAverage = sum / len(energy)
    #    print(energyAverage)

    # 首先计算语音前一段的静音部分的能量均值(前5帧)
    sum = 0
    for en in energy[:5]:
        sum = sum + en
    ML = sum / 5
    # 将能量均值的1/4作为MH
    MH = energyAverage / 4  # 较高的能量阈值
    # 将静音部分的能量均值和MH的平均数的1/4作为ML。
    ML = (ML + MH) / 4  # 较低的能量阈值

    # 计算前5帧的过零率
    sum = 0
    for zcr in zeroCrossingRate[:5]:
        sum = float(sum) + zcr
    Zs = sum / 5  # 过零率阈值

    A = []
    B = []
    C = []

    # 首先利用较大能量阈值 MH 进行初步检测
    flag = 0
    for i in range(len(energy)):
        if len(A) == 0 and flag == 0 and energy[i] > MH:
            A.append(i)
            flag = 1

        # 如果当前点与上一个浊音的结束点之间的距离大于阈值(这里设为21),则将当前点设为新的浊音的起始点
        elif flag == 0 and energy[i] > MH and i - 21 > A[len(A) - 1]:
            A.append(i)
            flag = 1

        # 如果当前能量超过 MH,但当前点与上一个浊音的结束点之间的距离小于等于阈值 21,则将上一个浊音的结束点舍弃
        elif flag == 0 and energy[i] > MH and i - 21 <= A[len(A) - 1]:
            A = A[:len(A) - 1]
            flag = 1

        # 拿到结束点
        if flag == 1 and energy[i] < MH:
            A.append(i)
            flag = 0

    print("较高能量阈值,计算后的浊音A:" + str(A))

    # 根据较低能量阈值,在基础 A 上增加一段语音
    for j in range(len(A)):
        i = A[j]
        if j % 2 == 1:  # 奇数下标为结束点
            while i < len(energy) and energy[i] > ML:
                i = i + 1
            B.append(i)
        else:  # 偶数下标为起始点
            while i > 0 and energy[i] > ML:
                i = i - 1
            B.append(i)

    print("较低能量阈值,增加一段语言B:" + str(B))

    # 利用过零率进行最后一步检测,过零率高表示活跃语音
    print(B)
    for j in range(len(B)):
        i = B[j]
        if j % 2 == 1:  # 奇数下标为结束点
            while i < len(zeroCrossingRate) and zeroCrossingRate[i] >= 3 * Zs:
                i = i + 1
            C.append(i)
        else:  # 偶数下标为起始点
            while i > 0 and zeroCrossingRate[i] >= 3 * Zs:
                i = i - 1
            C.append(i)

    print("过零率阈值,最终语音分段C:" + str(C))
    return C


f = wave.open("./output.wav", "rb")
# getparams() 一次性返回所有的WAV文件的格式信息
params = f.getparams()
# nframes 采样点数目 帧数
nchannels, sampwidth, framerate, nframes = params[:4]
# readframes() 按照采样点读取数据
str_data = f.readframes(nframes)  # str_data 是二进制字符串

# 以上可以直接写成 str_data = f.readframes(f.getnframes())

# 转成二字节数组形式(每个采样点占两个字节)
wave_data = np.fromstring(str_data, dtype=np.short)
f.close()

# 转成双声道
wave_data.shape = -1, 2
wave_data = wave_data.T

time = np.arange(0, nframes) * (1.0 / framerate)  # 每个采样点对应的时间,单位是 s
waveDate = wave_data[0]  # 提取一个声道的数据
print("采样点数目:" + str(len(waveDate)))  # 输出一个声道应为采样点数目
print("采样率:" + str(framerate))
plt.plot(waveDate)
plt.ylabel("voiceprint")
plt.xlabel("nframes")
plt.show()

minvalue = min(waveDate)
maxvalue = max(waveDate)
energy = calEnergy(waveDate)  # 每 256 为一帧,energy 为语音块的能量
plt.subplot(211)
plt.plot(energy)
plt.ylabel("energy")
plt.xlabel("frame")

# 保存 energy
with open("./energy/1_en.txt", "w") as f:
    for en in energy:
        f.write(str(en) + "\n")

zeroCrossingRate = calZeroCrossingRate(waveDate)
plt.subplot(212)
plt.plot(zeroCrossingRate)  # 同样是以帧为单位的过零率
plt.ylabel("zeroCrossingRate")
plt.xlabel("frame")
plt.show()

# 保存过零率
with open("./zero/1_zero.txt", "w") as f:
    for zcr in zeroCrossingRate:
        f.write(str(zcr) + "\n")

# 双门限法进行端点检测
N = endPointDetect(waveDate, energy, zeroCrossingRate)

plt.plot(waveDate)
for i in range(0,len(N),2):
    print(i)

    x = [N[i] * 256, N[i] * 256]  # * 256 放大到原来的采样点上
    x1 = [N[i+1] * 256, N[i+1] * 256]
    y = [minvalue, maxvalue]
    plt.plot(x, y, "-g")
    plt.plot(x1, y, "-r")
    plt.plot()
    plt.ylabel("voiceprint")
    plt.xlabel("nframes")
    
plt.show()

# 输出为 pcm 格式
with open("./corpus/1.pcm", "wb") as f:
    i = 0
    while i < len(N):
        for num in waveDate[N[i] * 256: N[i + 1] * 256]:
            f.write(num)
        i = i + 2

运行结果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1283903.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

差分基准站

差分基准站&#xff0c;又称参考接收机&#xff0c;是一种固定式卫星接收机&#xff0c;用于提高卫星定位精度。 差分基准站的作用是提供已知位置和准确的位置信号&#xff0c;以纠正其他移动定位终端接收器接收到的卫星信号中的误差。 卫星定位信号会受到多种因素的影响&#…

Redis缓存——Spring Cache入门学习

Spring Cache 介绍 Spring Cache 是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;只需要简单地加一个注解&#xff0c;就能实现缓存功能。 Spring Cache 提供了一层抽象&#xff0c;底层可以切换不同的缓存实现&#xff0c;例如&#xff1a; EHCacheCaffeineR…

JAVA-作业7-画一个笑脸

要求如题 代码如下&#xff1a; SmileFace01: import java.awt.Color; import java.awt.Graphics;import javax.swing.JPanel;public class SmileFace01 extends JPanel {Overrideprotected void paintComponent(Graphics g) {super.paintComponent(g);int width getWidth(…

【c】有序数列插入一个整数

#include<stdio.h> int main() {int n;scanf("%d",&n);int arr[n1];for(int i0;i<n;i){scanf("%d",&arr[i]);}int a;scanf("%d",&a);arr[n]a;for(int j0;j<n;j){if(arr[j]>arr[n])//交换元素位置{int temparr[j];arr…

【广州华锐互动】风电场检修VR情景模拟提供接近真实的实操体验

风电场检修VR情景模拟系统由广州华锐互动开发&#xff0c;这是一种新兴的培训方式&#xff0c;它通过虚拟现实技术将风力发电场全范围进行1:1仿真建模还原&#xff0c;模拟监视风力发电场各种运行工况下的运行参数和指标&#xff0c;同时可进行升压站系统的巡视&#xff0c;倒闸…

JavaWeb 分页查询

由于html不能直接从域当中直接拿数据 所以我们引入了jsp文件 数据存在了requets域当中 如果数据量很大,不可能把所有数据全部在页面展示: 数据全部在页面展示缺点: SQL执行时间过长 用户查看数据,滚动滚动条,用户体验不高 在实际开发中,分页查询&#xff0c; 实现: sql语句…

什么是Overlay网络?Overlay网络与Underlay网络有什么区别?

你们好&#xff0c;我的网工朋友。 在传统历史阶段&#xff0c;数据中心的网络是以三层架构&#xff08;核心、汇聚、接入&#xff09;为基本标准。 但是随着技术的发展&#xff0c;不同的厂家有不同的组建方式&#xff0c;比如说在核心层、汇聚层和接入层增加虚拟化技术。 …

Linux Namespace技术

对应到容器技术&#xff0c;为了隔离不同类型的资源&#xff0c;Linux 内核里面实现了以下几种不同类型的 namespace。 UTS&#xff0c;对应的宏为 CLONE_NEWUTS&#xff0c;表示不同的 namespace 可以配置不同的 hostname。User&#xff0c;对应的宏为 CLONE_NEWUSER&#xf…

Vmware17虚拟机安装windows10系统

不要去什么系统之家之类的下载镜像&#xff0c;会不好安装&#xff0c;镜像被魔改过了&#xff0c;适合真实物理机上的系统在PE里安装系统&#xff0c;建议下载原版系统ISO文件 安装vmware17pro 下载地址https://dwangshuo.jb51.net/202211/tools/VMwareplayer17_855676.rar 解…

【源码解析】聊聊线程池 实现原理与源码深度解析(二)

AbstractExecutorService 上一篇文章中&#xff0c;主要介绍了AbstractExecutorService的线程执行的核心流程&#xff0c;execute() 这个方法显然是没有返回执行任务的结果&#xff0c;如果我们需要获取任务执行的结果&#xff0c;怎么办&#xff1f; Callable 就是一个可以获…

【yolov8】与yolov5的区别及改进详解

图像识别技术在物联网、智能监控等领域广泛应用。而深度学习中的目标检测技术&#xff0c;能够帮助我们对图像中的目标进行识别&#xff0c;进而实现自动化控制。目前&#xff0c;Yolov8和Yolov5是目标检测领域热门的模型。 yolo目标检测原理yolov5详解yolov8yolov8结构图Conv模…

RK3588+MCU机器人控制器解决方案

1 产品简介 XMP04A 是一款信迈科技基于 RK3588 设计的高性能、低功耗的边缘计算设备&#xff0c; 内置 NPU 算力可达 6.0TOPSINT8&#xff0c;以及具备强大的视频编解码能力&#xff0c;最高可支持 32 路 1080P30fps 解码和 16 路 1080P30fps 编码 &#xff0c;支持 4K12…

数据库管理-第120期 初探Halo数据库(202301201)

数据库管理-第120期 初探Halo数据库&#xff08;202301201&#xff09; 12月份正好也是第120期&#xff0c;新的一篇文章&#xff0c;尝试一条新的路线。其实吧&#xff0c;Halo&#xff08;羲和&#xff09;这个数据库我较早时间就听说过&#xff08;早于今年DTCC&#xff0c…

SpringBoot+SSM项目实战 苍穹外卖(3)

继续上一节的内容&#xff0c;本节完成菜品管理功能&#xff0c;包括公共字段自动填充、新增菜品、菜品分页查询、删除菜品、修改菜品。 目录 公共字段自动填充新增菜品文件上传实现新增菜品实现 useGeneratedKeys 菜品分页查询删除菜品修改菜品根据id查询菜品实现修改菜品实现…

【Go】Go语言基础内容

变量声明&#xff1a; 变量声明&#xff1a;在Go中&#xff0c;变量必须先声明然后再使用。声明变量使用 var 关键字&#xff0c;后面跟着变量名和类型&#xff0c;如下所示&#xff1a; var age int这行代码声明了一个名为 age 的整数变量。 变量初始化&#xff1a;您可以在声…

JFrog----SBOM清单包含哪些:软件透明度的关键

文章目录 SBOM清单包含哪些&#xff1a;软件透明度的关键引言SBOM清单的重要性SBOM清单包含的核心内容SBOM的创建和管理结论 软件物料清单&#xff08;SBOM&#xff09;是一个在软件供应链安全中越来越重要的组成部分。它基本上是一份清单&#xff0c;详细列出了在特定软件产品…

ENVI植被指数阈值法

植被指数阈值法提取纯净像元 首先用ENVI打开无人机遥感影像 1. 假彩色显示 打开数据管理工具&#xff0c;无人机的4波段为红边波段 2. 波段计算 打开band math&#xff0c;输入 float(b1-b2)/(b1b2) 选择对应波段 3. 阈值筛选 阈值按经验值选的0.7&#xff0c;ndvi…

从零开始实现神经网络(二)_CNN卷积神经网络

参考文章: 介绍卷积神经网络1 介绍卷积神经网络2 在过去的几年里&#xff0c;关于卷积神经网络&#xff08;CNN&#xff09;的讨论很多&#xff0c;特别是因为它们彻底改变了计算机视觉领域。在这篇文章中&#xff0c;我们将建立在神经网络的基本背景知识的基础上&#xff0c;探…

[GPT-1]论文实现:Improving Language Understanding by Generative Pre-Training

Efficient Graph-Based Image Segmentation 一、完整代码二、论文解读2.1 GPT架构2.2 GPT的训练方式Unsupervised pre_trainingSupervised fine_training 三、过程实现3.1 导包3.2 数据处理3.3 模型构建3.4 模型配置 四、整体总结 论文&#xff1a;Improving Language Understa…

android studio 打开flutter项目 出现 dart sdk is not configured

android studio 版本 flutter版本 解决方式 1 点击Open Dart setting 2 打勾Enable Dart support for the project 3 Dart SDK path 选择flutter/bin/cache/dart-sdk 4 打勾Enable Dart support for the following modules