Diferenças

Aqui você vê as diferenças entre duas revisões dessa página.

Link para esta página de comparações

c:fotomosaico [2023/08/01 19:12] – criada mazieroc:fotomosaico [2023/08/01 19:20] (atual) – edição externa 127.0.0.1
Linha 1: Linha 1:
 +====== Fotomosaico ======
 +
 +{{ progc_proj_fotomosaico.mkv|Video deste projeto}}
 +
 +{{ photomosaic.jpg?800 |https://commons.wikimedia.org/wiki/File:Photomosaic_WLM2014_Winner.png}}
 +
 +Um [[https://en.wikipedia.org/wiki/Photographic_mosaic|fotomosaico]] ou mosaico fotográfico é uma fotografia construída a partir de imagens menores, ou "pastilhas" (do inglês //tiles//). As pastilhas são escolhidas de forma a reproduzir a cor e intensidade luminosa do bloco da imagem original correspondente, gerando um efeito visual muito interessante.
 +
 +===== O formato PPM =====
 +
 +Para facilitar a leitura e escrita dos arquivos de imagem, neste projeto será adotado o formato de imagem  [[https://en.wikipedia.org/wiki/Netpbm_format|Portable PixMap]] (PPM), um formato de imagem colorida bem simples e fácil de ler/escrever. Boa parte dos programas de tratamento de imagens reconhece o formato PPM.
 +
 +A estrutura básica de um arquivo PPM é bem simples:
 +
 +<code>
 +TYPE                    (tipo de imagem: P3 ou P6, vide abaixo)
 +WIDTH HEIGHT            (largura e altura da imagem em pixels)
 +MAX                     (valor máximo de cada cor)
 +R0 G0 B0 R1 G1 B1 ...   (valores Red/Green/Blue de cada pixel, entre 0 e MAX)
 +</code>
 +
 +<note important>
 +Existem duas variantes do formato PPM: //PPM ascii// (P3) e //PPM binary// (P6); **ambas** devem ser tratadas neste projeto. Mais detalhes sobre essas variantes podem ser obtidas [[http://netpbm.sourceforge.net/doc/ppm.html|nesta página]].
 +</note>
 +
 +Um exemplo de imagem PPM ascii (P3):
 +
 +<code ppm flower.ppm>
 +P3
 +# this is a comment
 +10 10
 +255
 +255 255 255 255 255 255 255 255 255 255 255 255 255 254 254 255 254 254 255 254 254 255 255 255 255 255 255 255 255 255 
 +255 255 255 255 255 255 255 255 255 238 215 214 218 145 145 213 120 119 241 224 224 254 253 253 255 255 255 255 255 255 
 +255 255 255 255 255 255 236 209 209 217 60 59 219 52 53 222 56 56 215 56 55 229 184 183 255 254 254 255 255 255 
 +255 255 255 255 254 254 209 103 103 224 54 55 239 96 47 236 86 46 228 58 57 213 126 126 255 254 254 255 255 255 
 +255 255 255 255 255 255 209 93 93 228 55 56 240 120 41 238 99 44 229 59 59 213 123 123 255 254 254 255 255 255 
 +255 255 255 255 255 255 217 151 151 220 53 52 233 60 59 225 53 53 218 57 57 230 191 191 255 254 254 255 255 255 
 +255 255 255 255 255 255 250 246 245 208 183 158 200 94 84 181 123 94 201 165 133 229 234 203 255 255 255 255 255 255 
 +255 255 255 255 255 255 253 253 251 192 210 139 127 169 65 122 166 64 156 186 87 229 236 204 255 255 255 255 255 255 
 +255 255 255 255 255 255 255 255 255 254 254 253 172 200 141 201 220 182 254 254 253 255 255 255 255 255 255 255 255 255 
 +255 255 255 255 255 255 255 255 255 255 255 255 250 251 248 253 254 253 255 255 255 255 255 255 255 255 255 255 255 255 
 +</code>
 +
 +Você pode usar as imagens que quiser neste projeto. Para perceber melhor o efeito de mosaico, use imagens de grandes dimensões (acima de 3000 pixels de largura). Para gerá-las, pode usar qualquer editor de imagens que ofereça a possibilidade de "salvar como" PPM. No Linux, os softwares Gimp e GThumb oferecem essa opção.
 +
 +===== Atividade =====
 +
 +Construir um programa em C (C99 ou similar) que leia uma imagem de entrada em formato PPM e gere como saída essa mesma imagem convertida em mosaico, no mesmo formato e dimensões da imagem de entrada, usando as pastilhas disponíveis em um diretório informado.
 +
 +A estratégia básica de composição do mosaico é simples:
 +
 +  - Consideram-se pastilhas quadradas, todas com N×N pixels (o programa deve descobrir N e se ajustar a ele)
 +  - Percorrer o diretório informado e carregar todas as pastilhas.
 +  - Para cada pastilha, calcular sua cor predominante.
 +  - Abrir/carregar imagem de entrada (PPM raw ou ascii).
 +  - Para cada bloco de N×N pixels da imagem de entrada:
 +    - Calcular a cor predominante do bloco: [ R<sub>med</sub> G<sub>med</sub> B<sub>med</sub> ].
 +    - Substituir o bloco pela pastilha que tenha a cor predominante mais próxima.
 +  - Salvar a imagem de saída no mesmo formato da imagem de entrada (PPM raw ou ascii).
 +
 +A **cor predominante de um bloco** pode ser calculada pela média simples das componentes RGB dos pixels que compõem esse bloco. [[https://sighack.com/post/averaging-rgb-colors-the-right-way|Alguns autores sugerem]], no entanto, usar a raiz quadrada da média dos quadrados das componentes RGB para obter um resultado mais preciso. A mediana das componentes RGB também pode trazer bons resultados.
 +
 +A **distância entre duas cores** A = [ R<sub>A</sub> G<sub>A</sub> B<sub>A</sub> ] e B = [ R<sub>B</sub> G<sub>B</sub> B<sub>B</sub> ] é relativamente complexa de calcular, pois as cores não se comportam de forma linear para os olhos humanos. Uma fórmula simplificada de cálculo no padrão RGB é a distância //Red Mean//, descrita [[https://en.wikipedia.org/wiki/Color_difference|nesta página]].
 +
 +<note warning>
 +Um dos objetivos deste projeto é capacitar o aluno na leitura e análise de arquivos de dados ASCII e binários, por isso o uso de bibliotecas externas para leitura dos arquivos de imagem **não será aceito** (Netpbm, OpenCV e similares).
 +</note>
 +
 +==== Forma de chamada ====
 +
 +<code>
 +$ mosaico [ -p diretório ] [ -i arquivo ] [ -o arquivo ]
 +</code>
 +
 +Opções:
 +
 +  * ''-i'' : indica a imagem de entrada; se não for informada, assume-se a entrada padrão (//stdin//).
 +  * ''-o'' : indica a imagem de saída; se não for informada, assume-se a saída padrão (//stdout//).
 +  * ''-p'' : indica o diretório de pastilhas; se não for informado, assume-se o diretório ''./tiles''.
 +  * ''-h'' : gera uma mensagem de ajuda na saída de erro (//stderr//), explicando o que o programa faz e quais as opções disponíveis.
 +  * Todas as mensagens de erro devem ser enviadas para a saída de erro (//stderr//).
 +
 +Essas opções podem ser usadas em qualquer ordem:
 +
 +<code>
 +// entrada e saída em arquivos
 +mosaico -i input.ppm  -o output.ppm
 +mosaico -o output.ppm -i input.ppm
 +
 +// entrada em arquivo, saída em stdout, vice-versa ou ambos
 +mosaico -i input.ppm  > output.ppm
 +mosaico -o output.ppm < input.ppm
 +mosaico <  input.ppm  > output.ppm
 +
 +// as opções podem estar em qualquer ordem
 +mosaico -p /tmp/tiles -i input.ppm -o output.ppm
 +mosaico -i input.ppm -p /tmp/tiles -o output.ppm
 +mosaico -o output.ppm -i input.ppm -p /tmp/tiles
 +</code>
 +
 +O programa deve indicar sua atividade  (em ''stderr''):
 +
 +<code>
 +Reading tiles from ./tiles
 +1419 tiles read
 +Tile size is 20x20
 +Calculating tiles' average colors
 +Reading input image
 +Input image is PPM P3, 3000x4496 pixels
 +Building mosaic image
 +Writing output file
 +</code>
 +
 +===== Requisitos =====
 +
 +  * O executável deve se chamar ''mosaico''.
 +  * O programa deve aceitar como entrada uma imagem no formato PPM (P3 e P6, plain e raw) e gerar como saída uma imagem no mesmo formato e dimensões da entrada: se entrar uma imagem PPM //raw// deve sair uma imagem PPM //raw// e vice-versa.
 +  * As pastilhas a usar para a construção do mosaico são imagens em formato PPM fornecidas pelo professor e colocadas em um diretório separado (por default ''./tiles/'').
 +  * Sempre que possível, as informações da imagem necessárias às funções devem ser transferidas como parâmetros (por valor ou por referência, dependendo da situação); o uso de variáveis globais deve ser minimizado.
 +  * Use ''structs'' e alocação dinâmica de memória para todas as imagens; só aloque a memória para os pixels após encontrar o tamanho da imagem.
 +  * Construir um Makefile para o projeto:
 +    * Ao menos os alvos ''all'' (default), ''clean'' e ''purge''.
 +    * ''CFLAGS = -Wall''
 +    * Compilar e ligar separadamente (gerar os arquivos-objeto intermediários)
 +  * O que deve ser entregue ao professor:
 +    * código-fonte
 +    * ''Makefile''
 +    * Por favor, não envie as imagens de teste! m(
 +
 +===== Leitura de diretório =====
 +
 +Para carregar as pastilhas, você terá de percorrer o diretório de pastilhas, encontrar os nomes de todos os arquivos e ler as imagens contidas neles. Existem funções específicas em C para manipular diretórios, que são descritas [[pua:operacoes_em_diretorios|nesta página]].
 +
 +<note warning>
 +Não use funções como ''system()'' e ''popen()'' para varrer o diretório de pastilhas usando comandos do //shell//. Essas funções lançam processos externos e são **ineficientes** e **inapropriadas ** neste caso, pois existem funções adequadas para resolver o problema dentro da própria linguagem C.
 +</note>
 +===== Pastilhas =====
 +
 +Coleções de pastilhas prontas para uso:
 +
 +  * {{tiles20.zip|20x20 pixels}}, PPM P3 e P6
 +  * {{tiles32.zip|32x32 pixels}}, PPM P6
 +  * {{tileslol.zip |Tiles League of Legends}}, contribuição de João Lucas Cordeiro
 +  * {{minecrafttiles.zip |Tiles Minecraft}}, contribuição de Gabriel Dolzan e Dante dos Santos
 +
 +Para os curiosos, o procedimento que usei para a construção dessas coleções de pastilhas foi o seguinte:
 +
 +  - Limpar o cache do navegador web (usei o Firefox).
 +  - Fazer uma ou mais buscas no //Google Images// com o tema de interesse (por exemplo "flower"); deslizar várias páginas na busca, para carregar bem o cache com as miniaturas das imagens.
 +  - Copiar os arquivos do cache do navegador (em ''$HOME/.mozilla/.../cache/'') para um diretório separado e remover os que não forem imagens ou não forem relacionados ao tema de interesse.
 +  - Converter as imagens para formato PPM (//raw// ou //ascii//), ajustando ao tamanho desejado (32×32 neste exemplo) e cortando os excessos para ficarem quadradas (o comando ''mogrify'' faz parte do pacote [[https://imagemagick.org/index.php|ImageMagick]]):<code>$ mogrify -format ppm -thumbnail 32x32^ -gravity center -extent 32x32 *</code>
 +  - Para obter imagens em formato PPM ASCII, adicionar os flags ''-compress none''
 +
 +Fonte: [[https://superuser.com/questions/275476/square-thumbnails-with-imagemagick-convert]]