Ir para o conteúdo principal
Paca
  • Página inicial
  • Mais
Você acessou como visitante
Acessar
Página inicial
  1. Semestres anteriores
  2. MAC0122 2016
  3. EP9
Tarefa

EP9

Condições de conclusão
Vencimento: domingo, 20 nov. 2016, 23:55

EP9 - Processamento de Imagens Digitais: detectando e realçando bordas

``Uma imagem vale mais que mil palavras.'',
Provérbio chinês.

Objetivos

Neste exercício programa você vai treinar um pouco o uso de arrays em Python, como definido no módulo Numpy. Para isso, você vai desenvolver um programa que manipula imagens digitais representadas na forma de Numpy arrays.

  • uso de objetos: usar arrays em programas em Python;
  • criação e manipulação de arrays;
  • uso de objetos que contém arrays;
  • representar imagens usando arrays; e
  • processar imagens digitais usando de filtros de convolução.

O que é uma imagem digital?

Uma imagem digital ou simplesmente imagem é basicamente uma matriz, com, digamos, altura height (número de linhas) e largura width (número de colunas). Cada elemento da matriz é chamada de pixel (picture element), que possui uma "cor".

Na sua forma mais básica um pixel pode ser representado por 1 bit (= dígito binário) para armazenar quando o pixel está aceso ("branco") ou apagado ("preto"). As imagens em que cada pixel possui apenas um dentre dois "níveis" possíveis são chamadas de imagens binárias. Em geral, no entanto, dois nívels são insuficientes para representar o que costumamos chamar de imagens em preto e branco, pois estas, em geral, possuem vários níveis ou tons de cinza. Uma forma comum de representar uma imagem com vários tons de cinza é reservando um byte (8 bits) para cada pixel. Desta forma podemos representar imagens com até 256 níveis de cinza por pixel. Chamamos as imagens em que cada pixel pode ter vários tons de cinza de imagens com níveis de cinza.

Uma imagem com níveis de cinza nos permite ver as variações de luminosidade da cena. Já uma imagem colorida requer ainda mais informação para cada pixel. Baseado no sentido da visão humana, que é tricromática, a representação de imagens mais comum é obtida decompondo uma cor nas componentes básicas red (vermelho), green (verde) e blue (azul) ou RGB. Assim, usando 1 byte para representar cada cor primária (vermelho, verde e azul), podemos representar todo o espéctro visivel de cores. Nesse EP vamos adotar o método True Color (24 bits) para representar imagens coloridas.

Transformando uma imagem colorida para níveis de cinza

Nesse EP, uma imagem colorida será uma matriz de pixeis, onde cada pixel é um outro array com 3 valores representado as intensidades das componentes R (vermelho), G (verde), e B (azul), respectivamente. No formato True Color Vamos usar um inteiro de 8 bits para representar cada intensidade, ou seja, um número de 0 a 255. Assim, a cor vermelha será presentada pela lista [255,0,0], a cor verde por [0,255,0] e a cor branca, que é formada pela combinação de todas as cores, será [255,255,255]. Observe que podemos considerar cada canal separadamente (R, G, ou B) como uma imagem em níveis de cinza.

Para converter uma imagem colorida em níveis de cinza você deve utilizar a regra de Luminância Relativa definida pela seguinte fórmula:


          L = 0.2126 R + 0.7152 G + 0.0722 B

Onde L é a imagem com níveis de cinza resultante da imagem colorida formada por R, G e B.

Convolução

A operação de convolução é muito utilizada para processar imagens e pode ser matematicamente representada por


          C = I * F

Onde C é uma imagem resultado da convolução (operador *) da imagem de entrada I por um filtro F. Vamos assumir que as imagens C e I são imagens com níveis de cinza e o filtro é uma matriz 2D de números reais. O filtro representa uma transformação que é aplicada na imagem I e tem forma quadrada de ordem ímpar, ou seja, é uma matriz 3 × 3, 5 × 5, 7 × 7 etc. Você deve assumir que um filtro tem tamanho ímpar pois assim sempre há um elemento central. O filtro só deve ser aplicado em posições [lin,col] válidas da imagem.

Uma posição é válida se, quando o ponto central do filtro F for colocado em [lin,col], todos os elementos do filtro possuem um elemento correspondente na imagem, ou seja, o filtro não pode ser aplicado fora da imagem. As posições inválidas ocorrem nas primeiras e últimas linhas e colunas da imagem. A imagem resultado da convolução C deve receber 0 (zero) nas posições inválidas.

Para cada posição válida, o resultado da convolução C[lin,col] é calculado como a soma da multiplicação elemento a elemento do filtro F na posição [lin,col] pelo conteúdo correspondente da imagem.

As imagens a seguir ilustram a operação de convolução. Na imagem da esquerda, kernel representa o filtro, input faz as vezes da imagem em níveis de cinza, o pixel azul escuro é o da posição do ponto central [lin,col] e o pixel em vermelho representa o valor resultado da convolução. A imagem da direita apresenta um exemplo numérico de convolução. Ambas as imagens foram copiadas de River Trail documentation.

   

Detecção de Bordas

Para treinar o uso de objetos com arrays nesse EP vamos detectar e realçar bordas em imagens. De uma maneira geral, os algoritmos para detecção de bordas (edge detection) procuram identificar os pixels da imagem em que há uma mudança brusca ou descontinua na luminosidade (luminous intensity) (ou seja, em uma imagem com níveis de cinza).

