knitr::opts_chunk$set( collapse = TRUE, comment = "#>" )
Na área de reconhecimento automático de voz, uma das primeiras etapas está no processo de extração de características dos sinais de voz, ou seja, identificar os componentes do sinal de áudio que são bons para identificar o conteúdo linguístico. E uma dessas técnicas de reconhecimento de voz está o Mel-Frequency Cepstral Coefficients (MFCCs), a qual foi introduzida na década de 1980 por Davis e Mermelstein e tem sido considerada o estado da arte até o momemento [1].
Os MFCCs são comumente obtidos através dos seguintes passos:
A operação do MFCC foi implementado para a tarefa 2 da disciplina de Fundamentos de Computação Gráfica (FCG), a linguagem de programação escolhida foi o R. O código encontra-se disponível no github.
devtools
contido no CRAN executando o seguinte comando no console do R: install.packages("devtools")
.install.packages('ggplot2')
).`install.packages('tuneR')
).devtools::install_github("JessicaSousa/MFCC")
no console do R.Após efetuar a instalação do pacote, para usá-lo basta utilizar a seguinte função library(MFCC)
. Com o comando lsf("package:MFCC")
é possível obter uma lista contendo o nome das funções implementadas, conforme ilustrado abaixo:
library(MFCC) ls("package:MFCC")
Para saber informações sobre alguma função, pode ser utilizado help('nome da função')
ou ?nome da função
.
Alguns exemplos do uso do pacote são ilustrados a seguir:
library(MFCC) #carregar pacote do MFCC library(ggplot2) #biblioteca para gráficos #Obter arquivo de áudio exemplo sound.data <- MFCC::sound.data #Com o pacote tuneR, pode-se carregar um arquivo do disco da seguinte forma: (descomentar abaixo) #sound.data <- tuneR::readWave('audio.wav', from = 0, to = 3.5, units = "seconds") sound <- sound.data@left #valores do arquivo de áudio sample.rate <- sound.data@samp.rate #sample rate do arquivo de áudio #Exibir arquivo de áudio sound.time <- 0:(length(sound)-1)/sample.rate #tempo em segundos #criar estrutura contendo o x e y do gráfico data.raw <- data.frame(x = sound.time, y = sound) #Exibir gráfico p <- ggplot(data.raw, aes(x, y)) + geom_line() + xlab("Tempo (s)") + ylab("Amplitude") #+
plotly::ggplotly(p)
Inicialmente, são definidos alguns parâmetros arbitrários que são necessários para o cálculo das MFCCs, são eles:
fft.npoints
), geralmente é realizada uma FFT de 512 pontos.freq.lower
e freq.lower
, respectivamente)num.filters
), consiste em um conjunto de valores de 20-40.A seguir são inicializadas as respectivas variáveis.
fft.npoints <- 512 #números de pontos considerados para o cálculo da fft #help(nfft) #para mais informações freq.lower <- 0 #frequência mínima em hertz considerada freq.upper <- sample.rate / 2 #frequência máxima em hertz considerada num.filters <- 40 #número filtros considerados para o filterbank
Antes de aplicar os passos da MFCCs, é aplicado um filtro de pré-ênfase sobre o sinal, com o objetivo de amplificar as altas frequências. A aplicação desse filtro pode ser obtida a partir da seguinte equação:
$$y(t) = x(t) - \alpha x(t-1)$$
Esse filtro foi implementado sobre o nome apply_preemphasis
, os valores padrões de $\alpha$ são 0,95 ou 0,97. A seguir é ilustrado o resultado da aplicação do filtro sobre o sinal de som de entrada.
emphasized_signal <- apply_preemphasis(sound, 0.97) #criar estrutura contendo o x e y do gráfico data.emphasized <- data.frame(x = sound.time, y = emphasized_signal) #Exibição p <- ggplot(data.emphasized, aes(x, y)) + geom_line() + xlab("Tempo (s)") + ylab("Amplitude")
plotly::ggplotly(p)
As etapas do algoritmo dos MFCCs são descritas juntamente com as chamadas de funções implementadas neste pacote:
r
frames <- frame_the_signal(emphasized_signal, sample.rate)#1.Dividir o sinal em short frames.
frames <- apply_window_hamming(frames) #aplicar a função de hamming para cada frame
r
power.frames <- compute_power_spectrum(frames, n = fft.npoints)
r
fbanks <- compute_mel_filterbanks(freq.lower,freq.upper, num.filters, fft.npoints, sample.rate)
#Para calcular a energia do filter bank, multiplica-se cada filter bank com seus power spectrum.
filter.banks <- power.frames %*% t(fbanks)
r
#substituir os zeros para evitar problemas com log
filter.banks[filter.banks == 0] <- .Machine$double.eps
filter.banks <- 20 * log10(filter.banks)
r
#Para cada FilterBank é aplicada a operação de Discrete Cosine Transform (DCT).
mfcc <- t(apply(filter.banks, 1, function(x) apply_dct(x)))
r
mfcc <- mfcc[, 2:13]
fft.npoints <- 512 #números de pontos considerados para o cálculo da fft #help(nfft) #para mais informações freq.lower <- 0 #frequência mínima em hertz considerada freq.upper <- sample.rate / 2 #frequência máxima em hertz considerada num.filters <- 40 #número filtros considerados para o filterbank #1.Dividir o sinal em short frames. frames <- frame_the_signal(emphasized_signal, sample.rate) frames <- apply_window_hamming(frames) #aplicar a função de hamming para cada frame #2.Para cada quadro, calcular o power spectrum power.frames <- compute_power_spectrum(frames, n = fft.npoints) #3.Aplicar o mel filterbank aos power spectra, somar a energia em cada filtro fbanks <- compute_mel_filterbanks(freq.lower,freq.upper, num.filters, fft.npoints, sample.rate) #Para calcular a energia do filter bank, multiplica-se cada filter bank com seus power spectrum. filter.banks <- power.frames %*% t(fbanks) #4. Obter o logaritmo de todas as filterbank energies filter.banks[filter.banks == 0] <- .Machine$double.eps #substituir os zeros para evitar problemas com log filter.banks <- 20 * log10(filter.banks) #5. Obter a DCT do log das filterbank energies. mfcc <- t(apply(filter.banks, 1, function(x) apply_dct(x))) #6. Manter os coeficientes DCT 2-13, descartar o resto.. mfcc <- mfcc[, 2:13]
A visualização dos filterbanks pode ser vista com o seguinte trecho de código:
#Organizar dado para melhor visualização x <- seq(from = freq.lower, to = freq.upper, length.out = ncol(fbanks)) %>% rep(num.filters) y <- t(fbanks) y %<>% as.data.frame() %>% tidyr::gather() data <- data.frame(x = x, values = y$value, filters = y$key) #Exibir espectograma p <- ggplot(data, aes(x, values, colour = filters)) + geom_line() + xlab("Frequência") + ylab("Amplitude") + theme(legend.position="none") + scale_x_continuous(expand = c(0, 0)) + scale_y_continuous(expand = c(0, 0))
plotly::ggplotly(p)
O espectograma da aplicação do Filter Bank ao Power Spectrum é ilustrado a seguir:
#Organizar dado para melhor visualização fbanks.spec <- reshape2::melt(filter.banks) fbanks.spec$Var1 <- fbanks.spec$Var1 / 100 fbanks.spec$Var2 <- fbanks.spec$Var2 / 10 #Exibir espectograma p <- ggplot(fbanks.spec, aes(Var1,Var2)) + geom_raster(aes(fill = value)) + scale_fill_gradientn(colours = rainbow(10)) + xlab("Tempo (s)") + ylab("Frequência (kHz)") + ggtitle("Espectograma do sinal") + scale_x_continuous(expand = c(0, 0)) + scale_y_continuous(expand = c(0, 0))
plotly::ggplotly(p)
Para realce de sinal pode ser aplicado o sinusoidal liftering aos MFCCs, o qual é descrito pela seguinte equação:
$$\hat{MFCC_i} = 1 + (\frac{w_i D}{2})\sin(\frac{π n}{D})$$
E está implementado sobre a seguinte função apply_lifter
:
#Aplicar o sinusoidal liftering aos MFCCs mfcc.lift <- apply_lifter(mfcc) #Organizar dado para melhor visualização mfccs.spec <- reshape2::melt(mfcc.lift) mfccs.spec$Var1 <- mfccs.spec$Var1 / 100 #Espectograma do MFCCs p <- ggplot(mfccs.spec, aes(Var1,Var2, fill=value)) + geom_raster(aes(fill = value)) + scale_fill_gradientn(colours = rainbow(10)) + xlab("Tempo (s)") + ylab("Coeficientes das MFCCs") + ggtitle("MFCCs") + scale_x_continuous(expand = c(0, 0)) + scale_y_continuous(expand = c(0, 0))
plotly::ggplotly(p)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.