Manipulação de Imagens com Python e OpenCV - parte 2
Dando sequência na série de manipulação de imagens com Python e OpenCV, dessa vez vamos aplicar os conceitos descritos na parte 1 para construir uma aplicação utilizando, além de Python e OpenCV, o Streamlit.

Dando sequência a esta série de manipulação de imagens com Python e OpenCV, dessa vez vamos aplicar os conceitos descritos na parte 1 para construir uma aplicação utilizando, além de Python e OpenCV, o Streamlit.
Nota: nesse artigo iremos nos concentrar na utilização do Streamlit e como podemos utilizá-lo para aplicar os conceitos da primeira parte desta série. Portanto não iremos nos preocupar, com a arquitetura do software.
Streamlit
O Streamlit é uma biblioteca Python que nos permite transformar scripts de dados em aplicações web de maneira fácil e rápida. Para utilizá-lo precisamos apenas instalar e importar em nosso script.
Desenvolvimento da aplicação
Como não iremos utilizar o Google Colab dessa vez, precisamos, antes de iniciarmos o desenvolvimento da nossa aplicação, instalar as dependências que iremos utilizar.
pip install streamlit opencv-python numpy
Com as dependências instaladas, já podemos dar inicio ao desenvolvimento da aplicação. Primeiro criamos um arquivo chamado main.py
e nele vamos importar as bibliotecas necessárias:
import streamlit as st
import numpy as np
import cv2
from PIL import Image, ImageEnhance
Com os pacotes importados iremos criar nossa função principal main()
que executará nosso código exibindo o título da página e da barra lateral utilizando o streamlit
:
def main():
st.title("Aplicação de Filtros em Imagens")
st.sidebar.title("Escolha o filtro")
if __name__ == '__main__':
main()
O if
é uma função de segurança que só executa a função main
se o script for invocado intencionalmente.
Para iniciarmos nosso servidor streamlit
utilizamos o comando:
streamlit run main.py
Por padrão o streamlit estará disponível pelo endereço http://localhost:8051
Nessa altura você deve ter uma tela semelhante a essa:

É uma tela simples mas suficiente para entendermos como o streamlit funciona, na primeira linha de nosso script, definimos o titulo da página principal com o comando st.title("Aplicação de Filtros em Imagens")
e, logo em seguida, definimos também o título da sidebar st.sidebar.title("Escolha o filtro")
.
Podemos perceber, portanto que, todo conteúdo que queremos alocar na sidebar deverá ser precedido de st.sidebar
. A maioria dos componentes que estão disponíveis para a página principal, tem sua versão sidebar. Mais detalhes podem ser vistos na documentação.
Em seguida iremos adicionar um componente para fazer o upload de uma imagem:
image_file = st.file_uploader("Carregue uma foto e aplique um filtro no menu lateral", type=['jpg', 'jpeg', 'png'])
if image_file:
user_image = Image.open(image_file)
st.sidebar.text("Imagem Original")
st.sidebar.image(user_image, width=150)
else:
user_image = Image.open('empty.jpg')
Nesse trecho, inserimos um componente de upload de arquivos st.file_uploader
e indicamos seu label
e quais os formatos aceitos.
Em seguida verificamos se o arquivo foi enviado. Em caso positivo, carregamos a imagem utilizando o Pillow (PIL) Image.open(image_file)
, precisamos carregar a imagem dessa forma (e não utilizando o OpenCV diretamente) para que o streamlit
consiga utilizá-la corretamente.
Com a imagem carregada mostramos o texto "Imagem Original" e uma miniatura da imagem carregada na sidebar st.sidebar.text("Imagem Original")
e st.sidebar.image(user_image, width=150)
.
Para finalizar, caso a imagem não tenha sido carregada exibimos uma imagem estática user_image = Image.open("empty.jpg")
.
Com a imagem carregada podemos começar aplicando nossos filtros.
Para este exemplo optamos por criar um novo arquivo filters.py
onde escreveremos nossa classe que terá os métodos necessários para a aplicação dos filtros:
# importar pacotes
import cv2
import numpy as np
from PIL import ImageEnhance
# definição do nome dos filtros
FILTER_NAMES = {
'Desenho': 'sketch'
}
# definição do tamanho padrão de saída
OUTPUT_WIDTH = 500
class Filters:
def __init__(self, st, original_image):
self.st = st
self.original_image = original_image
self.selected_filter = st.sidebar.radio("Filtros", [key for key in FILTER_NAMES.keys()]
def __call__(self, width=OUTPUT_WIDTH):
run = getattr(self, FILTER_NAMES.get(self.selected_filter))
result_image = run()
self.st.image(result_image, width=width)
def grayscale(self):
converted_image = np.array(self.original_image)
gray_image = cv2.cvtColor(converted_image, cv2.COLOR_RGB2GRAY)
return gray_image
Explicando o que fazemos em cada bloco. Primeiro importamos os pacotes e definimos algumas constantes. A constante FILTER_NAMES
é um dicionário que tem o nome do filtro (que será exibido na tela) e o nome da função correspondente na classe.
A primeira função da nossa classe será invocada quando a classe for instanciada e irá receber o objeto do streamlit e a imagem que foi enviada. Ainda como parte da inicialização da classe também criamos a lista de filtros disponíveis na sidebar como botões do tipo radio
, também estamos armazenando a opção de filtro selecionado na variável self.selected_filter
.
A segunda função que criamos é responsável por chamar o filtro selecionado a partir da variável definida anteriormente. Iremos carregar a imagem resultante de uma das funções diretamente na página utilizando o streamlit self.st.image(result_image, width=width)
.
Por fim nossa última função contém a execução do filtro (grayscale). Nessa função primeiramente convertemos a imagem carregada em um array do numpy np.array(self.original_image)
, em seguida utilizamos o OpenCV para convertê-la para escala de cinza cv2.cvtColor(converted_image, cv2.COLOR_RGB2GRAY)
.
Atenção! Utilizamos cv2.COLOR_RGB2GRAY
nesse caso pois nossa imagem foi carregada pelo Pillow, e não pelo OpenCV.
Após a conversão, retornamos a imagem para que seja exibida na tela.
Agora em nosso main.py
precisamos importar e instanciar nossa classe para utilizarmos os filtros.
# importar a classe
from filters import Filters
...
# instanciar a classe
filter = Filters(st, user_image)
# executar a classe (chama __call__)
filter()
Como todas as funções estão encapsuladas em nossa classe. Após instanciada, precisamos apenas executá-la como se fosse uma função.
Conclusão
Nesse exemplo mostramos como é simples utilizar o Streamlit para transformar scripts ou notebooks em aplicações web prontas para serem disponibilizadas.
Esse e os demais filtros podem ser conferidos no repositório do projeto disponível neste link.
Você pode conferir uma demo da aplicação nesse link.