image

Bootcamps ilimitados + curso de inglês para sempre

80
%OFF
Article image
Ubiratan Tavares
Ubiratan Tavares28/10/2023 12:16
Compartilhe

Processando uma imagem digital com o OpenCV

  • #Python

1 - INTRODUÇÃO

Ao trabalhar com imagens, algumas das operações mais básicas que são essenciais para dominar incluem ler as imagens do disco, exibi-las, acessar seus valores de pixel e convertê-las de um espaço de cores para outro.

Este artigo tem como objetivo explicar essas operações básicas da biblioteca OpenCV, essenciais quando é necessário manipular imagens. Entretanto, iniciaremos primeiro com uma descrição de como uma imagem digital é formulada em termos de suas coordenadas espaciais e valores de intensidade.

2 - VISÃO GERAL

Este artigo está dividido em três partes; eles são:

  • Formulação de uma imagem;
  • Lendo e exibindo imagens em OpenCV;
  • Convertendo entre espaços de cores.

3 - FORMULAÇÃO DE UMA IMAGEM

Uma imagem digital é composta por pixels, onde cada pixel é caracterizado por suas coordenadas espaciais dentro do espaço da imagem e seu valor de intensidade ou nível de cinza.

Essencialmente, uma imagem pode ser descrita por uma função 2D, I(x, y), onde x e y denotam as coordenadas espaciais acima mencionadas, e o valor de I em qualquer posição da imagem (x, y) denota a intensidade do pixel. Numa imagem digital, as coordenadas espaciais, bem como os valores de intensidade, são todos quantidades finitas e discretas.

O tipo de imagem digital que acabamos de descrever é chamada de imagem em tons de cinza , porque compreende um único canal onde os valores dos pixels carregam apenas informações de intensidade.

As intensidades de pixel são comumente representadas por valores inteiros no intervalo [0, 255], o que significa que cada pixel pode assumir qualquer um dos 256 valores discretos.

Uma imagem RGB (Red, Green, Blue), por outro lado, é composta por três canais, caracterizado pelas cores vermelha, verde e azul.

O modelo de cores RGB não é o único que existe, mas é possivelmente o mais comumente usado em muitas aplicações de visão computacional. É um modelo de cor aditivo, que se refere ao processo de criação de cor misturando (ou adicionando) espectros de luz de fontes de cores diferentes.

Como uma imagem RGB é composta por três canais, então precisamos de três funções para descrevê-la:

  • IR (x, y): canal vermelho;
  • IG (x, y): canal verde;
  • IB (x , y): canal azul.

Consequentemente, numa imagem RGB cada valor de pixel é expresso por um trio de valores de intensidade.

4 - LENDO E EXIBINDO UMA IMAGEM COM O OpenCV

Vamos começar importando primeiro o método imread da biblioteca OpenCV em um script Python.

Em seguida, faremos a leitura de uma imagem no formato RGB. Para isso, faça download da imagem de um cachorro disponível gratuitamente, salvando-a no disco na pasta images com o seguinte nome: "dog.jpg".

Para maiores informações sobre a instalação da biblioteca OpenCV leia o artigo "Uma introdução ao OpenCV" acessando este link.

from cv2 import imread
img = imread('images/dog.jpg')

O método imread retorna uma matriz NumPy que é armazenada na variável img, que contém os valores de pixel da imagem.

Podemos verificar o tipo de dados e as dimensões do array da seguinte forma:

print('Datatype:', img.dtype, '\nDimensions:', img.shape)
Datatype: uint8 

Resultado:

Dimensions: (4000, 6000, 3)

As informações retornadas nos dizem que o array é o dado é do tipo uint8, o que significa que estamos trabalhando com valores inteiros de 8 bits sem sinal. Isso significa que os pixels em cada canal da imagem podem assumir qualquer um dos 256 valores (2 elevado a 8), dentro de um intervalo de 0 a 255.

Isso corresponde exatamente à formulação da imagem que revisamos acima.

Aprendemos também que as dimensões do array são 4.000 × 6.000 × 3, que correspondem ao número de linhas, número de colunas e canais da imagem, respectivamente.

A imagem é uma matriz NumPy tridimensional. Portanto, podemos manipular o array usando a biblioteca NumPy.

Vamos acessar os valores do primeiro pixel situado no canto superior esquerdo da imagem.

Tenha em mente que os arrays em Python são indexados em zero e, portanto, as coordenadas deste pixel são (0, 0).

print(img[0, 0])

Resultado:

[173 186 232]

Você pode ver na saída que, como esperado, cada pixel carrega três valores, um para cada um dos três canais que compõem a imagem.

Descobriremos a qual canal específico corresponde cada um desses três valores na próxima seção.

NOTA :

  1. Um ponto importante a ter em mente é que, se o método imread falhar ao carregar a imagem de entrada, então provavelmente, o nome da imagem fornecida não existe ou está errada ou seu caminho é inválido.
  2. O método imread não gerará um erro, mas retornará um objeto do tipo None.
  3. Portanto, a seguinte verificação pode ser incluída antes de prosseguir com a execução de código adicional que eventualmente faça uso dos valores da variável img:
if img is not None:
  ...

A seguir exibiremos a imagem usando o pacote Matplotlib, bem como o método imshow do OpenCV. Este último toma como primeiro argumento o nome da janela que conterá a imagem e a imagem a ser exibida como segundo argumento.

Também chamaremos a função waitkey do OpenCV após a exibição da imagem, que aguarda um evento de teclado por um determinado período de milissegundos. Caso contrário, se um valor 0 for fornecido como entrada, a função waitkey aguardará indefinidamente, permitindo-nos ver a janela exibida até que um evento de teclado seja gerado.

