Instituto de Computação da UNICAMP
Disciplina MC202: Estruturas de Dados

2° Semestre de 2005

Prof. Ricardo da Silva Torres e Prof. Sandro Rigo

Laboratório Nº 03


Descrição:

Imagem

Uma imagem digital em tons de cinza é um par (DI, I), onde DI é um conjunto de pontos do Z2, denominados pixels (picture elements), e I é um mapeamento que associa a cada pixel p em DI um valor escalar que está associado a alguma propriedade física. No caso de uma foto digital, o valor I(p) representa o brilho, onde um valor alto é um pixel claro e um valor baixo é um pixel escuro. O número de níveis de cinza possíveis é dado por 2b, onde b é chamado profundidade da imagem em bits (e.g., b = 8, profundidade de 8 bits).
A imagem é portanto uma matriz de tamanho N x M pixels (N linhas e M colunas), e pode ser armazenada como um vetor, onde o índice i que relaciona cada pixel p = (x,y) é dado por:

i = x + M * y
para x = 0..M-1 e y = 0..N-1.

As posições x e y de um pixel da posição i do vetor podem ser obtidas por:

x = i % M
y = i / M

Histograma e Histograma Acumulado

O histograma de uma imagem em tons de cinza é uma função h(L) que produz o número de ocorrências de cada nível de cinza 0 <= L <= 2b-1 na imagem. Ele representa a distribuição de probabilidade dos valores dos pixels. O histograma é normalizado em [0,1] quando dividimos h(L) pelo número N x M de pixels da imagem.
O histograma acumulado de uma imagem é uma função ha(L) que produz o número de ocorrências de níveis de cinza menores ou iguais a L, 0 <= L <= 2b-1.

Exemplo:

Imagem 4 x 4 com profundidade de 2 bits:
0130
1133
1030
3311

Representação como vetor:
0130113310303311

Histograma:
Nível de cinza0123
Histograma4606
Histograma normalizado0.250.37500.375
Histograma acumulado4101016
Histograma acum. normalizado0.250.6250.6251.0

Equalização de histograma

A equalização tem o objetivo de realçar a imagem, aproximando o histograma da imagem original para um histograma uniforme.
Para isso, usa-se o histograma acumulado normalizado. O nível de cinza I' de um pixel p na imagem equalizada é dado por:

I'(p) = hanorm(I(p)) * (2b-1)
onde I(p) é o nível de cinza do pixel p na imagem original, hanorm(I(p)) é o histograma acumulado normalizado do nível de cinza I(p) e b é a profundidade da imagem original.

O valor de I'(p) deve ser aproximado para o valor inteiro mais próximo, ou o maior valor inteiro mais próximo em caso de empate (e.g., 12.49 = 12, 12.51 = 13, 12.50 = 13).

Exemplo:

Imagem original Imagem equalizada

Negativo

Negativos de imagens digitais são úteis em diversas aplicações, tais como a exibição de imagens médicas. O negativo de um pixel p é dado por:

I'(p) = 2b-1 - I(p)
onde I(p) é o nível de cinza do pixel p na imagem original e b é a profundidade da imagem original.

Exemplo:

Imagem original Negativo

Segmentação por Limiarização (Threshold)

A segmentação consiste em particionar uma imagem em regiões de pixels relevantes para uma dada aplicação (i.e. objetos e fundo). Dado um valor de limiar t e profundidade da imagem b, a limiarização particiona a imagem em duas regiões, uma com os níveis de cinza entre 0 e t, e outra com níveis de cinza entre t+1 e 2b-1.
A imagem segmentada normalmente é uma imagem binária, onde os pixels com níveis de cinza entre 0 e t recebem o valor 0, e o restante dos pixels recebem o valor 1. Para facilitar a visualização, usaremos os valores 0 e 255.

Exemplo:

Imagem original Imagem segmentada
t = 228

Objetivo:

O objetivo deste laboratório é implementar um conjunto de funções para manipulação de imagens em tons de cinza. Estas funções usarão imagens no formato PGM P5 e P2 na leitura, e imagens no formato PGM P2 para impressão. O cabeçalho de imagens PGM é no formato texto, e possui a seguinte estrutura:

P5
320 240
255
...