Para determinar se um pixel [lin,col] é de borda, primeiramente utilizaremos o filtro de Sobel (Sobel operator). No método será necessário o cálculo de duas grandezas, os chamados gradientes horizotal gH e o gradiente vertical gV para cada pixel [lin,col]. A seguir denotaremos por L[lin,col] a luminosidade relativa de um pixel [lin,col]. Os valores de gH e gV em cada pixel (válido) [lin,col] serão calculados da seguinte maneira:


          gH[lin,col] =    L[lin-1,col+1] + 2*L[lin,col+1] + L[lin+1,col+1]
                         - L[lin-1,col-1] - 2*L[lin,col-1] - L[lin+1,col-1]

          gV[lin,col] =    L[lin+1,col-1] + 2*L[lin+1,col] + L[lin+1,col+1] 
                         - L[lin-1,col-1] - 2*L[lin-1,col] - L[lin-1,col+1]

Observe que gH e gV são imagens resultantes da convolução da imagem L com os filtros de Sobel Sh (horizontal) e Sv (vertical), mostrados abaixo:


               0    1    2                 0    1    2 
            +----+----+----+            +----+----+----+
          0 | -1 |  0 | +1 |          0 | -1 | -2 | -1 |
            +----+----+----+            +----+----+----+
          1 | -2 |  0 | +2 |          1 |  0 |  0 |  0 |
            +----+----+----+            +----+----+----+
          2 | -1 |  0 | +1 |          2 | +1 | +2 | +1 |
            +----+----+----+            +----+----+----+

          Sh para cálculo de gH       Sv para cálculo de gV

Após calculadas as componentes gH e gV, cada pixel deve ser classificado como borda caso o módulo do seu gradiente seja maior que um limiar, ou seja, pixels de borda são aqueles que satisfazem a seguinte condição:


          sqrt(gH * gH + gV * gV) > limiar,

em caso contrário, o pixel não é de borda.

 


O que você deve fazer?

Você deve implementar os seguintes métodos dentro da classe Imagem no arquivo esqueleto_ep9.py.

  • para_cinza
  • binarize
  • filtre
  • pinte
  • segmente_bordas

As especificações desses métodos estão no arquivo esqueleto_ep9.py.

Observe que a classe Imagem já tem vários métodos implementados que você pode utilizar, mas você não deve modificá-los.

 


Exemplos de execução do programa principal

Nesse EP, o programa principal pede ao usuário o nome de uma imagem no formato PNG (ou seja, arquivo com extensão .png), o nome do arquivo imagem de saída (também com extensão .png) e o valor de um limiar utilizado para segmentar as bordas. Quanto mais alto o limiar, menos bordas o programa deve segmentar. As imagens intermediárias são exibidas em janelas, que o usuário deve fechar para que o programa prossiga. Cada borda segmentada é realçada (pintada) e, ao final, o resultado é salvo na imagem de saída. Você pode alterar a função main para testar o seu EP, alterando parâmetros, cor de realce, filtros etc.

Como exemplo, você pode utilizar as imagens calouro-ime.png e ime-usp. Ao executar o programa para essas imagens teríamos:

     Digite o nome do arquivo de entrada [.PNG] >>> ime-usp.png
     Digite o nome do arquivo de saída   [.PNG] >>> saida2.png
     Digite o limiar desejado (int)             >>> 20
     Imagem de entrada:  ime-usp.png
     Feche a janela da imagem para continuar....

e o programa deve exibir a imagem de entrada em uma janela como abaixo:

Após fechar a janela, o programa continua com:

     Imagem das bordas segmentadas: 
     Feche a janela da imagem para continuar....

exibindo a imagem binária com as bordas:

e após fechar essa janela temos:

     Imagem com bordas realçadas 
     Feche a janela da imagem para continuar....

     Fim. A imagem realçada foi salva em  saida2.png

Rodando o programa para a imagem calouro-ime.png e o limiar 25 temos:

       

Roteiro

  • Faça o download do arquivo esqueleto_ep9.py.

  • Mude o nome do arquivo esqueleto_ep9.py para NUSP_ep9.py, onde NUSP é o seu número USP.

  • Abra o arquivo NUSP_ep9.py no Spyder ou em qualquer outro editor ou ambiente apropriado para desenvolver programas em Python. Esse é o único arquivo que você deve editar.

  • Leia e preencha o cabeçalho do arquivo com o seu nome, nusp, etc. Não modifique o resto do cabeçalho.

  • Implemente cada um dos métodos da classe Imagem e teste-os, usando imagens bem pequenas antes de usar imagens grandes. A operação de convolução é cara computacionalmente, e pode demorar bastante caso a imagem for grande.

  • Teste o seu programa com várias imagens diferentes.

  • Entregue o arquivo NUSP_ep9.py na página da disciplina.

  • Não deixe de seguir as Instruções para entrega de EPs.

 


Entrega

A entrega deve ser feita até o dia 20/11 (até 23h55m).
O EP receberá comentários até o dia 22/11.
Uma nova versão poderá ser entregue até o dia 23/11 (até 23h55m).

Você acessou como visitante (Acessar)
Resumo de retenção de dados
Baixar o aplicativo móvel.
Fornecido por Moodle