Para visualizar a imagem usando a biblioteca Matplotlib usamos as seguintes linhas de código:

# visualizando a imagem usando a biblioteca Matplotlib

import matplotlib.pyplot as plt
 
plt.imshow(img)
plt.title('Displaying image using Matplotlib')
plt.show()

Resultado:

image

Figura 1

Para visualizar a imagem usando a biblioteca OpenCV usamos as seguintes linhas de código:

# visualizando a imagem usando a biblioteca OpenCV

from cv2 import imshow, waitKey
 
imshow('Displaying image using OpenCV', img) 
waitKey(0)

Resultado:

image

Figura 2

Se você está surpreso com a saída produzida pelo Matplotlib e está se perguntando como isso aconteceu, a razão para isso é que o OpenCV lê e exibe a imagem em BGR em vez de ordem RGB.

Os desenvolvedores iniciais do OpenCV escolheram o formato de cores BGR (em vez do RGB) porque, na época, o formato de cores BGR era muito popular entre fornecedores de software e fabricantes de câmeras (Villan, 2019).

O Matplotlib, por outro lado, usa o formato de cores RGB e, portanto, requer que a imagem BGR seja primeiro convertida para RGB antes de ser exibida.

Com OpenCV, você também pode escrever um array NumPy como uma imagem em um arquivo, como segue:

from cv2 import imwrite
imwrite("output.jpg", img)

Ao escrever uma imagem com a função imwrite() no OpenCV, você deve ter certeza de que o array NumPy está no formato esperado pelo OpenCV, ou seja, é um array tridimensional de uint8 em linha × coluna × canal na ordem de canal BGR.

5 - CONVERTENDO ENTRE ESPAÇO DE CORES

A conversão de uma imagem de um espaço de cores para outro pode ser obtida por meio do método cvtColor da biblioteca OpenCV, que toma a imagem fonte como argumento de entrada junto com um código de conversão do espaço de cores.

Para converter entre os espaços de cores BGR e RGB, podemos usar o seguinte código:

from cv2 import cvtColor, COLOR_BGR2RGB
 
img_rgb = cvtColor(img, COLOR_BGR2RGB)

Se tivéssemos que tentar exibir a imagem novamente usando Matplotlib, agora poderíamos ver que ela é exibida corretamente, como apresentada na Figura 2, após a execução das linhas de código abaixo:

# convertendo uma imagem BGR em RGB e exibindo-as usando a biblioteca Matplotlib
plt.imshow(img_rgb)
plt.show()

Se também tivéssemos que acessar os valores do primeiro pixel da imagem RGB recém-convertida, executaríamos:

print(img_rgb[0, 0])

Resultado:

[232 186 173]

Comparando o resultado acima os valores, [173 186 232], que imprimimos anteriormente para a imagem BGR, podemos notar que o primeiro e o terceiro valores foram trocados. O que isto nos diz é que a ordem dos valores corresponde, portanto, à ordem dos canais de imagem.

BGR para RGB não é a única conversão de cores que pode ser obtida por este método. Na verdade, existem muitos códigos de conversão de espaço de cores para escolher, tal como o COLOR_RGB2HSV, que converte entre os espaços de cores RGB e HSV (Hue, Saturation, Value).

Outra conversão popular é de RGB para escala de cinza onde, como mencionamos anteriormente, espera-se que a saída resultante seja uma imagem de canal único. Podemos experimentar, executando as linhas de código abaixo:

#  convertendo uma imagem RGB em tons de cinza e exibindo-a usaando a biblioteca OpenCV

from cv2 import COLOR_RGB2GRAY
 
img_gray = cvtColor(img_rgb, COLOR_RGB2GRAY)
 
imshow(‘Grayscale Image', img_gray)
waitKey(0)

Resultado:

image

A conversão parece ter sido bem sucedida, mas vamos tentar também acessar o valor do primeiro pixel nas coordenadas (0, 0):

print(img_gray[0, 0])

Resultado:

198

Como esperado, é impresso apenas um único número que corresponde ao valor de intensidade do pixel

Vale ressaltar que este não é o único método pelo qual a imagem pode ser convertida em tons de cinza.

Na verdade, se tivéssemos que trabalhar com um aplicativo que requer apenas o uso de uma imagem em escala de cinza (em vez de RGB), também poderíamos optar por ler a imagem em escala de cinza imediatamente, conforme as linhas de código abaixo:

from cv2 import IMREAD_GRAYSCALE
 
img_gray = imread('Images/Dog.jpg', IMREAD_GRAYSCALE)
 
imshow(‘Grayscale Image', img_gray)
waitKey(0)

NOTA :

  1. A documentação do OpenCV diz que o uso do código de conversão de espaço de cores denominado IMREAD_GRAYSCALE fará uso da conversão interna de escala de cinza quando disponível, o que pode resultar em uma saída diferente daquela de cvtColor().

O método imread também oferece suporte a vários outros códigos de conversão de espaço de cores, tais como o IMREAD_COLOR e IMREAD_UNCHANGED. O código IMREAD_COLOR é a opção padrão que converte uma imagem em cores BGR, ignorando qualquer transparência. Já o código IMREAD_UNCHANGED, por outro lado, lê uma imagem que também pode incluir um canal alfa.

6 - REFERÊNCIAS

  • VILLAN, Alberto Fernandez. Mastering OpenCV 4 with Python: A practical guide covering topics from image processing, augmented reality to deep learning with OpenCV 4 and Python 3.7, 2019
Compartilhe
Recomendados para você
Suzano - Python Developer
BairesDev - Machine Learning Practitioner
Santander - Cibersegurança #2
Comentários (1)
Talita Santos
Talita Santos - 28/10/2023 13:22

Muito bom, vou aplicar. Parabéns Ubiratan!