Manipulação de imagens no formato PPM

O artigo seguinte faz uma introdução sobre o formato ".ppm", que faz o armazenamento de forma simples e "bruta" de imagens. Além de como manipular o arquivo, para podermos aplicar filtros de imagem já existentes ou criar nossos próprios filtros.

[ Hits: 32.212 ]

Por: Pablo Margreff em 16/01/2015 | Blog: https://pmargreff.wordpress.com/


Filtros



Agora chegamos na parte interessante deste artigo, criar filtros para as imagens. O seu propósito final pode variar, de como entender como os filtros que aplicamos no Instagram e outros programas funcionam, passando por inserção de logo ou marca em imagens de forma automatizada, até testar o resultado de seu próprio filtro.

Vou dar exemplos de filtros simples, porém é bom saber que temos como aplicar qualquer tipo em uma imagem, o limite é a nossa criatividade.

Começaremos com um filtro que transforma uma imagem colorida em uma imagem com tons de cinza, famoso "B&W" ou em português, branco e preto, que na verdade é chamado assim incorretamente. Para converter qualquer cor em seu nível aproximado de cinza, deve-se primeiro obter suas primitivas vermelho, verde e azul (da escala RGB). Adiciona-se então 30% do vermelho mais 59% do verde mais 11% do azul, independente da escala utilizada (0.0 a 1.0, 0 a 255, 0% a 100%.). No código serão valores com melhor precisão, para não escaparem cores fracas.

void gray_scale(pixel imagem[MAX][MAX], int coluna, int linha) {
    int i, j;
    for (i = 0; i < linha; i++){
        for (j = 0; j < coluna; j++){
            imagem[i][j].r = (int) ((0.299 * imagem[i][j].r) + (0.587 * imagem[i][j].g) + (0.144 * imagem[i][j].b)); //calcula o valor para conversão
            imagem[i][j].g = imagem[i][j].r; //copia o valor para
            imagem[i][j].b = imagem[i][j].r; //todas componentes

            //testa o valor para ver se o mesmo não passou de 255
            if (imagem[i][j].r > 255){
                imagem[i][j].r = 255;
                imagem[i][j].g = 255;
                imagem[i][j].b = 255;

            }
        
        }
    }
}

O código em si é bem simples, apenas calcula a regra mostrada anteriormente e depois distribui para todos três componentes dos pixeis. E também confere, caso no calculo, algum dos pixeis acabem passando de 255.

O segundo filtro será o filtro de auto relevo, que é usado para fazer macas d'água em papéis e outros tipos de materiais timbrados. Para o calculo dele, pegamos uma variável qualquer e subtraímos de sua variável de posição oposta, e este valor substitui a central, escolhi fazer isso com as variáveis das linhas anteriores e posteriores, mas poderia ser feito com as da lateral, ou até mesmo diagonal.
void autorelevo(pixel imagem[MAX][MAX], int coluna, int linha) {
    pixel img[linha][coluna]; // cria uma imagem para salvar o resultado do emboss
    int i, j;
    for (i = 1; i < linha - 1; i++){
        for (j = 0; j < coluna; j++){
            img[i][j].r = imagem[i + 1][j].r - imagem[i -1][j].r; //faz a operação passando o 
            img[i][j].g = imagem[i + 1][j].b - imagem[i -1][j].b; //resultado para a matriz de
            img[i][j].b = imagem[i + 1][j].b - imagem[i -1][j].b; //backup

            if (img[i][j].r < 0) //testa os limites
                img[i][j].r = 0;

            if (img[i][j].g < 0)
                img[i][j].g = 0;

            if (img[i][j].b < 0)
                img[i][j].b = 0;
        }
    }

    for (i = 1; i < linha - 1; i++){
        for(j = 0; j < coluna; j++){

                imagem[i][j].r = img[i][j].r + 128; //adiciona 128 para clarear a imagem
                imagem[i][j].g = img[i][j].g + 128;
                imagem[i][j].b = img[i][j].b + 128;

                if (img[i][j].r > 255) //testa os limites
                img[i][j].r = 255;

                if (img[i][j].g > 255)
                img[i][j].g = 255;

                if (img[i][j].b > 255)
                img[i][j].b = 255;                          
        }
    }
}

O cálculo é de forma simples de se explicar feito sobre esta matriz:

0      -1       0
0       C       0
0       1       0

Onde o pixel central é substituído pela soma do negativo imediatamente acima, e o valor positivo imediatamente abaixo, depois testamos os limites. Lembrando que usamos uma matriz para guardar os resultados, já que se alterarmos o valor imediatamente após realizarmos a conta, haveria interferência, pois usamos os pixeis para calcular os da próxima linha. Depois que tudo é calculado a matriz resposta é passada para a matriz original.

E por último aplicaremos o espelhamento, que é nada mais que inverter a imagem.

void espelhar(pixel imagem[MAX][MAX], int coluna, int linha) {
    pixel img[linha][coluna];
    int i, j;

    for (i = 0; i < linha; i++) {
        for (j = 0; j < coluna; j++) {
            img[i][j].r = imagem[i][coluna - j].r; //salva em uma matriz do tipo pixel a imagem com suas 
            img[i][j].g = imagem[i][coluna - j].g; //linhas salvas em complementos, isso faz com que a imagem
            img[i][j].b = imagem[i][coluna - j].b; //pegue o pixel complementar no seu extremo oposto horizontal 
        }
    }

    //passa a imagem para a matriz original
    for (i = 0; i < linha; i++) {
        for (j = 0; j < coluna; j++) {
            imagem[i][j].r = img[i][j].r;
            imagem[i][j].g = img[i][j].g;
            imagem[i][j].b = img[i][j].b;   
        }
    }
}

Esse efeito é bem simples, ele apenas substitui o pixel atual pelo pixel de complemento, ou seja, pega a dimensão da imagem, e subtrai dela o pixel corrente, para encontrar seu correspondente no outro lado da imagem. Neste caso o espelhamento foi feito na horizontal, mas nada impede de faze-lo na vertical, ou alterar a fórmula para girar a imagem.

Além destes, podemos obter muitos outros efeitos em fotos, como blur motion, sépia, detecção de bordas, negativo... O limite será sua necessidade e/ou criatividade.

Qualquer dúvida ou sugestão me disponibilizo no email abaixo, segue também o arquivo do algoritmo completo. E lembre-se, ao invés de ser apenas um usuário, seja um proliferador da informação, abraço.
pablo_margreff@hotmail.com

Fontes:
Página anterior    

Páginas do artigo
   1. Introdução ao formato ppm e seus usos
   2. Abrindo e salvando arquivo ppm
   3. Filtros
Outros artigos deste autor

Gerando Números Aleatórios

Algoritmos de compressão

Aumentando sua produtividade com o teclado padrão Dvorak

Leitura recomendada

DoTheWorld - Biblioteca completa para manipulação de Arquivos e Pastas em C

Manipulando arquivos em C (parte 2)

Manipulação de arquivos em C++

Manipulando arquivos em C (parte 1)

Criando aplicativos para o Mac OS X no GNU/Linux

  
Comentários
[1] Comentário enviado por fabio em 16/01/2015 - 09:58h

Muito bom artigo, meus parabéns! Nunca havia lido nada que abordasse tal assunto.

[2] Comentário enviado por Nerdiarretado em 08/05/2019 - 11:31h

Ótimo artigo! Parabéns pela iniciativa, estou também desenvolvendo um mesmo programa e esse será uma ótima referência!


Contribuir com comentário




Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts