Materiais de Aula – Parte 2

Processamento de Imagem e Visão Computacional • Prof. Me. William Tenório • 2026/2

Sobre esta página

Esta página reúne o material de apoio da segunda parte da disciplina, referente ao conteúdo trabalhado após a Prova 1. O material da primeira parte continua disponível na página Materiais de Aula.

Como na primeira parte, o conteúdo é apresentado principalmente na lousa, durante as aulas: esta página não substitui a aula, apenas reúne as imagens e os exemplos citados em sala para consulta posterior.

Detecção de Bordas

Uma borda é uma região da imagem onde a intensidade dos pixels muda de forma abrupta — normalmente o limite entre dois objetos, ou entre um objeto e o fundo. Detectar bordas é, portanto, procurar variações bruscas de intensidade na matriz de pixels.

Matematicamente, essa variação é medida pelo gradiente da imagem: a derivada da intensidade em relação a x (variação na horizontal) e em relação a y (variação na vertical). Onde o gradiente é alto, há uma transição forte — uma borda; onde ele é próximo de zero, a região é homogênea.

Painel com seis versões da mesma imagem em tons de cinza: original, bordas horizontais, bordas verticais, operador de Sobel, operador Laplaciano e bordas por Canny
Figura 10 – Comparação entre técnicas de detecção de bordas aplicadas à mesma imagem: bordas horizontais e verticais isoladas, o operador de Sobel (combinação das duas direções), o Laplaciano (segunda derivada) e o detector de Canny, que produz bordas finas e binarizadas.

Operador de Sobel

Painel com a foto colorida de uma flor de lótus, seu gradiente na direção X, seu gradiente na direção Y e o resultado final da detecção de bordas por Sobel
Figura 11 – Etapas do operador de Sobel: a partir da imagem original calcula-se o gradiente em X e o gradiente em Y separadamente; a combinação da magnitude dos dois produz o contorno final da flor.

Exemplo em Python: Sobel com OpenCV

Cálculo dos gradientes em X e em Y e da magnitude resultante, reproduzindo as etapas da Figura 11:

import cv2
import numpy as np
import matplotlib.pyplot as plt

# Carrega a imagem e converte para escala de cinza
imagem = cv2.imread("flor.jpg")
cinza = cv2.cvtColor(imagem, cv2.COLOR_BGR2GRAY)

# Suaviza antes de derivar, para não realçar o ruído como se fosse borda
cinza = cv2.GaussianBlur(cinza, (3, 3), 0)

# Gradiente em X e em Y, com kernel 3x3
# CV_64F preserva os valores negativos das derivadas
grad_x = cv2.Sobel(cinza, cv2.CV_64F, 1, 0, ksize=3)
grad_y = cv2.Sobel(cinza, cv2.CV_64F, 0, 1, ksize=3)

# Magnitude do gradiente: G = raiz(Gx² + Gy²)
magnitude = np.sqrt(grad_x**2 + grad_y**2)

# Converte de volta para a faixa de 0 a 255
grad_x = cv2.convertScaleAbs(grad_x)
grad_y = cv2.convertScaleAbs(grad_y)
magnitude = cv2.convertScaleAbs(magnitude)

# Exibe as etapas
plt.figure(figsize=(10, 8))

plt.subplot(2, 2, 1)
plt.imshow(cv2.cvtColor(imagem, cv2.COLOR_BGR2RGB))
plt.title("Imagem original")
plt.axis("off")

plt.subplot(2, 2, 2)
plt.imshow(grad_x, cmap="gray")
plt.title("Gradiente em X")
plt.axis("off")

plt.subplot(2, 2, 3)
plt.imshow(grad_y, cmap="gray")
plt.title("Gradiente em Y")
plt.axis("off")

plt.subplot(2, 2, 4)
plt.imshow(magnitude, cmap="gray")
plt.title("Sobel - detecção de bordas")
plt.axis("off")

plt.show()

