特征融合之openSMILE提取音频特征与生成文件的处理

如果以下内容对你有所帮助,可以点个赞关注一波哈!

下载安装openSMILE

openSMILE的主要版本包括Windows(32位)和Linux(64位)以及Android的二进制文件ARM(自2.1以来,android-10)。

对于Windows的朋友来说,大概意思就是你得再安一个linux系统(除非你的系统是Windows XP)。

这边建议在虚拟机中安linux系统。那具体怎么安装,这个别的地方应该挺多资源可以参考的,在这就不过多描述了。

如果已经安好linux系统了,就先去http://opensmile.audeering.com/下载opensmile。

Linux系统发行包包含静态链接的主要可执行文件SMILExtract,示例配置文件在config/文件夹中,可视化脚本 以及其他比如建模任务在scrrpts/文件夹,其他资源在src/文件夹。

下载完之后,可以参考另外一位博主的博客,翻译得特别好。https://blog.csdn.net/lccever/article/details/78649538

如果在这个过程中遇到什么问题,可以在底下评论或者私信我,我会尽快回复!

提取过程

在这里先介绍下opensmile自带的配置文件:

emobase2010.conf 情感特征:1582维特征向量
emobase_live4_batch_single.conf 现场情感识别:988维特征向量
IS09_emotion.conf 情感挑战:384维特征向量
emo_large.conf :大集合6552维向量
IS12_speaker_trait.conf 数字兼容特性
liveProsodyAcf.conf 语音韵律特征的音调和响度

(不同版本的opensmile特征数量稍微有些不同)

所以只需要根据自身的需求,更换下面命令中的conf文件名即可,注意音频文件必须是无损的wav格式。

SMILExtract -C config/IS09_emotion.conf -I wav_samples/opensmile.wav -O speech01.energy.csv

