Manipulação de imagens (JPG, PNG) em linguagem C.

1. Manipulação de imagens (JPG, PNG) em linguagem C.

Luis R. C. Silva
luisrcs

(usa Linux Mint)

Enviado em 12/11/2013 - 23:11h

Boa noite a todos.

Como mencionei em outro tópico, aqui: http://vivaolinux.com.br/topico/C-C++/Sistema-de-correcao-de-provas - tenho um projeto para desenvolvimento de um sistema de correção de provas.

Até aqui o sistema básico está funcionando bem, mas para torná-lo aplicável preciso resolver algumas pendências:

1 - Uma forma de manipular imagens através da linguagem C. Pois estou utilizando PHP (manjo melhor), mas tem a questão da dependência do interpretador, já C o código flui direto. Não há necessidade de GUI, basta interface textual.

2 - Caso não seja possível a manipulação de imagens direta em C, poderia ser uma biblioteca para tornar isso possível.

3 - Se nenhum dos dois anteriores forem possível, poderia ainda ter um software em linha de comando para manipulação de imagens. Descobri alguns, mas muito grandes para minhas pretensões, como ImageMagick, ExactImage e GraphicsMagick.

As únicas funções que preciso são: redimensionar, brilho, contraste, grayscale e, se possível cortar a imagem.

Muito grato.

Luís Roberto.


  


2. Re: Manipulação de imagens (JPG, PNG) em linguagem C.

???
gokernel

(usa Linux Mint)

Enviado em 13/11/2013 - 11:11h


Não conheço PHP... mas está na lista de linguagens para aprender no futuro.

Quando preciso usar alguma coisa referente de C/C++, faço assim:
Programo parte na "linguagem" e outra parte faço em C/C++(gerando os arquivos .so ou .DLL) e faço a exportação para a "linguagem".

Outra vez tentei fazer isso com Perl e desistir logo no começo... achei muito complicado extender com Perl.


3. Re: Manipulação de imagens (JPG, PNG) em linguagem C.

???
gokernel

(usa Linux Mint)

Enviado em 13/11/2013 - 11:11h


Não conheço PHP... mas está na lista de linguagens para aprender no futuro.

Quando preciso usar alguma coisa referente de C/C++, faço assim:
Programo parte na "linguagem" e outra parte faço em C/C++(gerando os arquivos .so ou .DLL) e faço a exportação para a "linguagem".

Outra vez tentei fazer isso com Perl e desisti logo no começo... achei muito complicado extender com Perl.


4. Re: Manipulação de imagens (JPG, PNG) em linguagem C.

Paulo
paulo1205

(usa Ubuntu)

Enviado em 13/11/2013 - 11:47h

Existem várias bibliotecas que permitem manipulação de imagens. Além das que fazem acesso direto aos arquivos de formatos específicos (libpng para PNG, libgif para GIF, libtif para TIFF etc.), existem as de mais alto nível, que frequentemente suportam vários formatos e permitem realizar outras funções avançadas, como libgd (de uso muito comum, aliás, com o PHP, que você mencionou), libmagick e seguramente muitas e muitas outras.

Seu problema de correção de provas, pelo que me lembro da descrição que você colocou no outro tópico, seria mais ou menos uma questão identificar as regiões da folha de resposta em que deveriam se encontrar as respostas marcadas e conferir se elas estão marcadas ou não.

Posso estar sendo muito simplista porque não pensei muito a fundo no problema, mas o que eu faria seria usar uma função que obtém a cor de um pixel para obter a média de cor dos pixels de uma região onde se deveria esperar uma resposta correta, e ver se ela diverge muito da cor média esperada de uma resposta não marcada. Com a libgd (que pode não ser a melhor opção para você, mas que é a única biblioteca gráfica com a qual eu já trabalhei diretamente -- e há muito tempo), seria uma questão de fazer mais ou menos o seguinte.

