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.
Operador de Sobel
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
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.
Erosão
Dilatação
Abertura
Fechamento
Gradiente Morfológico
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()