Filtrando imagens com Web Audio API

Alguns experimentos com arrays de som e imagem

6 min readOct 10, 2017

--

Enquanto brincava com canvas e web audio api; lembrava das minhas aulas de Sinais e Sistemas e ouvia David Bowie eu criei alguns pedaços de código mostrando como filtros funcionam com músicas e imagens. Vamos ver:

Vamos criar um arquivo html com um elemento canvas. Você pode carregar uma imagem e colocar nele da seguinte forma:

imageData tem uma propriedade data que é um array tipado e se parece com:

[211, 118, 103, 255, 209, 116, 101, 255, 207, …]

Cada grupo de quatro valores corresponde a vermelho, verde, azul e alfa de cada pixel da imagem.

No caso dessa representação de rgb: um pixel preto é definido por [0, 0, 0, 255] enquanto um amarelo é [255, 255, 0, 255]. Se a imagem tem 400 x 300 (largura x altura) isso resulta em 120.000 pixels e o array data terá 480.000 valores.

Vamos usar a clássica imagem “Lena.jpg”

Quando plotamos os 200 primeiros valores (ou 50 pixels) é visível o quão rápida é a variação porque as cores (vermelho, verde e azul) são muito diferentes entre si em cada pixel (alfa, entretanto, é sempre 255). Vamos usar a excelente Chart.js para fazer os gráficos.

(1) primeiros 200 valores do array com vermelho, verde, azul e alfa (2) 150 primeiros valores do array quando removemos alfa

Como você pode ver, mesmo removendo alfa, existe uma variação considerável de pixel para pixel.

Vamos iterar o array data da imagem criando arrays separados para vermelho, verde, azul e alfa. Nós teremos quatro arrays diferentes com 160.000 valores cada (porque a imagem tem 400 x 400):

Primeiros 400 pixels (a primeira linha inteira) dos arrays vermelho, verde e azul

O gráfico com os arrays separados mostra como as cores são mais constantes ao longo da primeira linha com algumas mudanças bruscas de valores. Se você olhar a imagem mais perto pode perceber que existem objetos no fundo que são responsáveis por essas mudanças.

As barras no fundo são mais claras e causam a mudança busca de cor que vemos no gráfico por isso que vemos as subidas/descidas ali presentes

Mas esses gráficos são estáveis e não existem muitas mudanças. Vamos dar uma olhada na linha 200:

A image croppada perto da linha 200
Valores de vermelho, verde e azul dos arrays na linha 200 da imagem

Vamos chamar esse gráfico de “evidência 1” (porque notações comuns como “g1” são fáceis de esquecer, certo?). Você pode ver o código usado para gerá-los aqui.

Por que isso é importante?

Considerando que nós podemos expressar pixels da imagem como arrays nós veremos como visualizar/mudar áudio da mesma forma.

Vamos fazer esses arrays cantarem

Uma das coisas mais legais que se pode fazer com a web audio api é usar arrays para gerar som. Você pode usar sua equação favorita (todo mundo tem uma, não?), como sen(x) e ouvir como ela soa (talvez isso pareça meio poético demais, mas você realmente pode fazer isso).

Aqui uma função para criar um buffer e tocar o conteúdo:

Agora nós podemos usar playSignal para fazer uma pequena página sandbox para tocar os melhores hits no browser:

A função default na textarea é 0.5 * Math.sin(6.2831 * (200) * t). Que é um seno com frequência de 200 Hertz. A constante 6.2831 vem de 2 * π porque 2 * π * f é a frequência angular.

Você pode acessar essa sandbox aqui. Tome cuidado com os valores de amplitude (0.5 no caso) enquanto se diverte lá. Sons muito altos podem fazer mal para sua audição. Agora sabemos como obter arrays de dados de imagens em canvas e como usar web audio api para fazer barulho 🤘!

Mas e os filtros?

A web audio api tem alguns filtros disponíveis que podem ser usados para manipular áudio. No escopo desse artigo nós vamos dar uma olhada no passa-altas e passa-baixas. Os nomes são bem auto-explicativos, mas basicamente o passa-baixas atenua valores com frequência acima de um dado valor e o passa-altas vai fazer o mesmo com sinais de frequência abaixo de um valor. Para criar um filtro precisamos de algumas poucas linhas de código:

Para ilustrar, vamos criar um sinal com cuja frequência cresce linearmente

Math.sin(6.283 * (50 + 500 * t) * t)

É um seno cuja frequência é uma função linear (50 + 500 * t) em vez de uma constante (que era 200 Hz antes). Dê uma olhada no sinal e nas saídas dos filtros abaixo:

Sinal original com frequência variável
Resultado do filtro passa-baixas (em azul) comparado com o sinal original (em laranja)
Resultado do filtro passa-altas (em azul) comparado com o sinal original (em laranja)

Isso nos dá uma boa ideia de como filtros atenuam sinais de acordo com os valores de frequência. Se você quer ouvir como música é afetada aqui tem um pequeno exemplo. Ainda bem que músicas são mais complexas que o exemplo acima. Se plotarmos um pedaço de peels.mp3 que você pode encontrar em opsound.org nós vemos um caso mais real:

O sinal original está em laranja. Vamos dar uma olhada mais de perto para ver os efeitos dos filtros:

Uma amostra do sinal original

Primeiro, o passa-baixas:

Uma amostra da música origingal (em laranja) e o resultado do filtro passa-baixas (em azul)

Você pode ver como o filtro se opõe a mudanças abruptas e suaviza o sinal.

Veja o resultado do passa-altas:

Uma amostra da música original (em laranja) e o resultado do filtro passa-altas (em azul)

A parte de baixa frequência do sinal, responsável pela maior variação da amplitude foi totalmente removida no resultado! Olhando mais perto você pode ver como as altas frequências continuam lá:

Um imagem mais próxima do resultado do filtro passa-altas

Se nós sabemos como aplicar filtros a array de dados and sabemos como obter dados de uma imagem no canvas nós podemos usar isso como a entrada de um filtro. Vamos usar o gráfico vermelho da imagem “evidência 1” como entrada:

Gráfico vermelho da linha 200 da imagem lena.jpg (em vermelho) e a saída do filtro passa-baixas (em azul)

Então se filtrarmos as 3 cores com um passa-faixas numa frequência de corte de 1000 Hz e então usar os arrays para recriar uma imagem em outro canvas temos a imagem abaixo. Ela parece borrada porque todas as transições de cores foram suavizadas!

Imagem original (esquerda), resultado do filtro passa-baixas (direita)

Usando um filtro passa-altas com uma frequência de corte de 4000 Hz nós vamos produzir o seguinte:

Gráfico vermelho da linha 200 da imagem lena.jpg (em vermelho) e a saída do filtro passa-altas(em azul)

O filtro removerá as frequências baixas mantendo as mudanças abruptas. Então vai manter os contornos:

Imagem original (esquerda), resultado do filtro passa-altas (direita)

Este não é o exato resultado de filtros construídos para fazer as mesmas operações com imagens mas espero ter inspirado você a brincar com essas fantásticas APIs. Você pode ver este grande experimento do meu amigo Davidson Fellipe com diversas coisas legais com processamento de imagens.

Aqui o experimento final e o repositório com o código.

--

--

Web developer, gif sommelier, once called “weird webby wizard”