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__)
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.
# 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 maxx
para 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)
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)
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.