sol IntroPID
Objetivos da aula:
- Conhecer o que é uma imagem digital
- Conhecer como fazer leitura e exibição de imagens
- conhecer algumas propriedades de imagens
- conhecer canais de cores de imagens
Representação e visualização de imagem¶
Uma imagem digital nada mais é que uma uma matriz de linhas e colunas, onde cada posição desta matriz contem o valor de um pixel.
O valor de cada pixel representa a intensidade de cor naquele ponto especifico.
# Importando a biblioteca OpenCV
import cv2
#import a biblioteca Numpy8 bits
import numpy as np
#linha magica para imprimir graficos no notebook
%matplotlib inline
from matplotlib import pyplot as plt
print ("OpenCV Versão : %s " % cv2.__version__)
OpenCV Versão : 4.9.0
Dica para quem está utilizando o google colab¶
Por ser uma instância que é alocada temporariamente precisamos carregar as imagens neste seção.
Está etapa pode ser feita de forma manual, fazendo o upload das imagens.
Outra forma é fazer o download da imagem para o notebook, lempre-se que é um linux rodando! :) da uma olhada no exemplo abaixo.
# Para facilitar o download das imagens utilizadas neste notebook
!wget "https://raw.githubusercontent.com/arnaldojr/cognitivecomputing/master/material/aulas/PDI/lab01/NATUREZA_1.jpg" /content # este link é o local onde a imagem está salva
!wget "https://raw.githubusercontent.com/arnaldojr/cognitivecomputing/master/material/aulas/PDI/lab01/img3x3.png" /content
# para nao imprimir os eixos
image = cv2.imread("NATUREZA_1.jpg")
plt.imshow(image,interpolation="none")
plt.axis('off')
plt.show()
A imagem colorida possui três dimensões: as linhas e as colunas da matriz, bem como os canais da imagem. Uma imagem colorida geralmente possui três canais: R (Red - vermelho) G (Green - verde) B (Blue - azul)
Mas porque a imagem é mostrada de modo estranho pelo pacote matplotlib? Porque a OpenCV representa os canais da imagem na ordem B - G - R, e não R - G - B como é esperado pela maior parte das bibliotecas.
Assim, para podermos visualizar corretamente uma imagem do OpenCV com matplotlib, precisamos inverter os canais, como no código abaixo:
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image_rgb)
plt.axis('off')
plt.show()
# Mostrando a representação interna da imagem
print("Dimensões da imagem: ", image_rgb.shape)
print("Quantidade de linhas: ", image_rgb.shape[0])
print("Quantidade de colunas: ", image_rgb.shape[1])
print("Camadas de cores: ", image_rgb.shape[2])
Dimensões da imagem: (768, 1024, 3) Quantidade de linhas: 768 Quantidade de colunas: 1024 Camadas de cores: 3
# Mostrando a representação interna da imagem
print("Dimensões da imagem: \n", image_rgb)
Dimensões da imagem: [[[ 10 92 194] [ 12 94 196] [ 12 95 197] ... [ 6 98 201] [ 5 97 200] [ 2 95 198]] [[ 11 93 195] [ 11 94 196] [ 11 94 196] ... [ 6 98 201] [ 6 98 201] [ 4 97 200]] [[ 11 94 196] [ 11 94 196] [ 9 95 196] ... [ 5 97 200] [ 7 99 202] [ 7 100 203]] ... [[ 0 69 111] [ 1 70 112] [ 1 70 112] ... [ 11 31 6] [ 17 41 17] [ 6 34 9]] [[ 0 67 109] [ 0 69 111] [ 2 71 113] ... [ 65 105 68] [ 86 135 90] [ 82 136 86]] [[ 0 66 108] [ 0 69 111] [ 2 71 113] ... [ 53 109 62] [ 72 138 77] [ 74 145 77]]]
A matriz acima é a representação da imagem de forma numérica, é o valor de cada pixel da imagem. Com esta imagem fica complicado. Vamos tentar analisar separando os canais de cores de um pixel específico.
(b, g, r) = image[450, 50]
print('O pixel (50, 50) tem as seguintes cores:')
print('Vermelho:',r, 'Verde:', g, 'Azul:', b)
O pixel (50, 50) tem as seguintes cores: Vermelho: 2 Verde: 14 Azul: 36
Desafio 1¶
Abra a imagem "img3x3.png" e plote suas componentes externas (shape) e internas (matriz).
Como você esta relacionado as possições da matriz com os pixels da imagem??
# implemente aqui o seu código.
# vou carregar a imagem
image = cv2.imread("img3x3.png")
# vou converter a imagem para RGB
image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# vou mostrar a imagem
plt.imshow(image_rgb)
plt.axis('off')
plt.show()
# Mostrando a representação interna e externa da imagem
print("Dimensões da imagem: ", image_rgb.shape)
print("Quantidade de linhas: ", image_rgb.shape[0])
print("Quantidade de colunas: ", image_rgb.shape[1])
print("Camadas de cores: ", image_rgb.shape[2])
print(image_rgb)
Dimensões da imagem: (3, 3, 3) Quantidade de linhas: 3 Quantidade de colunas: 3 Camadas de cores: 3 [[[255 5 5] [255 255 255] [ 1 1 255]] [[255 255 255] [ 1 255 1] [255 255 255]] [[ 2 255 255] [255 255 21] [255 1 255]]]
Imagem em tons de cinza¶
Em muitos casos trabalhamos com imagens na escala de cinza, logo, a imagem possui apenas 1 canal de cor.
import cv2
import numpy as np
from matplotlib import pyplot as plt
# Carregando a imagem na versão tons de cinza (grayscale) de um arquivo
imagem_cinza = cv2.imread("img3x3.png", cv2.IMREAD_GRAYSCALE)
# ou use o argumento 0, tem o mesmo efeito de importar na escala de cinza
#imagem_cinza = cv2.imread("img3x3.png", 0)
plt.imshow(imagem_cinza)
plt.axis('off')
plt.show()
imagem_cinza
array([[ 79, 255, 29], [255, 150, 255], [179, 228, 105]], dtype=uint8)
Desafio 2¶
Eita! alguma está errada nesse plot, era esperado uma imagem na escala de cinza. Por que apareceu isso, como corrigir?
# Coloque aqui sua solução.
# Importando a biblioteca OpenCV, Numpy e matplotlib
import cv2
import numpy as np
from matplotlib import pyplot as plt
# Carregando a imagem na versão tons de cinza (grayscale) de um arquivo
imagem_cinza = cv2.imread("img3x3.png", 0)
# por padrao o matplotlib usa o cmap='viridis' para mostrar a imagem em tons de cinza.
# para mostrar a imagem em tons de cinza com o matplotlib é necessário usar o cmap='gray'
# mas pode ser usado outro cmap para mostrar a imagem em tons de cinza com cores diferentes
# Mostrando a imagem em tons de cinza
plt.subplot(1,2,1)
plt.imshow(imagem_cinza)
plt.axis('off')
plt.title('cinza com cmap= viridis (padrão)')
plt.subplot(1,2,2)
plt.imshow(imagem_cinza, cmap='gray')
plt.axis('off')
plt.title('Imagem em tons de cinza')
plt.show()
# o plt.subplot é usado para mostrar mais de uma imagem na mesma janela do matplotlib
# o primeiro argumento é o número de linhas
# o segundo argumento é o número de colunas
# o terceiro argumento é o número da imagem
# o plt.title é usado para mostrar o título da imagem
# o plt.show é usado para mostrar a imagem
Amostragem da imagem¶
As imagens capturadas por dispositivos digitais possuem as características de resolução espacial e resolução de cores Enquanto a resolução de cores afeta o número de cores que podem serr epresentadas na imagem, sua resolução espacial afeta o tamanho que a imagem irá ter. Embora não se possa comparar diretamente a resolução de duas imagens com tamanhos diferentes, a imagem do mesmo objeto, se possui mais pixels, significará que tamém possui maior resolução
Alterando o tamanho de uma imagem¶
O redimensionamento da imagem pode ser feito na OpenCV através do comando cv2.resize(imagem, tamanho, interpolação)
O tamanho é dado por uma tupla (W,H), onde W é a largura (número de colunas) e H é a altura (número de linhas)
# Carregando a imagem na versão colorida de um arquivo
import cv2
import matplotlib.pyplot as plt
imagem = cv2.imread("NATUREZA_1.jpg")
image = cv2.cvtColor(imagem, cv2.COLOR_BGR2RGB)
print("Dimensões da imagem: ", image.shape)
imagem2 = cv2.resize(image, (600,400), cv2.INTER_LINEAR)
print("Novas dimensões da imagem: ", imagem2.shape)
plt.imshow(imagem2)
plt.show()
Dimensões da imagem: (768, 1024, 3) Novas dimensões da imagem: (400, 600, 3)
Desafio 3¶
Comparar os diferentes métodos de interpolação (vizinho mais próximo, bilinear e bicúbica) ao ampliarmos uma imagem em 10 vezes seu tamanho. Escolha uma imagem pequena.
Dica de onde encontrar na documentação as flags de interpolação: https://docs.opencv.org/3.4/da/d54/group__imgproc__transform.html#ga5bb5a1fea74ea38e1a5445ca803ff121
Para saber mais sobre interpolação, sugiro assistir ao video: https://www.youtube.com/watch?v=8bTDssnJyZc&ab_channel=S.M.RiazulIslam
#Implemente aqui sua solução............
# Carregando a imagem na versão colorida de um arquivo
import cv2
import matplotlib.pyplot as plt
imagem = cv2.imread("img3x3.png")
image = cv2.cvtColor(imagem, cv2.COLOR_BGR2RGB)
print("Dimensões da imagem original: ", image.shape)
# para testar diferentes métodos de interpolação, vamos redimensionar a imagem para um tamanho maior
# e vamos usar diferentes métodos de interpolação para redimensionar a imagem
# vamos usar os métodos cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_AREA, cv2.INTER_CUBIC e cv2.INTER_LANCZOS4
# que são os métodos de interpolação disponíveis no OpenCV
interpolacao = [cv2.INTER_NEAREST, cv2.INTER_LINEAR, cv2.INTER_AREA, cv2.INTER_CUBIC, cv2.INTER_LANCZOS4]
# essa função é um list comprehension do python que cria uma lista com as imagens redimensionadas com os diferentes métodos de interpolação
resized_images = [cv2.resize(image, (image.shape[1] * 2, image.shape[0] * 5), interpolation=nome) for nome in interpolacao]
# Vamos exibir as imagens redimensionadas com os diferentes métodos de interpolação usando o matplotlib com o loop for.
interpolation_names = ['INTER_NEAREST', 'INTER_LINEAR', 'INTER_AREA', 'INTER_CUBIC', 'INTER_LANCZOS4']
plt.figure(figsize=(15, 10))
for i, resized_image in enumerate(resized_images):
plt.subplot(2, 3, i + 1)
plt.imshow(resized_image)
plt.title(interpolation_names[i])
plt.axis('off')
plt.show()
Dimensões da imagem original: (3, 3, 3)
Alterando os valores dos pixels de uma imagem¶
Range de valores¶
Antes de alterar os valores dos pixels temos que entender que a OpenCV trabalha com valores de 8 bits para cada componente de cor ou escala de cinza, quer dizer que os valores possiveis estão no range entre 0 e 2⁸-1, que é a mesma que dizer entre 0 e 255.
import cv2
import numpy as np
# Carregando a imagem
imagem_cinza = cv2.imread("img3x3.png", cv2.IMREAD_COLOR)
plt.imshow(imagem_cinza)
plt.axis('off')
plt.show()
Desafio 4¶
Implemente um codigo que faz a alteração do pixel(0,0) para a a cor Magenta - RGB (255,0,255);
# implemente aqui sua solução....
import cv2
import numpy as np
# Carregando a imagem na versão colorida de um arquivo
imagem = cv2.imread("img3x3.png", cv2.IMREAD_COLOR)
imagem_rgb = cv2.cvtColor(imagem, cv2.COLOR_BGR2RGB)
imagem_rgb[0,0] = [255, 0, 255] # alterando a cor do pixel (0,0) para magenta
# Mostrando a imagem em tons de cinza
plt.subplot(1,2,1)
plt.imshow(cv2.cvtColor(imagem, cv2.COLOR_BGR2RGB))
plt.axis('off')
plt.title('original')
plt.subplot(1,2,2)
plt.imshow(imagem_rgb)
plt.axis('off')
plt.title('alterada')
plt.show()
Desafio 5¶
Crie uma array de zero com 8 linhas e 5 colunas. E escreva (desenhe) a primeira letra do seu nome ou grupo.
Plot a imagem para visualizar o resultado.
Dica: Use np.zeros() para criar o array, para facilitar faça em escala de cinza onde o valor de intensidade do pixel 0=branco e 255=preto.
# Começamos importanto as bibliotecas
import cv2
import numpy as np
from matplotlib import pyplot as plt
# Criamos o array de zero 3x3
letra = np.zeros((8,5), dtype=int)
# implemente aqui o seu código.........
letra[0, 2] = 255
letra[1, 1] = 255
letra[1, 3] = 255
letra[2, 0] = 255
letra[2, 4] = 255
letra[3, 0] = 255
letra[3, 4] = 255
letra[4, 0] = 255
letra[4, 1] = 255
letra[4, 2] = 255
letra[4, 3] = 255
letra[4, 4] = 255
letra[5, 0] = 255
letra[5, 4] = 255
letra[6, 0] = 255
letra[6, 4] = 255
letra[7, 0] = 255
letra[7, 4] = 255
# Plota resultado
plt.imshow(letra, cmap='gray')
plt.show()
Varredura de uma imagem¶
Desenvolver uma rotina capaz de varrer sua imagem pixel a pixel é muito mais interessante para aplicações mais práticas, embora exista tecnicas mais otimizadas e rápidas para essa aplicação, podemos utilizar uma estrutura de dois laços For para passar sobre todas as linhas e todas as colunas da matriz (imagem).
import cv2
imagem = cv2.imread("NATUREZA_1.jpg")
image = cv2.cvtColor(imagem, cv2.COLOR_BGR2RGB)
for y in range(0, image.shape[0]):
for x in range(0, image.shape[1]):
image[y, x] = (255,0,0) #sobreescrevendo todos os pixels da imagem para a cor vermelha
#pass
plt.imshow(image, interpolation="none")
plt.show()
Desafio 6¶
Utilizando a técnica dos 2 for, implemente uma função que desenha um linha branca na vertical no centro da imagem de largura 50 pixeis. Dica: use um if para checar a posição (x,y) antes de pintar de branco o pixel.
### seu código aqui
import cv2
import matplotlib.pyplot as plt
imagem = cv2.imread("NATUREZA_1.jpg")
image = cv2.cvtColor(imagem, cv2.COLOR_BGR2RGB)
# Achar o meio da imagem e o range
meio = image.shape[1] // 2 # Divisão inteira para achar o meio da imagem (largura)
faixa = 50 // 2
min = meio - faixa
max = meio + faixa
for y in range(0, image.shape[0]):
for x in range(0, image.shape[1]):
if x > min and x < max:
image[y, x] = (255, 0, 0) # Sobreescrevendo todos os pixels da imagem para a cor vermelha
plt.imshow(image, interpolation="none")
plt.show()