Tarefa 7 - Calculadora de imagens

Prazo de entrega recomendado:

Iremos construir um editor interativo de imagens capaz de realizar diversas operações, como destaque e aplicação de filtros. Para isso, será necessário manipular matrizes.


A visão é um dos sentidos mais complexos do ser humano. Ela permite capturar as mais diferentes imagens ao nosso redor. Nós percebemos essas imagens através da luz, que traz uma quantidade abundante de dados. Com o tempo, aprendemos a processar esses dados, identificar e classificar objetos de maneira tão simples, que encaramos a visão de maneira natural e a entendemos como um processo elementar.

Replicar esse processo com os computadores, no entanto, é desafiador. A primeira dificuldade ocorre ao representar uma imagem na memória de nosso computador, que nada mais é do que uma sequência de bits. Depois disso, ainda precisamos saber como processar esses dados para manipular a imagem e extrair informações.

Tradicionalmente, representamos uma imagem como uma matriz de pixels. Cada pixel corresponde a uma cor ou à intensidade da luz refletida em uma região pequenininha da imagem correspondente ao pixel. Assim, manipular essa imagem nada mais é do que realizar operações sobre essa matriz.

Nesta tarefa, representaremos imagens no formato PGM, que é utilizado para armazenar imagens em escala de cinza sem compressão de dados em um arquivo de texto. Nesse formato, uma imagem é uma matriz de inteiros no intervalo $[0, …, 255]$. Cada entrada da matriz representa a intensidade da luz em um determinado pixel, de forma que, quanto mais próximo de $0$, mais escuro é o pixel e, quanto mais próximo de $255$, mais claro ele é.

O formato PGM começa com uma linha com o texto P2, que representa uma imagem em escala de cinza. Depois, pode haver um comentário arbitrário, começando com # e a próxima linha deve conter dois números representando, respectivamente, a largura e a altura da matriz. Na próxima linha há o número $255$, que indica a intensidade do branco. Em seguida deve haver uma sequência de números inteiros, cada um representando uma entrada da matriz, lidos da esquerda para a direita e de cima para baixo. Abaixo, há uma imagem e o arquivo PGM correspondente.

[Arquivo content/tarefas/07-calculadora-imagens/mc102.pgm não existe]

Calculadora de imagens

Sua tarefa é construir um programa interativo calculadora_imagens.py capaz de carregar imagens de arquivos PGM da pasta dados, realizar operações sobre elas e gravar uma imagem resultante em um novo arquivo dentro da pasta teste. O programa mantém em memória um banco de imagens, cada uma identificada por um índice inteiro começando em $0$. Cada operação pode criar, acessar e modificar uma ou mais imagens desse banco de imagens.

Entrada

Cada linha da entrada conterá o nome de uma operação a ser realizada e uma sequência de parâmetros correspondentes. Por exemplo, a entrada abaixo carrega duas fotos na memória. A segunda foto é transformada em preto e branco utilizando um limiar de $50$. Em seguida, a primeira imagem é modificada, utilizando a segunda como máscara. Finalmente, a imagem resultante é gravada em um novo arquivo.

carregar dados/selfie.pgm
carregar dados/disco.pgm
binarizar 1 50
multiplicar 0 1
gravar testes/avatar.pgm 0

A seguir mostramos o que esta acontecendo nos passos anteriores.

carregar selfie.pgm carregar disco.pgm binarizar 1 50 multiplicar 0 1
selfi mascara binary multiplicar

Saída

A cada operação processada, deverá ser mostrada uma ou mais linhas na saída, dependendo do comando. A saída para o exemplo acima será.

Carregado arquivo dados/selfie.pgm em imagem 0.
Carregado arquivo dados/disco.pgm em imagem 1.
Imagem 1 modificada: 24244 pixels maiores que zero.
Imagem 0 modificada: 24244 pixels maiores que zero.
Gravado arquivo testes/avatar.pgm com imagem 0.

Operações pixel a pixel

Podemos realizar operações entre duas imagens pixel por pixel. Por exemplo, se multiplicamos as intensidades de duas imagens, alguns pixels terão a intensidade aumentada e outros, diminuída. Podemos usar essa operação para destacar determinadas regiões de uma imagem e esconder as demais. Também podemos realizar operações lógicas, como OR, AND, XOR, SUB. Elas servem como instrumento para extração de componentes da imagem, descrever formas de uma região, como fronteiras, esqueletos e fecho convexo.

Normalizar

Às vezes uma imagem pode estar muito escura porque todos os pixels são menores que 255; ou muito clara, porque todos os pixels são maiores que 0. Para ajustar o branco e o preto, podemos normalizar os valores dos pixels de uma imagem $A$ linearmente. Para isso, você deve descobrir os valores máximo e mínimo de intensidade na imagem e interpolar o valor de cada pixel de forma que o mais intenso seja $255$ e o mais escuro seja $0$. Descarte frações, caso a intensidade resultante da normalização não seja inteira.