Atenção ao tipo de dado. As derivadas produzem valores negativos — uma transição de claro para escuro tem gradiente negativo. Se o resultado for calculado como uint8, esses valores são cortados em zero e metade das bordas simplesmente desaparece. Por isso usamos cv2.CV_64F no cálculo e só depois convertemos com cv2.convertScaleAbs, que toma o valor absoluto e devolve a imagem para a faixa de 0 a 255.

O mesmo cálculo, escrito manualmente com a convolução pixel a pixel, para deixar explícito o que a função cv2.Sobel faz internamente:

import cv2
import numpy as np

# Kernels de Sobel
kernel_x = np.array([[-1, 0, 1],
                     [-2, 0, 2],
                     [-1, 0, 1]])

kernel_y = np.array([[-1, -2, -1],
                     [ 0,  0,  0],
                     [ 1,  2,  1]])

imagem = cv2.imread("flor.jpg", cv2.IMREAD_GRAYSCALE)

altura, largura = imagem.shape

# Zero-padding, para também processar os pixels da borda
com_borda = cv2.copyMakeBorder(imagem, 1, 1, 1, 1, cv2.BORDER_CONSTANT)

magnitude = np.zeros_like(imagem, dtype=np.float64)

for y in range(altura):
    for x in range(largura):
        # Janela 3x3 centrada no pixel atual
        janela = com_borda[y:y+3, x:x+3]

        # Convolução: soma dos produtos entre a janela e cada kernel
        gx = np.sum(janela * kernel_x)
        gy = np.sum(janela * kernel_y)

        magnitude[y, x] = np.sqrt(gx**2 + gy**2)

resultado = cv2.convertScaleAbs(magnitude)

cv2.imshow("Original", imagem)
cv2.imshow("Sobel", resultado)
cv2.waitKey(0)
cv2.destroyAllWindows()

Operações Morfológicas

Os filtros vistos até aqui (média, mediana, Gaussiano) e os detectores de borda alteram os valores dos pixels. As operações morfológicas trabalham de outra forma: elas modificam a forma e a estrutura dos objetos presentes na imagem — encolhendo, expandindo, separando ou unindo regiões.

Elemento Estruturante

Três elementos estruturantes desenhados como grades: quadrado 3x3 só com uns, cruz 3x3 com zeros nos cantos e disco 5x5 com zeros nos cantos, cada um com a origem central marcada por um círculo vermelho
Figura 12 – Formatos comuns de elemento estruturante. O tamanho e o formato de B influenciam diretamente o resultado: a cruz, por exemplo, não considera os vizinhos diagonais.

Nos exemplos a seguir usamos o caso mais simples: B quadrado 3x3 aplicado a uma imagem 5x5 que contém um quadrado branco 3x3 no centro.

Três grades 5x5: a imagem original com um quadrado 3x3 de uns no centro; a erosão, em que só o pixel central continua 1 e os oito ao redor aparecem em vermelho como removidos; e a dilatação, em que toda a grade fica com 1 e a borda externa aparece em azul como acrescentada
Figura 13 – Exemplo de referência da aula. A erosão deixa apenas o pixel central (em vermelho, os pixels removidos); a dilatação expande o quadrado uma posição em cada direção e preenche a matriz 5x5 (em azul, os pixels acrescentados).

Erosão

Grade 5x5 com o elemento estruturante 3x3 desenhado em verde centrado no pixel do meio, totalmente dentro do objeto; ao lado, o mesmo elemento em vermelho centrado no pixel (1,1), com parte sobre o fundo; e o resultado, em que só o pixel central fica 1
Figura 14 – Como a erosão decide cada pixel. Centrado em (2,2), B cabe inteiro no objeto e o pixel fica 1; centrado em (1,1), parte de B cai sobre o fundo e o pixel vira 0. Por isso só o centro sobrevive.
A palavra PIVC em branco sobre fundo preto e três erosões com elementos estruturantes de 5x5, 13x13 e 23x23; as letras ficam cada vez mais finas até restarem apenas fragmentos
Figura 15 – Efeito do tamanho do elemento estruturante: quanto maior B, mais intensa a erosão. Com B 23x23, as partes mais estreitas das letras desaparecem por completo.