那在正式提取特征之前,我们还需要将我们需要提取的音频切割成多个短音频(如果后续有特征融合的需求的话),短音频的时长具体多少可根据自身需求进行更改,我这里是切割成了多个100ms(0.1s)的短音频。(很多情况下其实是按句子来切割的!

具体代码如下:

import os
import wave
from pydub import AudioSegment
import contextlib


def get_wav_time(wav_path):
    '''
    获取音频文件时长

    :param wav_path: 音频路径
    :return: 音频时长 (单位秒)
    '''
    with contextlib.closing(wave.open(wav_path, 'r')) as f:
        frames = f.getnframes()
    rate = f.getframerate()
    duration = frames / float(rate)
    return duration


def get_ms_part_wav(main_wav_path, start_time, end_time, part_wav_path):
    '''
    音频切片,获取部分音频 单位是毫秒级别

    :param main_wav_path: 原音频文件路径
    :param start_time:  截取的开始时间
    :param end_time:  截取的结束时间
    :param part_wav_path:  截取后的音频路径
    :return:
    '''
    start_time = int(start_time)
    end_time = int(end_time)

    sound = AudioSegment.from_mp3(main_wav_path)
    word = sound[start_time:end_time]

    word.export(part_wav_path, format="wav")


if __name__ == '__main__':

    path = r'E:/123/'  # 原音频目录
    path_segment = r'E:/234/'  # 切割后的音频目录

    print('开始切割音频!')
    time_segment = 100  # 切割后短音频的时长
    for root, dir, files in os.walk(path):
        for i in range(len(files)):
            audio = root + files[i]
            time_all = int(get_wav_time(audio) * 1000)  # 转换成毫秒
            start_time = 0  # 从第0ms开始切割
            index = 1  # 切割后的序号名,从序号1开始命令
            while start_time <= time_all - time_segment:
                # print(str(i)+ ': ' + str(index))
                end_time = start_time + time_segment
                aduio_segment = path_segment + files[i][:-4] + '_' + str(index) + '.wav'
                get_ms_part_wav(audio, start_time, end_time, aduio_segment)
                start_time += time_segment
                index += 1
            # 接下来这两行是为了将最终能够不足time_segment时长的音频剪下来
            aduio_segment = path_segment + files[i][:-4] + '_' + str(index) + '.wav'
            get_ms_part_wav(audio, start_time, time_all, aduio_segment)

    print('音频切割完成!')

注释是不是超级详细哈哈!

切割完音频之后,接下来就是对切割好的多个短音频进行处理了。

试想一下,如果一个一个进行提取,如果原音频是时长30s,那么切割后的音频就有300个了,更何况我们往往需要处理大量得到音频。

所以这个时候就需要我们进行批处理啦!(其实也就是用了一下os这个大家都很熟悉的模块而已哈哈)

话不多说,上代码:

"""

在执行该代码之前,你可以选择将这份代码放在opensmile的初目录下。
或者是执行os.system('cd path')  # 这里的path就是你opensmile的初目录

"""

import os

path = './audio27_segment/'  # 待处理的音频路径
count = 0
for root,dir,files in os.walk(path):
    for i in range(len(files)):
        print(files[i])
        print(count)
        # path_remake(files[i])
        try:
            os.system('SMILExtract -C config/IS09_emotion.conf -I ' + 'audio27_segment/' + files[i] + ' -O ' + 'audio27_segment_fea/' + files[i][:-4] + '.csv')
        except:
            count += 1
print(count)  # 出错次数,正常情况都是不会出错的。

生成文件的处理

当执行完以上操作之后,你也就基本完成了你的工作。

剩下最后一步,也就是将你真正需要用到的音频特征从csv文件中拿出来。

先介绍下这个生成的csv文件,这里以配置文件IS09_emotion.conf为例。

生成的csv文件中,第4~387行为特征名称,第392行一共386个元素,第一个元素为‘unknow’;最后一个元素为?;中间384个元素对应上面384个特征。

那如何将我们需要的这384个特征提取出来呢。

代码如下:

import os
import re
frome natsort import natsorted

# 先对文本进行操作
path2 = r'E:/audio27_segment_fea/'  # 待处理的短音频的路径
arr = [[] for i in range(45)]  # 45你可以随便改,只要大于你原长音频的数量就可以了!
index_num2 = []
for root, dir, files in os.walk(path2):
    num = len(files)
    files = natsorted(files) 
    for i in range(len(files)):
        with open(root + files[i], 'r') as f:
            content = f.readlines()
            fea = content[-1]
            fea1 = re.findall(r'\d+\.?\d*e?[-+]?\d+', fea)
            fea1 = list(map(float, fea1))
            index = int(re.findall(r'^(.*?)_', files[i])[0])
            if index not in index_num2:
                index_num2.append(index)
            arr[index].append(fea1)

f_A1 = []
for i in arr:
    if i != []:
        f_A1.append(i)

# 除去有问题的音频特征(特征数为0)(一般都是原本长音频截取的最后一个短音频)
for index1, value1 in enumerate(f_A1):
    for index2, value2 in enumerate(value1):
        if len(value2) != 384:
            print('holly shit!')
            print(index1,end=': ')
            print(index2,end=' ')
            print(len(value2))
            value1.pop(index2)
            break

# 这里的f_A1 就是我们要的啦

这里给的代码很详细哈哈。

结束语

由于博主能力有限,博文中提及的信息,也难免会有疏漏之处。希望发现疏漏的朋友能热心指出其中的错误,以便下次修改时能以一个更完美更严谨的样子,呈现在大家面前。同时如果有更好的方法也请不吝赐教。

如果有什么相关的问题,也可以关注评论留下自己的问题,我会尽量及时发送!

然后如果这些内容对你有所帮助的话,麻烦点赞或者评论告诉我可以吗(这样我更新博客的速度才会越来越快!!!)

你可能感兴趣的:(音频特征提取,特征融合,自然语言处理,深度学习,python)