int averageRGB(gdImagePtr im, int xmin, int ymin, int xmax, int ymax){
int avgR, avgG, avgB;
int color_index;
int x, y, npixels, npixels_2;

npixels=(1+abs(xmax-xmin))*(1+(abs(ymax-ymin));
npixels_2=npixels/2; /* Usado abaixo para facilitar arredondamento. */

avgR=avgG=avgB=0;
for(x=xmin; x<=xmax; x++){
for(y=ymin; y<ymax; y++){
color_index=gdImageGetPixel(im, x, y);
avgR+=gdImageRed(im, color_index);
avgG+=gdImageGreen(im, color_index);
avgB+=gdImageBlue(im, color_index);
}
}
avgR=(avgR+npixels_2)/npixels;
avgG=(avgG+npixels_2)/npixels;
avgB=(avgB+npixels_2)/npixels;

return (avgR<<16)+(avgB<<8)+avgB;
}

int naive_RGB2gray(int rgb){
return (((rgb&0xFF0000)>>16)+((rgb&0xFF00)>>8)+(rgb&0xFF))/3;
}

#define DARKNESS_THRESHOLD 0x55 /* menos de 1/3 (de 0xFF) de luminosidade indica resp. marcada */

int check_answer(gdImagePtr im, int quest_number, int right_answer, int max_answers){
int xmin, ymin, xmax, ymax;
int n_answer;
int avg_gray;
int checked_answers=0; right_answer_is_checked=0;

for(n_answer=1; n_answer<=max_answer; n_answer++){
/*
Determina valores de (xmin, ymin) e (xmax, ymax) em função
no nº da questão (quest_number) e do índice da alternativa
(n_answer), provavelmente usando alguma fórmula matemática
para determinar tais posições.
*/
avg_gray=naive_RGB2gray(averageRGB(im, xmin, ymin, xmax, ymax));
if(avg_gray<DARKNESS_THRESHOLD){
checked_answers++;
if(n_answer==right_answer)
right_answer_is_checked=1;
}
}

return right_answer_is_checked && checked_answers==1;
}



5. Re: Manipulação de imagens (JPG, PNG) em linguagem C.

Luis R. C. Silva
luisrcs

(usa Linux Mint)

Enviado em 13/11/2013 - 13:16h

gokernel escreveu:


Não conheço PHP... mas está na lista de linguagens para aprender no futuro.

Quando preciso usar alguma coisa referente de C/C++, faço assim:
Programo parte na "linguagem" e outra parte faço em C/C++(gerando os arquivos .so ou .DLL) e faço a exportação para a "linguagem".

Outra vez tentei fazer isso com Perl e desistir logo no começo... achei muito complicado extender com Perl.


Acho que uma das coisas que dificultam programadores desktop em aprender php é achar que a linguagem só serve para aplicações web. Porém se pode fazer coisas em desktop com maior rapidez e facilidade do que em outras linguagens, como java.

Em alguns poucos testes que fiz, php obteve melhor desempenho do que a mesma função escrita em java.

Se serve de incentivo, php é mais parecida com C do que a própria C++. Além de possibilitar implementação de GUI, com php-gtk.


6. Re: Manipulação de imagens (JPG, PNG) em linguagem C.

Luis R. C. Silva
luisrcs

(usa Linux Mint)

Enviado em 13/11/2013 - 13:27h

paulo1205 escreveu:

Existem várias bibliotecas que permitem manipulação de imagens. Além das que fazem acesso direto aos arquivos de formatos específicos (libpng para PNG, libgif para GIF, libtif para TIFF etc.), existem as de mais alto nível, que frequentemente suportam vários formatos e permitem realizar outras funções avançadas, como libgd (de uso muito comum, aliás, com o PHP, que você mencionou), libmagick e seguramente muitas e muitas outras.

Seu problema de correção de provas, pelo que me lembro da descrição que você colocou no outro tópico, seria mais ou menos uma questão identificar as regiões da folha de resposta em que deveriam se encontrar as respostas marcadas e conferir se elas estão marcadas ou não.

Posso estar sendo muito simplista porque não pensei muito a fundo no problema, mas o que eu faria seria usar uma função que obtém a cor de um pixel para obter a média de cor dos pixels de uma região onde se deveria esperar uma resposta correta, e ver se ela diverge muito da cor média esperada de uma resposta não marcada. Com a libgd (que pode não ser a melhor opção para você, mas que é a única biblioteca gráfica com a qual eu já trabalhei diretamente -- e há muito tempo), seria uma questão de fazer mais ou menos o seguinte.

int averageRGB(gdImagePtr im, int xmin, int ymin, int xmax, int ymax){
int avgR, avgG, avgB;
int color_index;
int x, y, npixels, npixels_2;

npixels=(1+abs(xmax-xmin))*(1+(abs(ymax-ymin));
npixels_2=npixels/2; /* Usado abaixo para facilitar arredondamento. */

avgR=avgG=avgB=0;
for(x=xmin; x<=xmax; x++){
for(y=ymin; y<ymax; y++){
color_index=gdImageGetPixel(im, x, y);
avgR+=gdImageRed(im, color_index);
avgG+=gdImageGreen(im, color_index);
avgB+=gdImageBlue(im, color_index);
}
}
avgR=(avgR+npixels_2)/npixels;
avgG=(avgG+npixels_2)/npixels;
avgB=(avgB+npixels_2)/npixels;

return (avgR<<16)+(avgB<<8)+avgB;
}

int naive_RGB2gray(int rgb){
return (((rgb&0xFF0000)>>16)+((rgb&0xFF00)>>8)+(rgb&0xFF))/3;
}

#define DARKNESS_THRESHOLD 0x55 /* menos de 1/3 (de 0xFF) de luminosidade indica resp. marcada */

int check_answer(gdImagePtr im, int quest_number, int right_answer, int max_answers){
int xmin, ymin, xmax, ymax;
int n_answer;
int avg_gray;
int checked_answers=0; right_answer_is_checked=0;

for(n_answer=1; n_answer<=max_answer; n_answer++){
/*
Determina valores de (xmin, ymin) e (xmax, ymax) em função
no nº da questão (quest_number) e do índice da alternativa
(n_answer), provavelmente usando alguma fórmula matemática
para determinar tais posições.
*/
avg_gray=naive_RGB2gray(averageRGB(im, xmin, ymin, xmax, ymax));
if(avg_gray<DARKNESS_THRESHOLD){
checked_answers++;
if(n_answer==right_answer)
right_answer_is_checked=1;
}
}

return right_answer_is_checked && checked_answers==1;
}


Seria mais ou menos isso. Até tentei fazer com a libgd, da php. Porém o problema foi identificar onde deveria está a resposta marcada no gabarito, pois após o escaneamento, a imagem teria que ser tratada e dimensionada para um tamanho (em pixels) padrão. Pensei em colocar marcadores para identificar o local de cada questão e, a partir deles contar os pixels para a resposta correta, negando se não a encontrar. Não sei se meu raciocínio está correto.

Nesse caso pergunto, como eu encontraria a região marcada? Passando pixel a pixel até encontrá-la? Ou tem uma maneira mais fácil?

O que fiz foi algo mais simples, porém mais sujeito a falhas. Utilizei em software OCR para reconhecer as respostas, convertendo as bolinha em branco em 'o', 'O' ou '0', e as bolinhas marcadas em '_'. Verificando se os '_' estão na posição correta. Mesmo assim, as imagens devem ser tratadas para reduzir a possibilidade de erros.

Vou verificar sua sugestão e estudar sei código, que de antemão agradeço por cedê-lo.


7. Re: Manipulação de imagens (JPG, PNG) em linguagem C.

Paulo
paulo1205

(usa Ubuntu)

Enviado em 14/11/2013 - 01:42h

rei_astro escreveu:

Seria mais ou menos isso. Até tentei fazer com a libgd, da php. Porém o problema foi identificar onde deveria está a resposta marcada no gabarito, pois após o escaneamento, a imagem teria que ser tratada e dimensionada para um tamanho (em pixels) padrão. Pensei em colocar marcadores para identificar o local de cada questão e, a partir deles contar os pixels para a resposta correta, negando se não a encontrar. Não sei se meu raciocínio está correto.


Cartões como os de loterias ou cartões de resposta como os utilizados em concursos públicos têm um formato (físico) fixo, e o processo de scan da imagem é feito por hardware especializado, o que certamente facilita na construção do programa que faz a contabilidade do resultado final. Entendo que o que você quer é similar, mas possivelmente menos sofisticado e mais dependente de interações manuais e, por conseguinte, de software mais elaborado.

Se você depende de scan manual, pode ser que tenha alguns problemas involuntários de escala e de rotação, ou até mesmo cortes na imagem adquirida. Tirando cortes na hora do scan, escalas e rotações podem ser compensadas por software depois, mas provavelmente com alguma degradação da informação original da imagem (porque ambos os processos geram imagens novas que fazem médias e interpolações de cores dos pixels da imagem original). O ideal é que você tente minimizar o máximo possível esses efeitos na hora da aquisição da imagem, a fim de eliminar etapas posteriores de rotacionamento, escalonamento e cortes.

Nesse caso pergunto, como eu encontraria a região marcada? Passando pixel a pixel até encontrá-la? Ou tem uma maneira mais fácil?


Acho que a maneira mais fácil é ter, sim, um gabarito de tamanho e disposição de informações, que todas as imagens devem seguir. Com isso, você poderia saber onde encontrar cada informação indo diretamente à posição onde ela deve ser encontrada (e eu estou falando de regiões e retângulos, como no código que eu mostrei; exigir que esteja num pixel específico pode aumentar muito a vulnerabilidade a eventuais problemas com a imagem capturada) e verificando se aquela posição está preenchida ou não.

Não tem de ser assim necessariamente. Uma solução no extremo da flexibilidade poderia prescindir de formato fixo, desde que o programa fosse suficientemente inteligente para identificar padrões fixos que poderiam ocorrer em qualquer lugar do quadro, com qualquer inclinação e em qualquer escala.


8. Re: Manipulação de imagens (JPG, PNG) em linguagem C.

Luis R. C. Silva
luisrcs

(usa Linux Mint)

Enviado em 14/11/2013 - 07:51h

paulo1205 escreveu:

rei_astro escreveu:

Seria mais ou menos isso. Até tentei fazer com a libgd, da php. Porém o problema foi identificar onde deveria está a resposta marcada no gabarito, pois após o escaneamento, a imagem teria que ser tratada e dimensionada para um tamanho (em pixels) padrão. Pensei em colocar marcadores para identificar o local de cada questão e, a partir deles contar os pixels para a resposta correta, negando se não a encontrar. Não sei se meu raciocínio está correto.


Cartões como os de loterias ou cartões de resposta como os utilizados em concursos públicos têm um formato (físico) fixo, e o processo de scan da imagem é feito por hardware especializado, o que certamente facilita na construção do programa que faz a contabilidade do resultado final. Entendo que o que você quer é similar, mas possivelmente menos sofisticado e mais dependente de interações manuais e, por conseguinte, de software mais elaborado.

Se você depende de scan manual, pode ser que tenha alguns problemas involuntários de escala e de rotação, ou até mesmo cortes na imagem adquirida. Tirando cortes na hora do scan, escalas e rotações podem ser compensadas por software depois, mas provavelmente com alguma degradação da informação original da imagem (porque ambos os processos geram imagens novas que fazem médias e interpolações de cores dos pixels da imagem original). O ideal é que você tente minimizar o máximo possível esses efeitos na hora da aquisição da imagem, a fim de eliminar etapas posteriores de rotacionamento, escalonamento e cortes.

Nesse caso pergunto, como eu encontraria a região marcada? Passando pixel a pixel até encontrá-la? Ou tem uma maneira mais fácil?


Acho que a maneira mais fácil é ter, sim, um gabarito de tamanho e disposição de informações, que todas as imagens devem seguir. Com isso, você poderia saber onde encontrar cada informação indo diretamente à posição onde ela deve ser encontrada (e eu estou falando de regiões e retângulos, como no código que eu mostrei; exigir que esteja num pixel específico pode aumentar muito a vulnerabilidade a eventuais problemas com a imagem capturada) e verificando se aquela posição está preenchida ou não.

Não tem de ser assim necessariamente. Uma solução no extremo da flexibilidade poderia prescindir de formato fixo, desde que o programa fosse suficientemente inteligente para identificar padrões fixos que poderiam ocorrer em qualquer lugar do quadro, com qualquer inclinação e em qualquer escala.


Entendi. Muito obrigado pelo esclarecimento.

Acho que o problema da rotação seria baixo se trabalhar com o tamanho do esquadro do escâner padrão.






Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts