Programa Mosaico: Recortando e Construindo Imagens com C
Sobre o programa
Uma imagem é, em geral, representada por uma matriz em que cada posição contém a informação de cor (RGB ou tons de cinza) de um pixel (ponto) da imagem. Um dos formatos para representação de imagens em tons de cinza é o PGM. Este formato, simplificadamente, consiste de um arquivo com um cabeçalho em formato ASCII e um corpo em formato binário, contendo a seguinte informação:
Cabeçalho (em ASCII):
Corpo:
Deseja-se fazer mosaicos com imagens PGM. Um mosaico é construído pela composição de diversas imagens. Assim, deve ser possível efetuar operações para adicionar, mover, e retirar os componentes do mosaico, e uma operação que gere a imagem resultante.
Entrada de dados
Os dados de entrada do programa consistem de arquivos de imagens no formato PGM.
Execução do Programa
O pacote de software a ser construído consiste do programa mosaico , que deve ser executado da seguinte forma:
mosaico [opções] [parâmetros...]
Uma das seguintes opções devem ser fornecidas ao programa:
-a adiciona uma imagem ao mosaico em uma certa posição deste.
O uso desta opção exige 4 parâmetros obrigatórios:
Se já existir uma imagem no mosaico com o mesmo valor de id, a imagem existente deve ser substituída pela imagem nova.
-m move uma imagem dentro do mosaico.
Com esta opção, devem ser fornecidos 3 parâmetros:
-r remove uma imagem do mosaico. Esta opção pede como único parâmetro o identificador id da imagem a ser removida;
-p gera a imagem do mosaico em formato PGM. Deve ser fornecido neste caso um nome de arquivo onde a imagem do mosaico será armazenada. A ordem de sobreposição é a ordem crescentes dos identificadores id: imagens id’s pequenos ficam sob imagens com id’s maiores;
A dimensão final da imagem do mosaico depende da posição das diversas imagens colocadas no mosaico e deve ser calculada pelo programa. Nos espaços entre as imagens inseridas a cor deve ser definida como a média dos valores MAXVAL das imagens que compõem o mosaico.
Além do arquivo com a imagem final do mosaico montado, quaisquer dados intermediários (usados para controlar as operações acima) que devam ser persistentes em disco devem ser armazenados em um único arquivo. Cada uma das operações acima (com excessão de -p) deve ser efetivada em tal arquivo.
Finalmente, se houver algum erro durante as operações, o programa deve terminar ou prosseguir conforme a gravidade do erro, mostrando mensagens de erro adequadas ao usuário. Lembre-se que mensagens de erro devem ser enviadas para a saída padrão de erros.
Resultados do Programa
O resultado da execução do programa mosaico deve ser um arquivo com a imagem do mosaico conforme gerada pela opção -p.
Documentação
O pacote deve conter um arquivo de documentação em texto plano (ASCII). Este arquivo, chamado LEIAME, deve conter as seguintes informações:
Além disso, o código fonte deve estar documentado de acordo com o padrão aceito pelo doxygen. A documentação html deve ser gerada a partir da execução deste comando via make.
Arquivo Makefile
O arquivo Makefile deve possuir as regras necessárias para compilar os módulos individualmente e gerar o programa executável. As seguintes regras devem existir obrigatoriamente:
Arquivos Fonte
O programa deve ser implementado exclusivamente em linguagem C , e deve ser composto de no mínimo 3 (três) módulos, sendo obrigatória a criação do módulo mosaico.c. Este módulo deve conter apenas a função main() e diretivas #include e #define que se fizerem necessárias.
As definições de macros, tipos de dados, estruturas e protótipos de funções devem estar em arquivos de cabeçalho (extensão .h). A implementação das diversas funções do software deverá estar em arquivos com extensão .c.
Critério de Avaliação
Legibilidade, elegância, eficiência, modularidade, coesão e acoplamento entre módulos, e uso adequado de estruturas de dados serão levados em conta na avaliação.
Os algoritmos de manipulação das estruturas de dados (inserção, ordenação, etc.) devem ser tão eficientes quanto possível, usando todos os conceitos vistos nas disciplinas de Algoritmos do Curso. Ponteiros e alocação dinâmica de memória devem ser usados onde for eficiente e conveniente. Estruturas dinâmicas abordadas em Alg II, devidamente utilizadas, colaboram fortemente para uma avaliação positiva.
Caso seu programa possua bugs conhecidos, descreva-os no arquivo LEIAME. A documentação de um bug pode evitar que o grupo receba nota Zero. Os itens de avaliação do trabalho e respectivas pontuações são:
Dica: Para transformar uma imagem PGM para PPM, basta replicar o valor do pixel PGM para os três componentes de cor no formato PPM.
Arquivo LEIAME
Arquivos
=======================================
LEIAME Este arquivo
Doxyfile Arquivo de configuração do doxygen(1)
Makefile Arquivo com diretivas para make(1)
src/ Diretório contendo arquivos com código-fonte
bin/ Diretório com o executável (criado após `make install')
html/ Diretório com a documentação do doxygen (criado após `make doc')
Compilação
=======================================
Para compilar o código-fonte digite
$ make
Para instalar o programa use
$ make install
Para gerar a documentação use
$ make doc
Para compilar, instalar e gerar a documentação use
$ make all
ou
$ make tudo
Para limpar use
$ make clean
ou
$ make limpa
ou
$ make faxina
Exemplos de uso:
$ bin/mosaico -a 1 arquivo0.pgm 0 0
$ bin/mosaico -a 2 arquivo1.ppm 10 10
$ bin/mosaico -m 1 3 3
$ bin/mosaico -p mosaico.ppm
Algoritmos, estrutura de dados e implementação
=======================================
1 Banco de dados
-----------------
O banco de dados é divido basicamente em duas partes:
1) Metainformações (sobre os dados).
2) Imagens (os dados);
+-----------------------------------+------------------+
| Imagens | Metainformações |
+-----------------------------------+------------------+
Banco de dados
1.1 Metainformações
--------------------
As metainformações contêm a posição de cada imagem no banco de dados, o número
idenficador da imagem, entre outros. Essas informações são alteradas a cada ação
no banco de dados, podendo aumentar ou diminuir (em bytes). Por isso, a escolha
de escrever as metainformações no final do arquivo evita movimentações
desnecessárias nos dados. Para adicionar uma imagem, por exemplo, basta ler as
metainformações em memória, escrever a nova imagem a partir do posição de início
das metainformações e, em seguinda, reescrever as metainformações, incluindo os
dados da nova imagem.
Internamente, as metainformações são dividas em duas partes: tabela com dados
sobre as imagens e número de imagens. O número de imagens é o último elemento de
todo o arquivo.
+---------------------+---+
| Tabela | N |
+---------------------+---+
Metainformações
A tabela, por sua vez, guarda em cada "linha" as seguintes colunas:
identificador da imagem (ID), posição da imagem no mosaico (coluna e linha),
posição do início dos dados da imagem no banco de dados e tamanho da imagem no
banco de dados (em bytes).
+----+--------+-------+---------+---------+
| ID | Coluna | Linha | Posição | Tamanho |
+----+--------+-------+---------+---------+
| | | | | |
+----+--------+-------+---------+---------+
Tabela
1.2 Imagens
------------
As imagens no banco de dados são guardadas em sequência, uma após a outra. Cada
imagem é dividida em duas partes: o cabeçalho e a grade de pixels.
???
Ao final, o arquivo de banco de dados é organizado como na representação
abaixo.
+-------------------------+----------+
| 00000000000000000000000 | 11111111 |
+----------+-----------+--+----------+
| 11111111 | 222222222 | 33333333333 |
+----+-----+-----------+-------------+
| 33 | 44444444444444444444444444444 |
+----+---+---------------------+-----+
| 444444 | Tabela | N |
+--------+---------------------+
1.2.1 Formatos das imagens
---------------------------
Os possíveis tipos de imagens aceitas pelo mosaico são Portable Gray Map
(PGM) e Portable Pixel Map (PPM). Estes formatos podem ser ter duas versões:
em texto puro ou em binário. Os formatos e versões são representados no
cabeçalho do arquivo da imagem por um "número mágico". Abaixo, uma tabela
com todos os números mágicos para as imagens conhecidas como Portable AnyMap
(PNM):
+---------+------------+-----------+
| formato | texto puro | binário |
+---------+------------+-----------+
| PBM | P1 | P4 |
| PGM | P2 | P5 * |
| PPM | P3 | P6 * |
+---------+------------+-----------+
Números mágicos
Atualmente o mosaico aceita apenas os formatos P5 e P6.
Cada versão de imagem em binário tem ainda duas variações, dependendo do valor
máximo dentro da imagem, MAXVAL. Se MAXVAL for maior que 255, então cada valor
da matriz da imagem será representado por dois bytes; caso contrário, apenas um
byte. Não são permitidos valores maiores que 65535.
A generalização dos formatos pode ser feita considerando que cada pixel é um
"bloco". Esses blocos, por sua vez, são compostos por "elementos". Dependendo do
valor de MAXVAL esses elementos podem ter tamanho de 1 ou 2 bytes. O número de
elementos de cada bloco pode ser 1 ou 3, dependendo se a imagem é em escala de
cinza ou em cores. Resumindo em termos de blocos e elementos, as possíveis
combinações aceitas pelo mosaico são as seguintes:
+--------+------------+------------+------------+
| mágico | núm. elem. | tam. elem. | tam. bloco |
+--------+------------+------------+------------+
| P5 | 1 | 1 | 1 |
| P5 | 1 | 2 | 2 |
| P6 | 3 | 1 | 3 |
| P6 | 3 | 2 | 6 |
+--------+------------+------------+------------+
Formatos aceitos pelo mosaico
1.2.2 Conversões das imagens
-----------------------------
O mosaico, imagem final gerada pela composição das imagens no banco de dados,
precisa ter o como MAXVAL o maior valor de todas as imagens, tamanho de elemento
igual ao maior tamanho de todas as imagens e número de elementos igual ao maior
número de elementos das imagens.
Como todas as imagens finais, que serão coladas no mosaico, precisam ter o mesmo
tamanho de bloco. Essa condição resulta nas possíveis conversões:
tam. bloco da imagem tam. de bloco do mosaico
1 -----> 2
1 -----> 3
1 -----> 6
2 -----> 6
3 -----> 6
A conversão 2->3 não acontece, pois caso existam imagens como tamanho de bloco 2
e 3 dentro do banco de dados o mosaiso terá tamanho de bloco 6.
Cada imagem é armazenada em arquivo em formato sequencial, linha a linha. E
desta mesma forma elas são lidas para a memória. Portanto, essas conversões
podem ser visualizadas mais detalhadamente desenhando os blocos de bytes.
+---+ +---+---+
1->2 | v | -----> | 0 : v |
+---+ +---+---+
+---+ +---+---+---+
1->3 | v | -----> | v : v : v |
+---+ +---+---+---+
+---+---+ +---+---+---+---+---+---+
2->6 | 0 : v | -----> | 0 : v : 0 : v : 0 : v |
+---+---+ +---+---+---+---+---+---+
+---+---+---+ +---+---+---+---+---+---+
3->6 | r : g : b | -----> | 0 : r : 0 : g : 0 : b |
+---+---+---+ +---+---+---+---+---+---+
Nesse desenho, cada quadrado separadado por ":" representa um byte e separado
por "|" representa um bloco. "v" é usado para valor em escala de cinza e "r",
"g" e "b" para cores. A conversão de escala de cinza para cores é feita com a
repetição do valor em cinza no tripleto vermelho, verde e azul.
Download
O programa pode baixado aqui.


