Processamento de Imagem — Image Filtering

Fabricio Bizotto
6 min readMar 2, 2021

--

Experimentos com a biblioteca OpenCV para suavizar, realçar e detectar bordas em uma imagem.

Na computação visual, técnicas de filtragem podem ser usadas para realçar ou suavizar imagens, bem como detectar bordas em uma imagem. Como forma de gerar experimentos, duas técnicas de filtragem em imagens foram aplicadas, utilizando a biblioteca OpenCV e a linguagem de programação Python.

A primeira técnica chama-se Image Blurring. Essa técnica desfoca a imagem, convolvendo a imagem com um kernel de filtro low-pass. É útil para remover ruído, removendo o conteúdo de alta frequência da imagem. Como resultado deste tipo de filtro, as bordas da imagem são borradas.

Uma vantagem desta primeira técnica é a redução de ruídos na imagem, contudo, a desvantagem disso é a redução de detalhes da imagem e o tempo de processamento.

A segunda técnica chama-se Canny Edge Detection. Essa técnica utiliza um algoritmo de multi-estágio que detecta uma ampla gama de bordas na imagem, realizando quatro etapas:

  1. Reduzir ruídos: remove ruídos na imagem com um filtro gaussiano de 5x5;
  2. Encontrar o gradiente de intensidade da imagem: A imagem suavizada é então filtrada com um kernel Sobel nas direções horizontal e vertical;
  3. Supressão não-máxima: Depois de obter a magnitude e a direção do gradiente, uma varredura completa da imagem é feita para remover quaisquer pixels indesejados que possam não constituir a borda. Para isso, a cada pixel, é verificado se ele possui o maior valor em sua vizinhança na direção do gradiente;
  4. Limiar de Hysteresis: Este estágio decide quais arestas são realmente arestas e quais não são. Quaisquer arestas com gradiente de intensidade maior que maxVal são certamente arestas e aquelas abaixo de minVal não são arestas, portanto, são descartadas;

Como vantagens desta segunda técnica podemos destacar a presença do filtro gaussiano, que remove possíveis ruídos da imagem. É adaptável a vários ambientes. A principal desvantagem de usar o detector de bordas Canny é que ele consome muito tempo devido à sua computação complexa.

A partir do exposto acima, vamos fazer alguns experimentos. Na primeira etapa, aplicamos: filtro pela média, filtro gaussiano e o filtro pela mediana. Já na segunda etapa, aplicamos o filtro de detecção de bordas.

Para a aplicação de cada filtro, o algoritmo criado vai carregar uma imagem e aplicar algum ruído randomicamente. Como resultado, tanto a imagem original quanto a imagem com o respectivo filtro serão renderizadas.

O algoritmo está dividido em duas partes. Na primeira parte (Anexo I), uma classe foi criada para aplicar os filtros desejados. Na segunda parte (Anexo II), uma lista de imagens é carregada e os filtros então são aplicados. Para visualizar mais alguns resultados da aplicação dos filtros, veja o Anexo III deste documento. O código-fonte completo pode ser acessado na plataforma Google Colab, clicando aqui.

Etapa 1

1. Filtro pela Média (Averaging)

Essa técnica simplesmente pega a média de todos os pixels sob a área do kernel e substitui o elemento central por essa média.

########## Filtro pela Média — Averaging ##########def to_averaging(self, image=None, kernel=(5,5)):
image = self._image if image is None else image
return cv.blur(image, kernel)

Resultado:

2. Filtro Gaussiano (Gaussian Filtering)

A filtragem gaussiana é altamente eficaz na remoção de ruído gaussiano da imagem.

########## Filtro Gaussiano — Gaussian Filtering ##########
def to_gaussian(self, image=None, kernel=(5,5), border_type=0):
image = self._image if image is None else image
return cv.GaussianBlur(image, kernel, border_type)

Resultado:

3. Mediana (Median Filtering)

Essa técnica calcula a mediana de todos os pixels, a partir do kernel definido. O pixel central é substituído por este valor mediano. É altamente eficaz na remoção de ruído de “sal e pimenta”. Uma coisa interessante a notar é que, nos filtros Gaussiano e de média, o valor filtrado para o elemento central pode ser um valor que pode não existir na imagem original. No entanto, este não é o caso da filtragem de mediana, uma vez que o elemento central é sempre substituído por algum valor de pixel na imagem. Isso reduz o ruído de forma eficaz. O tamanho do kernel deve ser um número inteiro ímpar positivo.

########## Filtro pela Mediana — Median Filtering ##########
def to_median(self, image=None, kernel_size=5):
image = self._image if image is None else image
return cv.medianBlur(image, kernel_size)

Resultado:

Etapa 2

Filtro de Borda — Canny Edge Detection

A biblioteca OpenCV também possui uma função para detecção de bordas. O primeiro parâmetro da função é a imagem, já o segundo e o terceiro parâmetro correspondem ao mínimo (minVal) e ao máximo (maxVal) valor respectivamente. As bordas com gradiente de intensidade maior que maxVal são certamente bordas e aquelas abaixo de minVal não são bordas, portanto, são descartadas.

# Filtro de Borda Canny — Canny Edge Detection #
def to_canny(self, image=None, min_value=125, max_value=175):
image = self._image if image is None else image
return cv.Canny(image, min_value, max_value)

Esse filtro foi aplicado de duas maneiras. No primeiro experimento, o filtro foi aplicado na imagem original (com ruídos). No segundo experimento, o filtro foi aplicado na imagem resultante da aplicação do filtro da mediana (Median Filtering). Os resultados podem ser vistos nas imagens abaixo:

Resultado:

Anexo I — Classe Filtro

import cv2 as cv
from google.colab.patches import cv2_imshow as imshow
from google.colab import drive
from matplotlib import pyplot as plt
drive.mount('/content/drive')
# Classe para aplicar Filtros na imagem
class Filtro:
_image = None

def __init__(self, path, gray=True):
self.gray = gray
self._image = cv.imread(path)
if gray:
self._image = cv.cvtColor(self._image, cv.COLOR_BGR2GRAY)
else:
self._image = cv.cvtColor(self._image, cv.COLOR_BGR2RGB)

########## Filtro pela Média - Averaging ##########
def to_averaging(self, image=None, kernel=(5,5)):
# return cv.boxFilter(self._image, 3, kernel)
image = self._image if image is None else image
return cv.blur(image, kernel)
########## Filtro Gaussiano - Gaussian Filtering ##########
def to_gaussian(self, image=None, kernel=(5,5), border_type=0):
image = self._image if image is None else image
return cv.GaussianBlur(image, kernel, border_type)
########## Filtro pela Mediana - Median Filtering ##########
def to_median(self, image=None, kernel_size=5):
image = self._image if image is None else image
return cv.medianBlur(image, kernel_size)
# ########## Filtro de Borda Canny - Canny Edge Detection ##########
def to_canny(self, image=None, min_value=125, max_value=175):
image = self._image if image is None else image
return cv.Canny(image, min_value, max_value)

def add_noise(self):
# Dimensões da imagem
if self.gray:
row, col = self._image.shape
else:
row, col, _ = self._image.shape[::1]
# Escolhendo randomicamente alguns pixels
# para aplicar ruídos na imagem
number_of_pixels = random.randint(300, 10000)
for i in range(number_of_pixels):
y_coord=random.randint(0, row - 1) # Coordenada Y
x_coord=random.randint(0, col - 1) # Coordenada X
self._image[y_coord][x_coord] = random.randint(0,255) # Cor randômica

# Plotar a imagen original e a imagem filtrada, lado a lado
def show(self, title, filtered_image, figsize=(15,15)):
cmap = plt.get_cmap('gray') if self.gray else None
plt.figure(figsize=figsize)
plt.subplot(121),plt.imshow(self._image, cmap=cmap),plt.title('Original')
plt.xticks([]),plt.yticks([])
plt.subplot(122),plt.imshow(filtered_image, cmap=plt.get_cmap('gray')),plt.title(title)
plt.xticks([]),plt.yticks([])

Anexo II — Execução

import os
import random
# Pasta com as imagens
default_folder = '/content/drive/MyDrive/COLAB/'
# Lendo os arquivos de imagem
images = os.listdir(default_folder)
# Processando cada uma das imagens e imprimindo os comparativos
for filename in images:
# randomico para grayscale
gray = random.randint(0,1) == 1
filtro = Filtro(path=default_folder + filename, gray=gray)
filtro.add_noise() #Adicionando ruídos na imagem
averaging = filtro.to_averaging()
gaussian = filtro.to_gaussian()
median = filtro.to_median()
canny_edge_original = filtro.to_canny()
canny_edge_median = filtro.to_canny(image=median,min_value=150, max_value=300)
filtro.show('Filtro pela Média', averaging)
filtro.show('Filtro Gaussiano', gaussian)
filtro.show('Filtro pela Mediana', median)
filtro.show('Filtro Canny', canny_edge_original)
filtro.show('Filtro Canny da mediana', canny_edge_median)

Considerações Finais

Essa foi uma pequena demonstração de como usar a biblioteca OpenCV para suavizar, realçar e detectar bordas em uma imagem. O experimento demonstrou que existem algumas vantagens e desvantagens na utilização de cada um dos filtros. A escolha do filtro vai depender do tipo de imagem e do seu objetivo.

O filtro pela média (Averaging) é o mais simples. Consiste em varrer a imagem e substituir o valor do pixel pela média da vizinhança. No entanto, o filtro gaussiano (Gaussian Filtering) é o principal filtro utilizado para remover ruídos na imagem. Já o filtro da mediana (Median Filtering) deve ser utilizado para remover ruídos do tipo “sal e pimenta”.

Para detecção de borda, o filtro Canny (Canny Edge Detection) é o mais comumente utilizado, bem como o mais eficiente para identificar bordas finas.

O códifo-fonte pode ser executado no Google Colab, clicando aqui.

--

--

No responses yet