A primeira linha indica o formato (P5 ou P2). A segunda linha indica o tamanho horizontal e vertical da imagem, e a terceira linha representa o número máximo de níveis de cinza. Neste laboratório usaremos sempre o valor 255. A partir da quarta linha seguem os brilhos dos pixels. Nas imagens P5, os brilhos estão no formato binário, e cada byte representa o brilho de um pixel. Nas imagens P2, os brilhos estão no formato texto, onde cada número inteiro representa o brilho de um pixel, e os brilhos estão separados por espaços em branco. Os valores de brilho começam na posição (0,0) no canto superior esquerdo e vão até a posição (M,N) no canto inferior direito.

Os comandos disponibilizados pela ferramenta para o usuário são:

ComandoDescrição
r nome_imagem.pgmCarrega na memória a imagem nome_imagem.pgm.
pImprime a imagem no formato PGM P2.
cLibera da memória a imagem carregada.
hImprime o histograma normalizado da imagem carregada na memória.
HImprime o histograma normalizado acumulado da imagem carregada na memória.
eEqualiza o histograma da imagem carregada na memória.
nCalcula o negativo da imagem carregada na memória.
t limiarLimiariza a imagem carregada na memória.
m Imprime a média dos níveis de cinza da imagem carregada na memória.
o x0 y0 x1 y1Recorta um retângulo representado pelos pontos (x0,y0) no canto superior esquerdo e (x1,y1) no canto inferior direito, e considera a região recortada como a nova imagem.
qSai do programa.

Implementação:

O laboratório consiste na implementação de duas bibliotecas: imagem.c e comandos.c. O interpretador de comandos principal.c é fornecido na íntegra e não deve ser modificado.

imagem.c

São fornecidos um arquivo imagem.h e um arquivo imagem.c. O primeiro contém a interface com os cabeçalhos das funções que deverão ser implementadas no arquivo imagem.c. Não é permitido modificar o arquivo imagem.h. A estrutura Image deve ser usada para armazenar a imagem na memória. Os brilhos dos pixels são representados pelo vetor de inteiros val.

comandos.c

O arquivo deverá conter a implementação dos comandos que foram descritos acima.


Execução:

Os caminhos das imagens PGM especificados nos arquivos de teste (arqN.in) devem ser modificados caso você queira testar o programa em sua máquina local.
O programa principal (interpretador de comandos) lê os comandos da entrada padrão, portanto para executar os testes a partir do arquivo de entrada é necessário redirecionar o arquivo para a entrada padrão do programa e eventualmente redirecionar a saída padrão do programa para um arquivo. Assim:

./principal < arqN.in > arqN.out

O arquivo de saída arqN.out pode ser posteriormente comparado com o arquivo de resposta esperado (arqN.res) visualmente ou através do comando diff:

diff arqN.out arqN.res

Para esse laboratório, será fornecido também um arquivo Makefile para facilitar a compilação do programa e execução dos testes.


Entrada e saída:

A entrada do programa consiste em uma seqüência de comandos. Espaços em branco serão ignorados.
A impressão do histograma deve ser uma sequência de 28 números com precisão de 4 casas decimais, separados por um espaço em branco.
A impressão da imagem P2 deve seguir o cabeçalho mencionado acima, e possuir 10 valores inteiros de brilho por linha. Por exemplo, a seguinte entrada:

r lena.pgm
m
c
q

Gera a saída:

127.1564

E a entrada:

r lena.pgm
p
c
q

Gera a saída:

P2
192 192
255
163 164 165 165 163 161 160 160 158 159
157 158 159 162 166 169 172 175 174 170
166 156 140 118 102 98 102 106 109 111
112 110 115 112 114 113 113 111 110 114
120 122 123 127 126 131 129 133 135 135
136 138 137 134 132 132 133 134 136 137
... removido do exemplo ...

A impressão da imagem P2 pode ser redirecionada para um arquivo com extensão .pgm, e a imagem pode ser visualizada na maioria das aplicações gráficas, como Gimp, ImageMagick e QIV.


Testes:

Os testes estarão classificados em 3 grupos, que testam as funções em ordem crescente de dificuldade.


Observações adicionais:

1. Devem ser submetidos apenas os arquivos imagem.c e comandos.c.

2. A sua última submissão deve incluir todos os casos.

3. O número máximo de submissões não pode passar de 20.


Referência:

R. C. Gonzalez and R. E. Woods, Digital Image Processing, Addison-Wesley, 1992