A entrada:
A função main receberá em argv dois nomes de arquivos que serão copiados para as variáveis arqEntrada e arqSaida, respectivamente. Em arqEntrada estará o nome do arquivo contendo a imagem original, e em arqSaida o nome do arquivo de saída que será escrito pelo programa.
A imagem original terá intensidade máxima igual a 255 e tamanho n x m, onde n,m <= 128. O efeito a ser aplicado (cinza, esticar ou normalizar) é lido da entrada padrão e armazenado na váriavel efeito, conforme implementação da função main no arquivo.
A saída:
A imagem resultante deve ser escrita em PPM no arquivo de saída (arqSaida).
Exemplo de um arquivo de entrada e outro de saída (repare no seu formato, abrindo o arquivo com um bloco de notas):
https://drive.google.com/file/d/1BhFXRoW8afqRBqJuyNUUgkYYz4FL0722/view
https://drive.google.com/file/d/1a1NtW6gxkLSZSxN-esXlKVZmq4Ul93ux/view
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
void normalizar(char *arqE, char *arqS);
void esticarContraste(char *arqE, char *arqS);
void escalaDeCinza(char *arqE, char *arqS);
int main(int argc, char **argv){
if (argc != 3){//Verifica se há os três argumentos.
fprintf(stderr, "Argumentos invalidos. Use:\n");//Caso erro, exibe mensagem com instrução.
fprintf(stderr, "./lab18 <arqEntrada> <arqSaida>\n");
fprintf(stderr, "Usado:");
for (int i=0; i<argc; i++){
fprintf(stderr, " %s", argv[i]);
}
fprintf(stderr, "\n");
return 1;
}
char efeito[20];
char *arqEntrada = argv[1];
char *arqSaida = argv[2];
scanf("%s", efeito);//Leia efeito.
if(strcmp("cinza", efeito)==0){//Verifica qual efeito aplicar e chama a respectiva função.
escalaDeCinza(arqEntrada, arqSaida);
}else if (strcmp("esticar", efeito)==0){
esticarContraste(arqEntrada, arqSaida);
}else if (strcmp("normalizar", efeito)==0){
normalizar(arqEntrada, arqSaida);
}
return 0;
}
//Função normalizar recebe como parâmetros dois apontadores para os endereços dos arquivos entrada e saída. Ele executa alterações no arquivo saída, apenas.
void normalizar(char *arqE, char *arqS){
FILE *arqEntrada = fopen(arqE, "r"), *arqSaida = fopen(arqS, "w");//Abre os arquivos.
char marcador[2];
int width, height, Imax, R, G, B, novaR, novaG, novaB, soma;
if(arqEntrada == NULL) return;//Se não encontrou arquivo de entrada, encerra a função.
fscanf(arqEntrada,"%s\n%d %d\n%d\n", marcador, &width, &height, &Imax);//Leia marcador, largura, altura e Imax do arquivo de entrada e escreve valores no arq. de saída.
fprintf(arqSaida, "%s\n%d %d\n%d\n", marcador, width, height, Imax);
for(int i = 0; i<height; i++){//Como uma matriz, percorre as linhas e as colunas.
for(int j = 0; j<width; j++){
fscanf(arqEntrada,"%d %d %d ", &R, &G, &B);//Leia três inteiros (que representam o R, G e o B).
soma = R + G + B;
if(soma!=0){//Evitar a divisão por zero.
novaR = (R * 255) / soma;
novaG = (G * 255) / soma;
novaB = (B * 255) / soma;//Armazena novos valores para R, G e B.
}else novaR = R, novaG = G, novaB = B;
fprintf(arqSaida, "%d %d %d%c", novaR, novaG, novaB, (j != width-1? ' ':'\n'));//Escreve no arquivo o R G e o B seguido de um espaço ou \n (este se for último elemento da linha.
}
fscanf(arqEntrada,"\n");
//fprintf(arqSaida, "\n");
}
fclose(arqEntrada);//Fecha os arquivos.
fclose(arqSaida);
}
//Função esticarContraste recebe como parâmetros dois apontadores para os endereços dos arquivos entrada e saída. Ele executa alterações no arquivo saída, apenas.
void esticarContraste(char *arqE, char *arqS){
/*Mesmo procedimento que na função normalizar*/
FILE *arqEntrada = fopen(arqE, "r"), *arqSaida = fopen(arqS, "w");
char marcador[2];
int width, height, Imax, R, G, B, Rmin = 255, Rmax = 0, Gmin = 255, Gmax = 0, Bmin = 255, Bmax = 0, novaR, novaG, novaB;
if(arqEntrada == NULL) return;
fscanf(arqEntrada,"%s\n%d %d\n%d\n", marcador, &width, &height, &Imax);
fprintf(arqSaida, "%s\n%d %d\n%d\n", marcador, width, height, Imax);
for(int i = 0; i<height; i++){//A diferença da função normalizar está aqui. Pretende-se encontrar o menor e o maior valor para cada uma das intensidades (R, G e B).
fscanf(arqEntrada,"\n");
for(int j = 0; j<width; j++){
fscanf(arqEntrada,"%d %d %d ", &R, &G, &B);
if(R<Rmin) Rmin = R;
else if(R>Rmax) Rmax = R;
if(G<Gmin) Gmin = G;
else if(G>Gmax) Gmax = G;
if(B<Bmin) Bmin = B;
else if(B>Bmax) Bmax = B;
}
}
rewind(arqEntrada);//Retorna ao início do arquivo e lê apenas o seguinte para posicionar novamente o ponteiro do aquivo para onde começa a sequência dos pixels.
fscanf(arqEntrada,"%s\n%d %d\n%d\n", marcador, &width, &height, &Imax);
for(int i = 0; i<height; i++){
for(int j = 0; j<width; j++){
fscanf(arqEntrada,"%d %d %d ", &R, &G, &B);//Leia três inteiros (que representam o R, G e o B).
novaR = ((R - Rmin) * 255)/(Rmax - Rmin);
novaG = ((G - Gmin) * 255)/(Gmax - Gmin);
novaB = ((B - Bmin) * 255)/(Bmax - Bmin);//Armazena os novos valores para R, G e B.
fprintf(arqSaida, "%d %d %d%c", novaR, novaG, novaB, (j != width-1? ' ':'\n'));
}
fscanf(arqEntrada,"\n");
//fprintf(arqSaida, "\n");
}
fclose(arqEntrada);
fclose(arqSaida);
}
//Função escalaDeCinza recebe como parâmetros dois apontadores para os endereços dos arquivos entrada e saída. Ele executa alterações no arquivo saída, apenas.
void escalaDeCinza(char *arqE, char *arqS){
/*Mesmo procedimento de normalizar, muda-se apenas a operação para cada novo pixel.*/
FILE *arqEntrada = fopen(arqE, "r"), *arqSaida = fopen(arqS, "w");
char marcador[2];
int width, height, Imax, piso, R, G, B;
if(arqEntrada == NULL) return;
fscanf(arqEntrada,"%s\n%d %d\n%d\n", marcador, &width, &height, &Imax);
fprintf(arqSaida, "%s\n%d %d\n%d\n", marcador, width, height, Imax);
for(int i = 0; i<height; i++){
for(int j = 0; j<width; j++){
fscanf(arqEntrada,"%d %d %d ", &R, &G, &B);
piso = floor((R + G + B) / 3.0);
fprintf(arqSaida, "%d %d %d%c", piso, piso, piso, (j != width-1? ' ':'\n'));
}
fscanf(arqEntrada,"\n");
//fprintf(arqSaida, "\n");
}
fclose(arqEntrada);
fclose(arqSaida);
}
Se voce é professor, pode ser uma boa cobrar de seus alunos a solução desta tarefa usando matrizes. Aqui preferi ler e escrever diretamente nos arquivos de entrada e saída, porém existe essa outra possibilidade.