Dilatação

Grade 7x7 com um quadrado 3x3 de uns no centro; o elemento estruturante em azul centrado em (1,1) toca o canto do objeto; em laranja, centrado em (0,0), não toca; o resultado mostra o objeto crescido para 5x5, com o anel novo em azul
Figura 16 – Como a dilatação decide cada pixel (em uma grade 7x7, para sobrar fundo ao redor). Centrado em (1,1), B toca o objeto e o pixel vira 1; centrado em (0,0), não toca e continua 0. O objeto cresce um pixel em cada direção.
A palavra PIVC original, erodida com letras mais finas e dilatada com letras mais grossas; abaixo, a erosão com a faixa removida destacada em vermelho no contorno das letras e a dilatação com a faixa acrescentada destacada em azul
Figura 17 – Erosão e dilatação aplicadas a uma imagem binária, com B 9x9. Na linha de baixo, em vermelho, a faixa que a erosão removeu; em azul, a faixa que a dilatação acrescentou. Ambas atuam nas bordas dos objetos.

Abertura

A palavra PIVC cercada de pequenos pontos brancos de ruído; após a erosão, os pontos somem e as letras ficam finas; após a dilatação, as letras voltam à espessura original e os pontos continuam ausentes
Figura 18 – Abertura passo a passo: a erosão remove o ruído claro (e afina as letras); a dilatação devolve a espessura às letras, mas não recria os pontos removidos.

Fechamento

A palavra PIVC com pequenos furos pretos e cortes finos atravessando as letras; após a dilatação, as falhas somem e as letras engordam; após a erosão, as letras voltam à espessura original sem as falhas
Figura 19 – Fechamento passo a passo: a dilatação cobre furos e cortes escuros; a erosão devolve às letras sua espessura, mas as falhas já preenchidas não reaparecem.
À esquerda, dois círculos brancos ligados por uma ponte fina, que após a abertura ficam separados; à direita, uma linha horizontal interrompida em três trechos, que após o fechamento fica contínua
Figura 20 – Abertura e fechamento na prática: a abertura separa objetos ligados por uma conexão estreita; o fechamento reconecta uma linha com pequenas interrupções.

Gradiente Morfológico

Três grades 7x7: a dilatação com um quadrado 5x5 de uns, menos a erosão com um único 1 no centro, igual ao gradiente, um anel de uns com o centro zerado
Figura 21 – Gradiente morfológico no exemplo da lousa: subtraindo a erosão da dilatação, resta apenas a região ao redor do contorno do objeto.
A palavra PIVC dilatada, menos a palavra erodida, resultando apenas no contorno das letras em branco sobre fundo preto
Figura 22 – Gradiente morfológico em uma imagem binária (B 5x5): o resultado é o contorno dos objetos.

Exemplo em Python: Operações Morfológicas com OpenCV

import cv2
import numpy as np

# Carrega em escala de cinza e binariza: 255 = objeto, 0 = fundo
imagem = cv2.imread("letras.png", cv2.IMREAD_GRAYSCALE)
_, binaria = cv2.threshold(imagem, 127, 255, cv2.THRESH_BINARY)

# Elemento estruturante quadrado 5x5
# (outros formatos: cv2.MORPH_CROSS, cv2.MORPH_ELLIPSE)
B = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))

erosao     = cv2.erode(binaria, B)
dilatacao  = cv2.dilate(binaria, B)
abertura   = cv2.morphologyEx(binaria, cv2.MORPH_OPEN, B)
fechamento = cv2.morphologyEx(binaria, cv2.MORPH_CLOSE, B)
gradiente  = cv2.morphologyEx(binaria, cv2.MORPH_GRADIENT, B)

cv2.imshow("Original", binaria)
cv2.imshow("Erosao", erosao)
cv2.imshow("Dilatacao", dilatacao)
cv2.imshow("Abertura", abertura)
cv2.imshow("Fechamento", fechamento)
cv2.imshow("Gradiente", gradiente)
cv2.waitKey(0)
cv2.destroyAllWindows()