【语音识别】语音端点检测及Python实现

系统 1610 0

【语音识别】语音端点检测及Python实现

  • 一、语音信号的分帧处理
  • 二、端点检测方法
    • 2.1、短时能量
    • 2.2、短时过零率
  • 三、Python实现

从接收的语音信号中准确检测出人声开始和结束的端点是进行语音识别的前提。本博文介绍基于短时过零率和短时能量的基本语音端点检测方法及Python实现。如图所示为语音信号,红色方框内为人声:
【语音识别】语音端点检测及Python实现_第1张图片

一、语音信号的分帧处理

语音信号是时序信号,其具有长时随机性和短时平稳性。长时随机性指语音信号随时间变化是一个随机过程,短时平稳性指在短时间内其特性基本不变,因为人说话是肌肉具有惯性,从一个状态到另一个状态不可能瞬时完成。语音通常在10-30ms之间相对平稳,因此语音信号处理的第一步基本都是对语音信号进行分帧处理,帧长度一般取10-30ms。
语音信号的分帧处理通常采用滑动窗的方式,窗口可以采用直角窗、Hamming窗等。窗口长度决定每一帧信号中包含原始语音信号中信息的数量,窗口每次的滑动距离等于窗口长度时,每一帧信息没有重叠,当窗口滑动距离小于窗口长度时帧信息有重合。本博文采用直角窗进行语音信号的分帧处理:

