Nesta série, dividida em 2 partes, iremos construir uma aplicação completa onde será possível fazer o upload de uma imagem e aplicar diferentes filtros de uma maneira fácil e rápida.
Na primeira parte iremos utilizar as técnicas de manipulação para desenvolver os filtros que serão aplicados às imagens, tudo isso utilizando Python e OpenCV.
Atualização: na parte 2 construiremos uma aplicação utilizando o Streamlit onde o usuário poderá realizar o upload de uma imagem e selecionar o filtro que deseja aplicar.
OpenCV
O OpenCV é uma biblioteca open-source de visão computacional, multiplataforma e otimizada para aplicações em tempo real.
Com o OpenCV é possível desde criar imagens do zero até realizar diferentes tipos de manipulações em imagens existentes - redimensionar, escurecer, borrar, aumentar a nitidez, dar efeitos de movimento, aplicar máscaras, etc. - de uma maneira simples e rápida.
Em nossos exemplos utilizamos o Google Colab que já vem com o OpenCV instalado. No entanto, para conseguir realizar os exemplos utilizando seu editor de preferência, será necessário primeiro instalar o opencv-python
.
pip install opencv-python
E importar a biblioteca
import cv2
Aplicando filtros
Em visão computacional, é muito comum precisarmos aplicar filtros a imagens, seja para reduzir ruídos ou para evidenciar alguma característica específica.
Para atingirmos esse efeito utilizamos uma operação chamada de convolução. A convolução consiste em "passar" uma matriz (filtro) através dos pixels de uma imagem. Como resultado dessa operação, teremos uma nova imagem com o efeito desejado (embaçar, deixar mais nítida etc.).
Nesse artigo iremos focar, nas transformações de efeito nas imagens, tais como manipular o brilho - deixando a imagem mais clara ou escura -, aplicar um efeito de embaçado (blurring), melhorar a nitidez (sharpening).
Alterando brilho
A primeira transformação, e a mais simples, que iremos realizar será aumentar/diminuir o brilho de uma imagem. Para isso iremos criar um "filtro" com as mesmas dimensões da imagem alvo.
# utilizando o ones do numpy para criar o filtro
filter_1 = np.ones(reduced_image.shape, dtype=np.uint8) * 110
Nosso filter_1
nada mais é que uma matriz com o mesmo tamanho da imagem composta de valores numéricos = 110
. Como o filtro tem o mesmo tamanho da imagem, podemos aumentar o brilho somando os valores do filtro a cada pixel da imagem.
# clarear
sum = cv2.add(reduced_image, filter_1)
# exibir a imagem
# no python
#cv2.imshow(sum)
# no google colab.
cv2_imshow(sum)
Conseguimos o efeito contrário se realizarmos a operação de subtração
# escurecer
sub = cv2.subtract(reduced_image, filter_1)
# exibir a imagem
# no python
#cv2.imshow(sub)
# no google colab.
cv2_imshow(sub)

Embaçando (Blur)
O segundo filtro (kernel) que utilizaremos como exemplo é o blur e suas variações - gaussian blur e motion blur - esse filtro utiliza as operações de convolução ao aplicar uma matriz sobre a imagem.
# criando o kernel
kernel_blur = np.ones((3, 3), np.float32) / 9
# aplicando o filtro
blurred = cv2.filter2D(reduced_image, -1, kernel_blur)
# mostranto a imagem com filtro
# no python
#cv2.imshow(blurred)
# no google colab
cv2_imshow(blurred)
Nesse exemplo, criamos uma matriz 3x3 com valores 1/3
e aplicamos sobre a imagem utilizando o comando filter2D
do OpenCV. Quanto menores forem os valores mais borrada a imagem ficará.
Por ser um filtro amplamente utilizado, o OpenCV já possui um método para aplicar o filtro Gaussian Blur de maneira bem simples:
# utilizando o GaussianBlur, que já é implementado no OpenCV
gaussian_blurred = cv2.GaussianBlur(reduced_image, (5, 5), 0)
# visualizando a imagem
# no python
# cv2.imshow(gaussian_blurred)
# no colab
cv2_imshow(gaussian_blurred)
Para aplicar o Motion Blur iremos, primeiro criar uma matriz 15x15 preenchida com zeros, em seguida iremos preencher com o valor 1 todas as colunas da sétima linha dessa matriz, por fim dividimos todos os valores por 15 e aplicamos sobre nossa imagem:
# implementando o filtro
kernel_motion_blur = np.zeros((15,15))
kernel_motion_blur[7, :] = np.ones(15)
kernel_motion_blur = kernel_motion_blur / 15
# aplicando o filtro
motion_blurred = cv2.filter2D(reduced_image, -1, kernel_motion_blur)
# plotando a imagem
# no python
#cv2.imshow(motion_blurred)
# no colab
cv2_imshow(motion_blurred)
Os resultados podem ser vistos na imagem abaixo:

Sharpening (afiando a imagem)
O objetivo do filtro de sharpening é melhorar a nitidez da imagem, normalmente esse filtro é usando quando se quer destacar os limites (edges) da imagem. Existem diversas maneiras de realizar esse filtro, o mais comum é utilizar uma matriz 3x3
com um centro positivo 9
e os demais pontos com valor -1
.
Utilizamos novamente o comando filter2D
para aplicar nosso filtro sobre a imagem.
# criando o filtro de sharpening
kernel_sharpening_1 = np.array([[-1, -1, -1],
[-1, 9, -1],
[-1, -1, -1]])
# implementando o filtro
sharpened = cv2.filter2D(reduced_image, -1, kernel_sharpening_1)
# mostrando a imagem
# no python
# cv2.imshow(sharpened)
# no colab
cv2_imshow(sharpened)
Podemos ver o resultado na imagem abaixo:

Conclusão
Chegamos ao fim da parte 1 dessa série. Nos concentramos nos principais conceitos e comandos básicos do OpenCV, que servirão de base para o desenvolvimento da nossa aplicação utilizando o Streamlit.
Por ser uma introdução, os filtros aqui demonstrados não são os únicos nem os melhores para todos os casos possíveis, apesar de serem os mais utilizados para a maioria dos problemas simples.
Podemos encontrar diversos outros filtros na literatura que serão mais indicados para casos específicos.
Mais detalhes sobre as implementações dos filtros e outras funções do OpenCV podem ser vistas aqui.