#!/usr/bin/env python
# coding: utf-8
# 
# ## Universidade Federal de Campina Grande (UFCG)
# ## Centro de Engenharia Elétrica e Informática (CEEI)
# ## Disciplina: Int. ao Processamento de Imagem Digital e Visão Computacional
# ## Professora: Luciana Ribeiro Veloso
# ## Aluno(a): Coloque seu nome aqui
# ## Observações
# ***
#
# 1. Os arquivos de laboratório devem ser salvos seguindo o seguinte padrão: `lab-x-nome-sobrenome.ipynb`.
# 2. Não esqueça de colocar o seu nome no cabeçalho acima.
# 3. Não altere a ordem das células e realize as implementações somente nos campos específicados.
# 4. Ao longo do laboratório será solicitado perguntas teóricas relativas aos assuntos das aulas da disciplina e implementações de código utilizando a linguagem de programação Python.
# 5. As células de implementação com código serão indicadas pelos seguintes comentários: `# IMPLEMENTE O SEU CÓDIGO AQUI`.
# 6. Para editar uma célula de texto, basta clicar duas vezes com o cursos do mouse para editar, e `Ctrl + Enter` para finalizar a edição.
# 7. Para rodar as células com os códigos desenvolvidos, digite `Ctrl + Enter` ou clique em `Run` no menu do Jupyter.
# 8. Dúvidas, problemas de execução de código ou dificuldades com a linguagem de programação Python devem ser feitas durante as aulas de laboratório, encaminhadas para o grupo de WhatsApp da turma ou fórum do PVAE da disciplina.
# 9. Os laboratórios devem ser enviados nos campos especificados pelo PVAE. ATENTE-SE AOS PRAZOS DE ENTREGA!
# # Laboratório 2: Processamento Digital de Imagens
# ***
# ### Importação dos Pacotes
# In[ ]:
import cv2 # opencv para manipulação de imagens
import numpy as np # numpy para manipulação de matrizes e arrays
import matplotlib.pyplot as plt # pyplot para plotagem de gráficos e imagens
import urllib.request as url # urllib para baixar arquivos via HTTPS
import zipfile # zipfile para lidar com pastas compactadas
# In[ ]:
# baixando as imagens de referência
url.urlretrieve('https://github.com/Alyssonmach/pdi-labs/raw/main/imagens.zip', 'imagens.zip')
with zipfile.ZipFile('imagens.zip', 'r') as zip_ref:
zip_ref.extractall('')
# ### Numpy Arrays
#
# Podemos utilizar a biblioteca Numpy para escrever arrays e matrizes de forma semelhante ao Matlab:
#
# * `a) A = np.array( [1, 2, 3, 4, 5])`
# * `b) B = np.array( [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ])`
# * `c) C = np.array( [ [ [1, 2], [3, 4] ], [ [1, 2], [3, 4] ] ])`
#
# Descrição:
# * O código do item **a)** produz um array unidimensional a partir de uma lista;
# * Já o do item **b)** produz um array bidimensional, ou uma matriz, a partir de uma lista de listas;
# * Por fim, o código do item **c)** produz um array tridimensional;
# * Os arrays podem ser exibidos a partir do comando **print**, como por exemplo em **print(A)**;
# * É possível checar as dimensões de cada array printando o atributo **shape**, digitando por exemplo **print(A.shape)**;
# In[ ]:
A = np.array([1, 2, 3, 4, 5])
B = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
C = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
# In[ ]:
print("Array A: {}".format(A))
print("Shape de A: {}".format(A.shape))
# In[ ]:
print("Array B:\n{}".format(B))
print("Shape de B: {}".format(B.shape))
# In[ ]:
print("Array C:\n{}".format(C))
print("Shape de C: {}".format(C.shape))
# Elementos internos dos arrays podem ser acessados utilizando colchetes, por exemplo:
#
# * **A[0]** acessa o primeiro elemento de A, nesse caso 1;
# * **B[0, 2]** acessa o terceiro elemento da primeira linha de B, ou seja 3.
# * **C[1, 0, 1]** acessa o segundo elemento da primeira linha da segunda matriz de C, ou seja 6;
# In[ ]:
print("A[0] == {}".format(A[0]))
print("B[0,2] == {}".format(B[0,2]))
print("C[1, 0, 1] == {}".format(C[1, 0, 1]))
# Também é possível acessar fatias do array utilizando o operador `:` como pode ser visto a seguir:
#
# * **A[0:4]** retorna um array formado pelos quatro primeiros elementos de A;
# * **B[2, 0:2]** retorna um array unidimensional formado pelos dois primeiros elementos da terceira linha de B;
# * **C[0, :, :]** retorna um array bidimensional formado por todas as linhas e colunas da primeira matriz de C;
# * Observe que a contagem dos índices é iniciada em 0;
# In[ ]:
print("A[0:4]: {}\n".format(A[0:4]))
print("B[2, 0:2]: {}\n".format(B[2, 0:2]))
print("C[0, :, :]:\n{}".format(C[0, :, :]))
# ## Questão 1: [Valor da Questão: 1.5][Taxa de acerto: x.x]
#
# * (a) Produza as seguintes matrizes:
# * `A1 = A[1:4]`
# * `B1 = B[1:2, 0:1]`
# * `B2 = B[-1, -2]`
# * `C1 = C[-2, -2, -2]`
# * `C2 = C[0, 0, 0]`
# * `C3 = C[:, 0, 0]`
# * (b) Analisando os resultados obtidos, o que os índices negativos significam?
# * (c) **C1** e **C2** são iguais? Explique.
# In[ ]:
# IMPLEMENTE SEU CÓDIGO AQUI -> QUESTÃO 1 - LETRA (a)
# ## Respostas da Questão 1:
#
# * (b) Adicione sua resposta aqui.
# * (c) Adicione sua resposta aqui.
# ### Tipos de Imagem
#
# 1. Vamos trabalhar com quatro tipos de imagens:
#
# a. **Imagens de Intensidades:** São matrizes cujos valores representam intensidades em cada ponto. Elementos de intensidade da classe **uint8** terão valores no intervalo [0, 255]. Já elementos da classe **uint16** terão valores entre [0, 65535].
#
# b. **Imagens Binárias:** São um arranjo lógico em forma de matriz cujos valores são booleanos, podendo ser 0s ou 1s;
#
# c. **Imagens Indexadas:** São imagens cujo valor de cada pixel está associado a uma cor descrita por um mapa de cores (colormap);
#
# d. **Imagens Coloridas:** São Imagens com múltiplos canais onde os múltiplos valores associados a um determinado pixel descrevem a sua cor. Um exemplo seriam imagens RGB, onde os diferentes canais descrevem a intensidade luminosa das cores vermelho (R), verde (G) e azul (B), respectivamente, de uma imagem;
#
# * Note que os tipos de imagem não são excludentes, uma mesma imagem pode estar associada a mais de um dos tipos descritos.
# In[ ]:
# a próxima linha de código torna a figura do matplotlib interativa, permitindo visualizar os valores de cada pixel
# a figura deixará de ser interativa quando outra célula for executada
# é possível reativá-la ao rodar essa célula novamente
get_ipython().run_line_magic('matplotlib', 'notebook')
# um array do numpy pode ser interpretado como uma imagem de intensidade
I = np.array([[0, 50, 100, 150, 200, 250],
[0, 50, 100, 150, 200, 250],
[0, 50, 100, 150, 200, 250],
[0, 50, 100, 150, 200, 250],
[0, 50, 100, 150, 200, 250]]).astype(np.uint8)
# podemos utilizar o matplotlib para visualizar a imagem através da função imshow
plt.figure(figsize = (4, 4))
plt.imshow(I, cmap = "gray")
# * Observe que a associação das intensidades a cores é arbitrária, podendo ser obtida uma imagem diferente mudando o colormap.
# In[ ]:
get_ipython().run_line_magic('matplotlib', 'notebook')
fig, axs = plt.subplots(nrows = 2, ncols = 3, figsize=(8, 6))
# primeira linha de subfiguras
# primeira subfigura
axs[0][0].imshow(I)
axs[0][0].set_title("Colormap Padrão", fontsize = 10)
# segunda subfigura
axs[0][1].imshow(I, cmap = "gray")
axs[0][1].set_title("Colormap em Escala de Cinza", fontsize = 10)
# terceira subfigura
axs[0][2].imshow(I, cmap = "Purples")
axs[0][2].set_title("Colormap em tons de roxo", fontsize = 10)
# segunda linha de subfiguras
# primeira subfigura
axs[1][0].imshow(I, cmap="Reds")
axs[1][0].set_title("Colormap em tons de vermelho", fontsize = 10)
# segunda subfigura
axs[1][1].imshow(I, cmap="Greens")
axs[1][1].set_title("Colormap em tons de verde", fontsize = 10)
# terceira subfigura
axs[1][2].imshow(I, cmap="Blues")
axs[1][2].set_title("Colormap em tons de azul", fontsize = 10)
# Referências de colormaps: https://matplotlib.org/stable/tutorials/colors/colormaps.html
# * Observe que a associação dos valores mínimos e máximos também é arbitrária e pode ser controlada pelos argumentos **vmin** e **vmax**.
# In[ ]:
get_ipython().run_line_magic('matplotlib', 'notebook')
fig, axs = plt.subplots(nrows = 2, ncols = 3, figsize=(8, 6))
# primeira linha de subfiguras
# primeira Subfigura
axs[0][0].imshow(I, cmap = "gray")
axs[0][0].set_title("Valores Padrão", fontsize = 10)
# segunda Subfigura
axs[0][1].imshow(I, vmin = 100, vmax = 200, cmap = "gray")
axs[0][1].set_title("vmin = 100, vmax = 200", fontsize = 10)
# terceira Subfigura
axs[0][2].imshow(I, vmin = 25, vmax = 75, cmap = "gray")
axs[0][2].set_title("vmin = 25, vmax = 75", fontsize = 10)
## segunda linha de subfiguras
# primeira Subfigura
axs[1][0].imshow(I, vmin = -1, vmax = 0, cmap = "gray")
axs[1][0].set_title("vmin = -1, vmax = 0", fontsize = 10)
# segunda Subfigura
axs[1][1].imshow(I, vmin = 115, vmax = 125, cmap = "gray")
axs[1][1].set_title("vmin = 115, vmax = 125", fontsize = 10)
# terceira Subfigura
axs[1][2].imshow(I, vmin = 255, vmax = 256, cmap = "gray")
axs[1][2].set_title("vmin = 255, vmax = 256", fontsize = 10)
# ## Questão 2: [Valor da Questão: 1.0][Taxa de acerto: x.x]
#
# * Ao ajustar os argumentos **vmin** e **vmax**, as imagens geradas foram diferentes da imagem com cores padrão. Que tipo de alteração ocorreu? A matriz original sofreu alguma modificação?
# ## Respostas da Questão 2:
#
# * Adicione sua resposta aqui.
# ### Convertendo Tipos de Dados
# In[ ]:
get_ipython().run_line_magic('matplotlib', 'notebook')
fig, axs = plt.subplots(nrows = 1, ncols = 3, figsize=(8, 6))
# é preciso se atentar aos valores da matriz ao converter entre os tipos de array
I16 = np.array([[ 0, 0, 0, 0, 0, 0],
[ 50, 50, 50, 50, 50, 50],
[100, 100, 100, 100, 100, 100],
[150, 150, 150, 150, 150, 150],
[200, 200, 200, 200, 200, 200],
[250, 250, 250, 250, 250, 250],
[300, 300, 300, 300, 300, 300]]).astype(np.uint16)
axs[0].imshow(I16, vmin = 0, vmax = 255, cmap = "gray")
axs[0].set_title("Imagem Original uint16", fontsize = 10)
axs[0].set_xlabel("vmin = 0\n vmax = 255", fontsize = 10)
# a conversão direta sem o reescalonamento dos valores pode produzir resultados inesperados
I8a = I16.astype(np.uint8)
axs[1].imshow(I8a, vmin = 0, vmax = 255, cmap = "gray")
axs[1].set_title("Imagem uint8 s/ \nreescalonamento", fontsize = 10)
axs[1].set_xlabel("vmin = 0\n vmax = 255", fontsize = 10)
# o reescalonamento melhora os resultados, mas como uint8 não aceita valores decimais, ocorrem erros de quantização
rescale_factor = 255 / np.max(I16)
I8b = ( rescale_factor * I16 ).astype(np.uint8)
axs[2].imshow(I8b, vmin = 0, vmax = 255, cmap = "gray")
axs[2].set_title("Imagem uint8 c/ \nreescalonamento", fontsize = 10)
axs[2].set_xlabel("vmin = 0\n vmax = 255", fontsize = 10)
# In[ ]:
get_ipython().run_line_magic('matplotlib', 'notebook')
fig, axs = plt.subplots(nrows = 1, ncols = 3, figsize=(8, 6))
# é preciso se atentar aos valores da matriz ao converter entre os tipos de array
I8 = np.array([[36, 47, 75, 32, 18],
[0, 90, 0, 67, 29],
[150, 22, 50, 20, 54],
[50, 34, 65, 40, 50],
[6, 50, 5, 50, 13],
[39, 1, 50, 25, 0]]).astype(np.uint8)
axs[0].imshow(I8, vmin = 0, vmax = 255, cmap = "gray")
axs[0].set_title("Imagem Original uint8", fontsize = 10)
axs[0].set_xlabel("vmin = 0\n vmax = 255", fontsize = 10)
# imagens formadas a partir de arrays float32 são tipicamente utilizadas em aplicações de IA como redes convolucionais
# nesse caso, a conversão pode ser realizada dividindo os elementos da matriz por 255, maior valor para imagens uint8
# como o tipo float32 aceita valores decimais e dispõe de mais bits para representar os valores, não ocorrem perdas.
Ifloat = (I8 / 255).astype(np.float32)
axs[1].imshow(Ifloat, vmin=0, vmax=1, cmap = "gray")
axs[1].set_title("Imagem Float", fontsize = 10)
axs[1].set_xlabel("vmin = 0\n vmax = 1.0", fontsize = 10)
# imagens (ou máscaras) binárias são geralmente utilizadas para a extração de características em imagens
# nesse caso, a conversão pode ser realizada a partir de um processo de limiarização (thresholding)
# os valores booleanos podem ser convertidos em números (0s e 1s) mudando o tipo de array para float ou uint
Ibin = (I8 >= 50)
axs[2].imshow(Ibin, cmap = "gray")
axs[2].set_title("Imagem Binária", fontsize = 10)
axs[2].set_xlabel("vmin = False\n vmax = True", fontsize = 10)
# ## Questão 3: [Valor da Questão: 1.5][Taxa de Acerto: x.x]
#
# * (a) reproduza e plote as seguintes matrizes:
# * `A = [[16, 3, 2, 13], [6, 9, 12, 7], [5, 10, 11, 8], [4, 15, 14, 8]]`
# * `B = [[16, 8, 2, 4], [20, 30, 40, 50], [5, 7, 8, 11]]`
# * `C = [[20, 30, 40], [50, 90, 15], [80, 30, 10]]`
# * `D = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 8, 8, 9], [8, 7, 7, 8], [4, 5, 9, 8]]`
# * (b) Plote as seguintes Imagens de Intensidade e comente os resultados obtidos.
# * `IA = A`
# * `IB = B, vmin = 4, vmax = 30`
# * `IC = C, vmin = 15, vmax = 20`
# * `ID = D, vmin = 0, vmax = 20`
# In[ ]:
# IMPLEMENTE SEU CÓDIGO AQUI -> QUESTÃO 3 - LETRA (a)
# In[ ]:
# IMPLEMENTE SEU CÓDIGO AQUI -> QUESTÃO 3 - LETRA (b)
# ## Resposta da Questão 3:
#
# * (b) Adicione sua resposta aqui.
# ## Questão 4: [Valor da Questão: 1.0][Taxa de acerto: x.x]
#
# * A partir da matriz **G** abaixo, gere as imagens solicitadas. Comente os resultados obtidos.
# * Uma imagem de intensidade com valores entre [0, 1].
# * Uma imagem binária com limiar de 0.25.
# * Uma imagem com valores no intervalo [0, 255].
#
# `G = [[-0.7, 1.2, 0.4, -0.6, -0.4, 1.2],
# [-1.6, -0.6, 0.4, 0.8, 0.0, 0.8],
# [1.5, -0.5, 0.1, 0.2, -0.8, 1.1],
# [2.1, 0.9, 0.5, -0.5, -1.6, -0.7],
# [0.1, -1.4, 1.1, -1.2, 0.2, -0.9],
# [-1.0, -2.0, 1.0, 0.6, -0.1, -1.3]]`
# In[ ]:
# IMPLEMENTE SEU CÓDIGO AQUI - QUESTÃO 4
# ## Resposta da Questão 4:
#
# * Adicione sua resposta aqui.
# ## Questão 5: [Valor da Questão: 1.0][Taxa de acerto: x.x]
#
# * Com base na matriz G, comente a diferença entre as imagens G1 e G2 abaixo. Observe os valores de diferentes pixels nas mesmas posições.
# In[ ]:
get_ipython().run_line_magic('matplotlib', 'notebook')
G = np.array([[-0.7, 1.2, 0.4, -0.6, -0.4, 1.2], [-1.6, -0.6, 0.4, 0.8, 0.0, 0.8],
[1.5, -0.5, 0.1, 0.2, -0.8, 1.1], [2.1, 0.9, 0.5, -0.5, -1.6, -0.7],
[0.1, -1.4, 1.1, -1.2, 0.2, -0.9], [-1.0, -2.0, 1.0, 0.6, -0.1, -1.3] ]).astype(np.float32)
# produzindo G1 a partir de G
G1 = G - np.min(G)
rescale_factor = 255 / np.max(G1)
G1 = (rescale_factor * G1).astype(np.uint8)
G1 = (G1 / 255).astype(np.float32)
# produzindo G2 a partir de G
G2 = G - np.min(G)
G2 = (G2 / np.max(G2)).astype(np.float32)
fig, axs = plt.subplots(nrows = 1, ncols = 2, figsize=(8, 6))
axs[0].imshow(G1, vmin=0, vmax=1, cmap="gray")
axs[0].set_title("Imagem G1", fontsize=10)
axs[1].imshow(G2, vmin=0, vmax=1, cmap="gray")
axs[1].set_title("Imagem G2", fontsize=10)
# In[ ]:
print('Informações Estatísticas de G:\n')
print('Dimensão da Imagem:', G.shape)
print('Quantidade de Pixels:', G.size)
print('Média: {:.3f}'.format(np.mean(G)))
print('Desvio Padrão: {:.3f}'.format(np.std(G)))
print('Valor Mínimo:', np.min(G))
print('Valor Máximo:', np.max(G))
print('\nInformações Estatísticas de G1:\n')
print('Dimensão da Imagem:', G1.shape)
print('Quantidade de Pixels:', G1.size)
print('Média: {:.3f}'.format(np.mean(G1)))
print('Desvio Padrão: {:.3f}'.format(np.std(G1)))
print('Valor Mínimo:', np.min(G1))
print('Valor Máximo:', np.max(G1))
print('\nInformações Estatísticas de G2:\n')
print('Dimensão da Imagem:', G2.shape)
print('Quantidade de Pixels:', G2.size)
print('Média: {:.3f}'.format(np.mean(G2)))
print('Desvio Padrão: {:.3f}'.format(np.std(G2)))
print('Valor Mínimo:', np.min(G2))
print('Valor Máximo:', np.max(G2))
# ## Resposta da Questão 5:
#
# * Adicione sua resposta aqui.
# ### Lendo imagens do computador
# ***
#
# A biblioteca OpenCV possibilita carregar imagens do computador como arrays do numpy através da função **imread** (Observe que o comando cv2.imread lê uma imagem colorida como BGR, enquanto o comando plt.imread lê como RGB):
#
# * **Sintaxe:** `im = cv2.imread( filepath, 0)`
#
# * **Descrição:** A função carrega a o arquivo cujo caminho está contido na string e a armazena na variável im como um array do numpy. O flag 0 indica o carregamento do arquivo como imagem monocromática.
# ## Questão 06: [Valor da Questão: 2.0][Taxa de Acerto: x.x]
#
# * (a) Realize a leitura da imagem lenna.jpg (ou outra a sua escolha) e utilize o matplotlib para visualizar a imagem. Analise a variável im produzida, verificando suas dimensões e valores máximo e mínimo.
# * (b) Faça o mesmo para a imagem morangos.jpg (ou outra a sua escolha), mas utilize também a mágica "%matplotlib notebook". Explore as ferramentas da janela produzida.
# In[ ]:
# IMPLEMENTE O SEU CÓDIGO AQUI -> QUESTÃO 6 - LETRA (a)
# In[ ]:
# IMPLEMENTE O SEU CÓDIGO AQUI -> QUESTÃO 6 - LETRA (b)
# A biblioteca OpenCV possibilita redimensionar imagens carregadas através da função **resize**:
#
# * **Sintaxe:** `dst_img = cv2.resize(src_img, (cols, rows))`
#
# * **Descrição:** A função altera as dimensões da imagem para as dimensões fornecidas (cols, rows), retornando , que é a imagem redimensionada. pode ser uma imagem monocromática, colorida ou binária e as novas dimensões podem ser maiores ou menores que as originais.
# ## Questão 7: [Valor da Questão: 2.0][Taxa de acerto: x.x]
#
# * (a) Carregue a imagem **mandril.tiff** e altere suas dimensões utilizando a função resize para as dimensões listadas a seguir. Verifique as dimensões de cada imagem para confirmar o redimensionamento.
#
# * 240 x 240
# * 120 x 120
# * 60 x 60
# * 30 x 30
# * (b) Plote as imagens redimensionadas utilizando subplots e comente os resultados observados.
# * (c) Comente os resultados obtidos.
# In[ ]:
# IMPLEMENTE O SEU CÓDIGO AQUI -> QUESTÃO 7 - LETRA (a)
# In[ ]:
# IMPLEMENTE O SEU CÓDIGO AQUI - QUESTÃO 7 - LETRA (b)
# ## Resposta da Questão 7:
#
# * Adicione sua resposta aqui.
# ***
# 