Entrada

carregar dog.pgm
normalizar <id imagem a>

Saída

Imagem <id imagem a> modificada: xx pixels maiores que zero.

Binarizar

Dado um limiar, defina como 0 todos pixels com valor menor ou igual ao limiar e como 255 os demais.

Entrada

binarizar <id imagem> <limiar>

Saída

Imagem <id imagem> modificada: xx pixels maiores que zero.
carregar impressao.pgm binarizar 0 91
fingerprint fingerprint_bin

Multiplicar

Dadas duas imagens com as mesmas dimensões, modifique a primeira de forma que o novo pixel tenha o produto dos pixels correspondentes nas imagens originais. Repare que a imagem resultante pode ter pixels com intensidades maiores do que $255$.

Entrada

carregar dog.pgm
carregar mascara3.pgm
multiplicar <id imagem a> <id imagem b>

Saída

Imagem <id imagem a> modificada: xx pixels maiores que zero.
carregar dog.pgm mascara3.pgm multiplicar 0 1
dog mascara3 dog_mascara3

Somar

Computa a média dos pixels de duas matrizes de mesma dimensão, descartando a fração não inteira.

Entrada

somar <id imagem a> <id imagem b>

Saída

Imagem <id imagem a> modificada: xx pixels maiores que zero.
carregar dog.pgm carregar eiffel.pgm somar 0 1
dog eiffel_tower dog_eiffel

Operações lógicas

Realiza operações lógicas pixel por pixel entre duas imagens com a mesma dimensão e altera a primeira. Nessas operações, garantimos que todo pixel tem valor 0 ou 255, representando verdadeiro e falso, respectivamente.

Entrada

<OPERADOR> <id imagem a> <id imagem b>

O nome do comando pode ser entre OR, AND, XOR, SUB.

Saída

Imagem <id imagem a> modificada: xx pixels maiores que zero.
mc102

Filtros em imagens

Uma operação comum em imagens é a aplicação de filtros digitais. Abaixo, aplicamos diferentes filtros em uma imagem de exemplo, cada um com um objetivo.

coin
suavização de imagem remover ruído melhorar a imagem destacar bordas
blur noise enhance edge

Para aplicar um filtros, realizamos uma operação chamada convolução, que consiste em percorrer a matriz original sobrepondo cada pixel com uma matriz menor (chamada filtro ou kernel). Para computar o valor resultante em cada pixel, multiplicamos os pixels sobrepostos e somamos.

Suponha que o kernel seja a matriz à esquerda, enquanto a matriz à direita seja uma parte da imagem, representando os valores dos pixels. Neste momento, estamos calculando o pixel da posição cujo valor na imagem original é 25. O valor deste pixel na imagem com filtro, após a convolução, será

$$ a \times 10 + b \times 10 + c \times 10 + d \times 10 + e \times 25 + f \times 10 + g \times 10 + h \times 10 + i \times 10. $$

Quando realizamos esse procedimento em todos os pixels da imagem, temos a imagem filtrada.

A imagem filtrada deve substituir a imagem. Repare que não é possível aplicar o filtro nos pixels próximos da borda da imagem, quando o kernel não couber completamente sobre a imagem. Nesses casos, defina o pixel da imagem filtrada como preto.

Entrada

fitrar <id> <nome do filtro>

O <nome do filtro> define qual o kernel será utilizado. Você precisa implementar pelo menos o kernel Laplaciano (para detectar bordas). dado pela matriz $L$. Umo outro filtro comum é o Gaussiano (para suavizado), dado pela matriz $G$. Note que, após aplicar um filtro, o valor de um pixel pode ser negativo ou maior que $255$.

$$ L = \begin{pmatrix} -1 & -1 & -1 \\ -1 & 8 & -1 \\ -1 & -1 & -1 \end{pmatrix} $$

$$ G = \begin{pmatrix} 1 & 4 & 7 & 4 & 1 \\ 4 & 16 & 26 & 16 & 4 \\ 7 & 26 & 41 & 26 & 7 \\ 4 & 16 & 26 & 16 & 4 \\ 1 & 4 & 7 & 4 & 1 \end{pmatrix} $$

Saída

Imagem <id> modificada: xx pixels maiores que zero.

Dicas

Critérios

Para obter conceito B é obrigatório implementar pelo menos os comandos carregar, gravar, binarizar, normalizar, multiplicar e aplicar o filtro laplaciano. Para obter conceito A, implemente também as operações lógicas AND e SUB.

Correção

Esta tarefa será corrigida automaticamente sempre que você realizar um git push. Depois de terminada a tarefa, deve-se utilizar o botão na interface de notas para solicitar a correção de um monitor.