• Unidade 2
  • Capítulo 4 - Imagens e Matrizes
  • Atividades
  • 3 - ROI e NumPy

ROI e NumPy

Como o OpenCV usa o Numpy para guardar a imagem, é muito útil usar as funções dessa biblioteca. Ser competente em Numpy vai dar um boost nas suas habilidades com imagens.

import cv2
import numpy as np

print ("OpenCV Version : %s " % cv2.__version__)
OpenCV Version : 4.5.3 

Cada seção deste guia apresenta operações frequentes e úteis com imagens. Use este notebook como consulta na hora de desenvolver as próximas atividades e APS.

Primeiramente vamos abrir a imagem da arara.

arara

# Vamos ler a imagem da arara igual ao exemplo do notebook da última aula
arara = cv2.imread("img/arara.jpg")

cv2.imshow("Arara", arara)
cv2.waitKey()
cv2.destroyAllWindows()

1. ROI - Region of Interest

  • Determinação de uma região retangular na imagem que se quer processar, de fora que ela possua as características de interesse.

  • Uma ROI define uma sub-imagem da imagem original, com menos linhas e/cou colunas

Para a definição de uma ROI, é necessário estabelecer:

  • A linha inicial (miny)

  • A coluna inicial (minx)

  • A linha final (maxy)

  • A coluna final (maxx)

A imagem do OpenCV em Python é armazenada dentro de uma estrutura tipo array bidimensional (tons de cinza) ou tridimensional (colorida)do pacote numpy, que permite a definição de ROIs através do fatiamento (slicing) dos eixos do array. Dessa forma, recuperamos uma ROI através do acesso por chaves:

roi = imagem[minyy:maxy, minx:maxx]

Atenção: os limites maxy e maxxpara a linha e coluna respectivamente não estão inclusos na ROI. Além disso, o acesso às linhas e colunas da nova imagem devem obedecer novos índices, começando pela linha 0 e coluna 0.

minx, miny = 50, 50
maxx, maxy = 250, 250

Agora vamos utilizar as variáveis para definir uma região, que marcaremos. Continuaremos usando a arara neste exemplo.

yellow_bgr = (0,255,255)
arara_corte = cv2.rectangle(arara, (minx, miny), (maxx, maxy), yellow_bgr, 2)

O comando cv2.rectangle desenha um retângulo na imagem. Para isso, temos os seguintes parâmetros:

  • A imagem que será desenhada

  • As coordenadas do canto superior esquerdo

  • As coordenadas do canto inferior direito

  • A cor do retângulo

  • A espessura da linha, mude para -1 para preencher o retângulo

cv2.imshow("Arara", arara_corte)
cv2.waitKey()
cv2.destroyAllWindows()

Vamos agora usar os valores do retângulo para recortar a imagem:

recorte = arara_corte[miny: maxy,minx: maxx]

cv2.imshow("Arara", arara_corte)
cv2.imshow("Recorte", recorte)
cv2.waitKey()
cv2.destroyAllWindows()

2. Mínimo, máximo, média, etc

Com o Numpy é muito fácil tirar estatísticas da imagem.

Aqui vamos trabalhar com uma imagem em tons de cinza, mas desta vez vamos enviar um argumento para a função cv2.imread para ler a imagem diretamente em tons de cinza.

Neste exercício vamos visualizar a imagem do RinTinTin.

Referencia: https://en.wikipedia.org/wiki/Rin_Tin_Tin

rintin_gray = cv2.imread("img/RinTinTin.jpg", cv2.IMREAD_GRAYSCALE)
# Esse segundo parâmetro é para ler a imagem em escala de cinza

cv2.imshow("Rintin", rintin_gray)
cv2.waitKey()
cv2.destroyAllWindows()

As funções do Numpy que já eram usadas com arrays 1D continuam funcionando:

minimo = np.min(rintin_gray)
maximo = np.max(rintin_gray)
media = np.mean(rintin_gray)

print("Minimo: ", minimo)
print("Maximo: ", maximo)
print("Media: ", media)
Minimo:  7
Maximo:  57
Media:  33.6369174495408

3. Operações Condicionais

O Numpy permite fazer operações condicionais em arrays (imagens).

Por exemplo, podemos fazer uma operação que retorna torna todos os pixels maiores que a média sejam convertivos para 255 e os menores que a média para 0.

Pergunta: Como vai ficar a imagem resultante?

# ```python
codicionado = rintin_gray.copy()
codicionado[codicionado < media] = 0
codicionado[codicionado >= media] = 255

cv2.imshow("Rintin", rintin_gray)
cv2.imshow("Condicionado", codicionado)
cv2.waitKey()
cv2.destroyAllWindows()
# ```python

4. Area

Após a condição, a imagem resultante é binária, ou seja, só tem dois valores: 0 e 255. Podemos usar isso para calcular a área da parte branca da imagem.

area = np.sum(codicionado)
print("Area: ", area)
print("Shape: ", codicionado.shape)
Area:  11921505
Shape:  (239, 318)

Exercício

No exemplo anterior, a area da parte resultante foi de 11921505 pixels brancos, mas a imagem original tem 239 x 318 = 76002 pixels.

Entenda por que a área resultante é maior que a área original e ajuste o problema, mostranda a área correta.

# # Desenvolva o código aqui # #

Prática 4.4

Crie um arquivo chamado webcam_BW.py que contenha uma classe chamada ProcessImage com as seguintes especificações:

A classe ProcessImage deve possuir um método chamado run_image que:

  • Recebe uma imagem.
  • Salva a imagem recebida em uma variável da classe chamada self.bgr.
  • Converte a imagem para tons de cinza, salvando o resultado na variável self.gray.
  • Processa a imagem para que os pixels com valores maiores ou iguais a 128 sejam convertidos para branco, enquanto os demais sejam convertidos para preto.

A classe ProcessImage deve possuir um método chamado show_image que exibe a imagem processada.

O arquivo webcam_BW.py deve ter uma função chamada main que:

  • Cria um loop infinito que captura imagens da webcam.
  • Utiliza o método run_image para processar a imagem capturada.
  • Chama o método show_image para exibir a imagem processada.