#!/usr/bin/env python # coding: utf-8 # ![banner-pdi](https://user-images.githubusercontent.com/58775072/141189378-b5df3287-e8c0-48a1-ad11-825ba317463b.png) # ## 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. # *** # ![image](https://user-images.githubusercontent.com/58775072/142712576-857585e2-09a4-49a2-92cd-17507e2e2fc9.gif)