Trabalho 1 - Gerador de ASCII Art
Laboratório de Programação II - Prof. Marcelo Cohen
04/2014
1 Introdução
O uso de caracteres da tabela ASCII para produzir desenhos não é uma
idéia recente: vem de tempos longínquos, onde os dispositivos de saída
eram monitores monocromáticos e impressoras matriciais ou de linha. Mais
recentemente, se tornou uma forma de "arte" - daí o termo ASCII Art. Ou seja, imagens criadas exclusivamente com o uso de caracteres da tabelas ASCII.
O objetivo deste trabalho é explorar os conceitos de programação C/C++
vistos em aula, criando um programa capaz de produzir a representação de
uma imagem qualquer em ASCII. A saída do programa será na forma de um
arquivo HTML, que pode ser visualizado no browser.
Se você nunca viu isso (em que planeta estava nos últimos anos ?), há
diversos serviços na rede que fazem esse tipo de conversão:
O resultado pode ser visto na figura abaixo:
2 Funcionamento
Ao ser iniciado, o programa deve solicitar o nome de um arquivo de imagem, e carregá-lo. Para tanto, utilizaremos a biblioteca
SFML (
Simple and Fast Multimedia Library), que está disponível para Linux e Windows no projeto base fornecido (veja abaixo).
Parte do objetivo deste trabalho é a criação de um algoritmo que produza
um resultado interessante. Uma possível estratégia é a seguinte:
-
Obter do usuário o nome da imagem a ser carregada, e o fator de redução
desejado. Por exemplo, o fator 50% vai utilizar apenas metade dos pixels
originais na saída. Esse fator é usado para calcular o tamanho dos
blocos de pixels (ver passo 5).
-
Ler a imagem colorida, onde cada pixel (ponto da imagem) é representado em RGB.
-
Converter a imagem para tons de cinza, isto é, eliminar a cor e
considerar que qualquer pixel pode ser representado por um único número
inteiro, representando variações de preto (0) a branco (255).
-
Associar cada caractere a um tom de cinza específico. Você pode
pesquisar nos sites indicados (ou outros) para ver como isso normalmente
é realizado. Mas a idéia básica é que caracteres que ocupam mais espaço
visualmente correspondam a cores mais claras (considerando um fundo
preto). Por exemplo, "@" é mais "claro" do que "."
-
De acordo com as proporções das letras (que não são quadradas), agrupar os pixels
da imagem em blocos retangulares (por exemplo, 4 x 5). Cada bloco irá
se transformar em um único caractere na saída. Isso é necessário, pois
as imagens normalmente são muito grandes para fazer uma correspondência
1:1.
-
Calcular o tom de cinza médio de cada bloco (por exemplo, fazendo a média de todos os pixels do bloco).
-
Para cada bloco de pixels, escolher e gerar um caractere na saída, cujo tom de cinza é uma boa aproximação para a média do bloco.
As próximas seções dão algumas dicas de como realizar certas etapas.
Leitura da imagem
Para ler uma imagem usando a biblioteca SFML, use um código como segue:
#include <stdlib.h>
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
int main(int argc, char *argv[])
{
sf::Image imagem;
if (!imagem.loadFromFile("imagem1.png")) {
}
sf::Vector2u tam = imagem.getSize();
int largura = tam.x;
int altura = tam.y;
const sf::Uint8* pixels = imagem.getPixelsPtr();
}
Observe que a varíavel
imagem representa um objeto da classe
sf::Image, que contém os pontos da imagem (
pixels). Os pontos são armazenados em um
array, que deve ser acessado corretamente. Basicamente, cria-se uma função para acessar os
pixels
como se fosse uma matriz. O resultado deve ser separado nas componentes
R,G, B e A (vermelho, verde, azul, que definem a cor do
pixel; e A, que define a opacidade do pixel):
struct Pixel {
unsigned char r, g, b, a;
};
...
Pixel* img = (Pixel*) pixels;
cout << (int) img[0].r;
...
A partir daí, a imagem pode ser processada normalmente como um array de Pixel.
O arquivo
asciiart-lapro2ec.zip contém um projeto do
Code::Blocks com as bibliotecas necessárias para compilá-lo, mais algumas imagens de teste.
Conversão para Tons de Cinza
O processo de conversão de uma imagem para tons de cinza pode ser feito
com o algoritmo descrito abaixo. A idéia é simplicar a imagem, deixando
as três componentes R,G e B de cada ponto iguais entre si - equivale a
"tirar a cor" da imagem. O valor a ser colocado nestes 3 componentes
deverá ser igual à intensidade da cor, dada pela fórmula
Para cada ponto (x,y) da imagem:
Obtem a cor do pixel (r,g,b)
i = (0.3 * r + 0.59 * g + 0.11 * b)
EscreveCor(x,y, i,i,i)
Geração do HTML de saída
Para gerar o código HTML resultante, é preciso escrever determinadas tags no arquivo de saída, de forma que o browser saiba como interpretar os caracteres.
<html><head></head>
<body style="background: black;" leftmargin=0 topmargin=0>
<style>
pre {
color: white;
font-family: Courier;
}
</style>
Esse trecho define que o fundo será preto, enquanto os caracteres serão brancos, para o estilo pré-formatado (tag PRE). A partir deste ponto, a imagem deve aparecer dentro de um bloco <pre>...</pre>:
<pre>
... caracteres da imagem - linha 1 ...
... caracteres da imagem - linha 2 ...
...
</pre>
Finalmente, deve-se fechar o corpo da página e o HTML em si:
3 Requisitos
-
Devem ser utilizados os conceitos vistos até agora de programação em C/C++: classes e modularização de código.
-
Deve ser criada uma classe capaz de LER uma imagem qualquer, informada
como parâmetro, e também gerar um arquivo com o ASCII da imagem
armazenada. A classe deve conter métodos para realizar as diversas
etapas do processo. O programa principal deve apenas usar os métodos
dessa classe.
-
Deve ser entregue um artigo, contendo um resumo do problema e a
descrição detalhada da solução implementada (lógica utilizada, etc). O
artigo não deve ter mais do que DUAS páginas.
4 Avaliação
Leia com atenção os critérios de avaliação:
-
Os trabalhos são em duplas ou individuais. Os arquivos contendo o código-fonte (.cpp) devem ser compactados em um arquivo .zip e submetidos pelo Moodle
até a data e hora especificadas. O artigo, em formato PDF, também deve
ser incluído no zip. O arquivo compactado deve ter os últimos sobrenomes
de ambos os alunos, da seguinte forma: sobrenome1_sobrenome2.zip.
-
Não envie .rar, .7z, .tar.gz, apenas .zip
-
O código deve estar identado corretamente (o Code::Blocks faz isso automaticamente).
-
A nota do trabalho depende da apresentação deste no laboratório, na data
marcada. Trabalhos entregues mas não apresentados terão sua nota
anulada automaticamente. Durante a apresentação será avaliado o domínio
da resolução do problema, podendo inclusive ser possível invalidar o
trabalho quando constatada a falta de conhecimento sobre o código
implementado.
-
A cópia parcial ou completa do trabalho terá como conseqüência a
atribuição de nota ZERO ao trabalho dos alunos envolvidos. A verificação
de cópias é feita inclusive entre turmas.
-
A cópia de código ou algoritmos existentes da Internet também não é permitida. Se alguma idéia encontrada na rede for utilizada na implementação, sua descrição e referência deve constar no artigo.