直角窗:
h ( n ) = { 1 , 0 ≤ n ≤ N − 1 0 , o t h e r {\rm{h}}(n) = \left\{ {\begin{matrix} {1, 0\le n \le N - 1}\\ {0,{\rm{other}}} \end{matrix}} \right. h ( n ) = { 1 , 0 n N 1 0 , o t h e r

二、端点检测方法

端点检测是指找出人声开始和结束的端点。利用人声信号短时特性与非人声信号短时特性的差异可以有效地找出人声开始和结束的端点,本博文介绍短时能量和短时过零率结合进行端点检测的方法。

2.1、短时能量

第n帧信号的短时平均能量定义为:
E n = ∑ m = n − N + 1 n [ x ( m ) w ( n − m ) ] 2 {E_n} = \sum\limits_{m = n - N + 1}^n {{{\left[ {x\left( m \right)w\left( {n - m} \right)} \right]}^2}} E n = m = n N + 1 n [ x ( m ) w ( n m ) ] 2
包含人声信号的帧的短时平均能量大于非人声信号的帧。

2.2、短时过零率

过零信号指通过零值,相邻取样值改变符号即过零,过零数是样本改变符号的数量。
第n帧信号的平均短时过零数为:
Z n = ∑ m = n − N + 1 n ∣ s g n [ x ( m ) ] − s g n [ x ( m − 1 ) ] ∣ w ( n − m ) {Z_n} = \sum\limits_{m = n - N + 1}^n {\left| {{\mathop{\rm sgn}} \left[ {x\left( m \right)} \right] - {\mathop{\rm sgn}} \left[ {x\left( {m - 1} \right)} \right]} \right|w\left( {n - m} \right)} Z n = m = n N + 1 n s g n [ x ( m ) ] s g n [ x ( m 1 ) ] w ( n m )

w ( n ) = { 1 / ( 2 N ) , 0 ≤ n ≤ N − 1 0 , o t h e r w\left( n \right) = \left\{ {\begin{matrix} {1/\left( {2N} \right),0 \le n \le N - 1}\\ {0,other} \end{matrix}} \right. w ( n ) = { 1 / ( 2 N ) , 0 n N 1 0 , o t h e r

三、Python实现

            
              
                import
              
               wave

              
                import
              
               numpy as np

              
                import
              
               matplotlib
              
                .
              
              pyplot as plt

def 
              
                read
              
              
                (
              
              data_path
              
                )
              
              
                :
              
              
                ''
              
              '读取语音信号
    
              
                ''
              
              '
    wavepath 
              
                =
              
               data_path
    f 
              
                =
              
               wave
              
                .
              
              
                open
              
              
                (
              
              wavepath
              
                ,
              
              
                'rb'
              
              
                )
              
              
    params 
              
                =
              
               f
              
                .
              
              
                getparams
              
              
                (
              
              
                )
              
              
    nchannels
              
                ,
              
              sampwidth
              
                ,
              
              framerate
              
                ,
              
              nframes 
              
                =
              
               params
              
                [
              
              
                :
              
              
                4
              
              
                ]
              
               #声道数、量化位数、采样频率、采样点数
    str_data 
              
                =
              
               f
              
                .
              
              
                readframes
              
              
                (
              
              nframes
              
                )
              
               #读取音频,字符串格式
    f
              
                .
              
              
                close
              
              
                (
              
              
                )
              
              
    wavedata 
              
                =
              
               np
              
                .
              
              
                fromstring
              
              
                (
              
              str_data
              
                ,
              
              dtype 
              
                =
              
               np
              
                .
              
              
                short
              
              
                )
              
               #将字符串转化为浮点型数据
    wavedata 
              
                =
              
               wavedata 
              
                *
              
              
                1.0
              
              
                /
              
              
                (
              
              
                max
              
              
                (
              
              
                abs
              
              
                (
              
              wavedata
              
                )
              
              
                )
              
              
                )
              
               #wave幅值归一化
    
              
                return
              
               wavedata
              
                ,
              
              nframes
              
                ,
              
              framerate

def 
              
                plot
              
              
                (
              
              data
              
                ,
              
              time
              
                )
              
              
                :
              
              
    plt
              
                .
              
              
                plot
              
              
                (
              
              time
              
                ,
              
              data
              
                )
              
              
    plt
              
                .
              
              
                grid
              
              
                (
              
              
                'on'
              
              
                )
              
              
    plt
              
                .
              
              
                show
              
              
                (
              
              
                )
              
              

def 
              
                enframe
              
              
                (
              
              data
              
                ,
              
              win
              
                ,
              
              inc
              
                )
              
              
                :
              
              
                ''
              
              '对语音数据进行分帧处理
    input
              
                :
              
              
                data
              
              
                (
              
              一维array
              
                )
              
              
                :
              
              语音信号
          
              
                wlen
              
              
                (
              
              
                int
              
              
                )
              
              
                :
              
              滑动窗长
          
              
                inc
              
              
                (
              
              
                int
              
              
                )
              
              
                :
              
              窗口每次移动的长度
    output
              
                :
              
              
                f
              
              
                (
              
              二维array
              
                )
              
              每次滑动窗内的数据组成的二维array
    
              
                ''
              
              '
    nx 
              
                =
              
              
                len
              
              
                (
              
              data
              
                )
              
               #语音信号的长度
    
              
                try
              
              
                :
              
              
        nwin 
              
                =
              
              
                len
              
              
                (
              
              win
              
                )
              
              
    except Exception as err
              
                :
              
              
        nwin 
              
                =
              
              
                1
              
              
                if
              
               nwin 
              
                ==
              
              
                1
              
              
                :
              
              
        wlen 
              
                =
              
               win
    
              
                else
              
              
                :
              
              
        wlen 
              
                =
              
               nwin
    nf 
              
                =
              
              
                int
              
              
                (
              
              np
              
                .
              
              
                fix
              
              
                (
              
              
                (
              
              nx 
              
                -
              
               wlen
              
                )
              
              
                /
              
               inc
              
                )
              
              
                +
              
              
                1
              
              
                )
              
               #窗口移动的次数
    f 
              
                =
              
               np
              
                .
              
              
                zeros
              
              
                (
              
              
                (
              
              nf
              
                ,
              
              wlen
              
                )
              
              
                )
              
                #初始化二维数组
    indf 
              
                =
              
              
                [
              
              inc 
              
                *
              
               j 
              
                for
              
               j in 
              
                range
              
              
                (
              
              nf
              
                )
              
              
                ]
              
              
    indf 
              
                =
              
              
                (
              
              np
              
                .
              
              
                mat
              
              
                (
              
              indf
              
                )
              
              
                )
              
              
                .
              
              T
    inds 
              
                =
              
               np
              
                .
              
              
                mat
              
              
                (
              
              
                range
              
              
                (
              
              wlen
              
                )
              
              
                )
              
              
    indf_tile 
              
                =
              
               np
              
                .
              
              
                tile
              
              
                (
              
              indf
              
                ,
              
              wlen
              
                )
              
              
    inds_tile 
              
                =
              
               np
              
                .
              
              
                tile
              
              
                (
              
              inds
              
                ,
              
              
                (
              
              nf
              
                ,
              
              
                1
              
              
                )
              
              
                )
              
              
    mix_tile 
              
                =
              
               indf_tile 
              
                +
              
               inds_tile
    f 
              
                =
              
               np
              
                .
              
              
                zeros
              
              
                (
              
              
                (
              
              nf
              
                ,
              
              wlen
              
                )
              
              
                )
              
              
                for
              
               i in 
              
                range
              
              
                (
              
              nf
              
                )
              
              
                :
              
              
                for
              
               j in 
              
                range
              
              
                (
              
              wlen
              
                )
              
              
                :
              
              
            f
              
                [
              
              i
              
                ,
              
              j
              
                ]
              
              
                =
              
               data
              
                [
              
              mix_tile
              
                [
              
              i
              
                ,
              
              j
              
                ]
              
              
                ]
              
              
                return
              
               f

def 
              
                point_check
              
              
                (
              
              wavedata
              
                ,
              
              win
              
                ,
              
              inc
              
                )
              
              
                :
              
              
                ''
              
              '语音信号端点检测
    input
              
                :
              
              
                wavedata
              
              
                (
              
              一维array
              
                )
              
              :原始语音信号
    output
              
                :
              
              
                StartPoint
              
              
                (
              
              
                int
              
              
                )
              
              
                :
              
              起始端点
           
              
                EndPoint
              
              
                (
              
              
                int
              
              
                )
              
              
                :
              
              终止端点
    
              
                ''
              
              '
    #
              
                1.
              
              计算短时过零率
    FrameTemp1 
              
                =
              
              
                enframe
              
              
                (
              
              wavedata
              
                [
              
              
                0
              
              
                :
              
              
                -
              
              
                1
              
              
                ]
              
              
                ,
              
              win
              
                ,
              
              inc
              
                )
              
              
    FrameTemp2 
              
                =
              
              
                enframe
              
              
                (
              
              wavedata
              
                [
              
              
                1
              
              
                :
              
              
                ]
              
              
                ,
              
              win
              
                ,
              
              inc
              
                )
              
              
    signs 
              
                =
              
               np
              
                .
              
              
                sign
              
              
                (
              
              np
              
                .
              
              
                multiply
              
              
                (
              
              FrameTemp1
              
                ,
              
              FrameTemp2
              
                )
              
              
                )
              
               # 计算每一位与其相邻的数据是否异号,异号则过零
    signs 
              
                =
              
              
                list
              
              
                (
              
              
                map
              
              
                (
              
              lambda x
              
                :
              
              
                [
              
              
                [
              
              i
              
                ,
              
              
                0
              
              
                ]
              
              
                [
              
              i
              
                >
              
              
                0
              
              
                ]
              
              
                for
              
               i in x
              
                ]
              
              
                ,
              
              signs
              
                )
              
              
                )
              
              
    signs 
              
                =
              
              
                list
              
              
                (
              
              
                map
              
              
                (
              
              lambda x
              
                :
              
              
                [
              
              
                [
              
              i
              
                ,
              
              
                1
              
              
                ]
              
              
                [
              
              i
              
                <
              
              
                0
              
              
                ]
              
              
                for
              
               i in x
              
                ]
              
              
                ,
              
               signs
              
                )
              
              
                )
              
              
    diffs 
              
                =
              
               np
              
                .
              
              
                sign
              
              
                (
              
              
                abs
              
              
                (
              
              FrameTemp1 
              
                -
              
               FrameTemp2
              
                )
              
              
                -
              
              
                0.01
              
              
                )
              
              
    diffs 
              
                =
              
              
                list
              
              
                (
              
              
                map
              
              
                (
              
              lambda x
              
                :
              
              
                [
              
              
                [
              
              i
              
                ,
              
              
                0
              
              
                ]
              
              
                [
              
              i
              
                <
              
              
                0
              
              
                ]
              
              
                for
              
               i in x
              
                ]
              
              
                ,
              
               diffs
              
                )
              
              
                )
              
              
    zcr 
              
                =
              
              
                list
              
              
                (
              
              
                (
              
              np
              
                .
              
              
                multiply
              
              
                (
              
              signs
              
                ,
              
               diffs
              
                )
              
              
                )
              
              
                .
              
              
                sum
              
              
                (
              
              axis 
              
                =
              
              
                1
              
              
                )
              
              
                )
              
              
    #
              
                2.
              
              计算短时能量
    amp 
              
                =
              
              
                list
              
              
                (
              
              
                (
              
              
                abs
              
              
                (
              
              
                enframe
              
              
                (
              
              wavedata
              
                ,
              
              win
              
                ,
              
              inc
              
                )
              
              
                )
              
              
                )
              
              
                .
              
              
                sum
              
              
                (
              
              axis 
              
                =
              
              
                1
              
              
                )
              
              
                )
              
              
#    # 设置门限
#    
              
                print
              
              
                (
              
              
                '设置门限'
              
              
                )
              
              
    ZcrLow 
              
                =
              
              
                max
              
              
                (
              
              
                [
              
              
                round
              
              
                (
              
              np
              
                .
              
              
                mean
              
              
                (
              
              zcr
              
                )
              
              
                *
              
              
                0.1
              
              
                )
              
              
                ,
              
              
                3
              
              
                ]
              
              
                )
              
              #过零率低门限
    ZcrHigh 
              
                =
              
              
                max
              
              
                (
              
              
                [
              
              
                round
              
              
                (
              
              
                max
              
              
                (
              
              zcr
              
                )
              
              
                *
              
              
                0.1
              
              
                )
              
              
                ,
              
              
                5
              
              
                ]
              
              
                )
              
              #过零率高门限
    AmpLow 
              
                =
              
              
                min
              
              
                (
              
              
                [
              
              
                min
              
              
                (
              
              amp
              
                )
              
              
                *
              
              
                10
              
              
                ,
              
              np
              
                .
              
              
                mean
              
              
                (
              
              amp
              
                )
              
              
                *
              
              
                0.2
              
              
                ,
              
              
                max
              
              
                (
              
              amp
              
                )
              
              
                *
              
              
                0.1
              
              
                ]
              
              
                )
              
              #能量低门限
    AmpHigh 
              
                =
              
              
                max
              
              
                (
              
              
                [
              
              
                min
              
              
                (
              
              amp
              
                )
              
              
                *
              
              
                10
              
              
                ,
              
              np
              
                .
              
              
                mean
              
              
                (
              
              amp
              
                )
              
              
                *
              
              
                0.2
              
              
                ,
              
              
                max
              
              
                (
              
              amp
              
                )
              
              
                *
              
              
                0.1
              
              
                ]
              
              
                )
              
              #能量高门限
    # 端点检测
    MaxSilence 
              
                =
              
              
                8
              
               #最长语音间隙时间
    MinAudio 
              
                =
              
              
                16
              
               #最短语音时间
    Status 
              
                =
              
              
                0
              
               #状态
              
                0
              
              
                :
              
              静音段
              
                ,
              
              
                1
              
              
                :
              
              过渡段
              
                ,
              
              
                2
              
              
                :
              
              语音段
              
                ,
              
              
                3
              
              
                :
              
              结束段
    HoldTime 
              
                =
              
              
                0
              
               #语音持续时间
    SilenceTime 
              
                =
              
              
                0
              
               #语音间隙时间
    
              
                print
              
              
                (
              
              
                '开始端点检测'
              
              
                )
              
              
    StartPoint 
              
                =
              
              
                0
              
              
                for
              
               n in 
              
                range
              
              
                (
              
              
                len
              
              
                (
              
              zcr
              
                )
              
              
                )
              
              
                :
              
              
                if
              
               Status 
              
                ==
              
              
                0
              
               or Status 
              
                ==
              
              
                1
              
              
                :
              
              
                if
              
               amp
              
                [
              
              n
              
                ]
              
              
                >
              
               AmpHigh or zcr
              
                [
              
              n
              
                ]
              
              
                >
              
               ZcrHigh
              
                :
              
              
                StartPoint 
              
                =
              
               n 
              
                -
              
               HoldTime
                Status 
              
                =
              
              
                2
              
              
                HoldTime 
              
                =
              
               HoldTime 
              
                +
              
              
                1
              
              
                SilenceTime 
              
                =
              
              
                0
              
              
            elif amp
              
                [
              
              n
              
                ]
              
              
                >
              
               AmpLow or zcr
              
                [
              
              n
              
                ]
              
              
                >
              
               ZcrLow
              
                :
              
              
                Status 
              
                =
              
              
                1
              
              
                HoldTime 
              
                =
              
               HoldTime 
              
                +
              
              
                1
              
              
                else
              
              
                :
              
              
                Status 
              
                =
              
              
                0
              
              
                HoldTime 
              
                =
              
              
                0
              
              
        elif Status 
              
                ==
              
              
                2
              
              
                :
              
              
                if
              
               amp
              
                [
              
              n
              
                ]
              
              
                >
              
               AmpLow or zcr
              
                [
              
              n
              
                ]
              
              
                >
              
               ZcrLow
              
                :
              
              
                HoldTime 
              
                =
              
               HoldTime 
              
                +
              
              
                1
              
              
                else
              
              
                :
              
              
                SilenceTime 
              
                =
              
               SilenceTime 
              
                +
              
              
                1
              
              
                if
              
               SilenceTime 
              
                <
              
               MaxSilence
              
                :
              
              
                    HoldTime 
              
                =
              
               HoldTime 
              
                +
              
              
                1
              
              
                elif 
              
                (
              
              HoldTime 
              
                -
              
               SilenceTime
              
                )
              
              
                <
              
               MinAudio
              
                :
              
              
                    Status 
              
                =
              
              
                0
              
              
                    HoldTime 
              
                =
              
              
                0
              
              
                    SilenceTime 
              
                =
              
              
                0
              
              
                else
              
              
                :
              
              
                    Status 
              
                =
              
              
                3
              
              
        elif Status 
              
                ==
              
              
                3
              
              
                :
              
              
                break
              
              
                if
              
               Status 
              
                ==
              
              
                3
              
              
                :
              
              
                break
              
              
    HoldTime 
              
                =
              
               HoldTime 
              
                -
              
               SilenceTime
    EndPoint 
              
                =
              
               StartPoint 
              
                +
              
               HoldTime
    
              
                return
              
               StartPoint
              
                ,
              
              EndPoint
              
                ,
              
              FrameTemp1
   
    

              
                if
              
               __name__ 
              
                ==
              
              
                '__main__'
              
              
                :
              
              
    data_path 
              
                =
              
              
                'audio_data.wav'
              
              
    win 
              
                =
              
              
                240
              
              
    inc 
              
                =
              
              
                80
              
              
    wavedata
              
                ,
              
              nframes
              
                ,
              
              framerate 
              
                =
              
              
                read
              
              
                (
              
              data_path
              
                )
              
              
    time_list 
              
                =
              
               np
              
                .
              
              
                array
              
              
                (
              
              
                range
              
              
                (
              
              
                0
              
              
                ,
              
              nframes
              
                )
              
              
                )
              
              
                *
              
              
                (
              
              
                1.0
              
              
                /
              
               framerate
              
                )
              
              
                plot
              
              
                (
              
              wavedata
              
                ,
              
              time_list
              
                )
              
              
    StartPoint
              
                ,
              
              EndPoint
              
                ,
              
              FrameTemp 
              
                =
              
              
                point_check
              
              
                (
              
              wavedata
              
                ,
              
              win
              
                ,
              
              inc
              
                )
              
              
    checkdata
              
                ,
              
              Framecheck 
              
                =
              
              
                check_signal
              
              
                (
              
              StartPoint
              
                ,
              
              EndPoint
              
                ,
              
              FrameTemp
              
                ,
              
              win
              
                ,
              
              inc
              
                )
              
            
          

端点检测结果:

【语音识别】语音端点检测及Python实现_第2张图片


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论