Compresion de imagenes con libjpeg.

Trabajando en el proyecto me he visto en la necesidad de realizar compresión a imagenes que capturo con una webcam desde el robot, para mandarlas a la aplicación cliente para poder visualizar lo que ve el robot para poder controlarlo a distancia. Actualmente lo estaba haciendo sin compresión alguna ya que todas las aplicaciones se ejecutaban en la misma máquina y no tenia problemas con la transmisión de datos e imagenes.

Investigando un poco por internet sobre la libreria de imagenes libjpeg he encontrado algunos ejemplos y los he modificado un poco para mis necesidades pero a continuación paso a explicar un pequeño ejemplo que te permite abrir un archivo .jpg, y comprimirla en otro archivo .jpg. Recordar que un archivo jpg es una imagen comprimida, si la abrimos en nuestro programa debemos de tener en cuenta que para poder usarla para otros programas e incluso para comprimirla de nuevo, primero debemos de descomprimirla.

Código y ejemplo después del salto –>

A simple vista no parece muy útil pero para alguien que empieza y para usarlo como ejemplo de uso y aprender como se hace esta muy bien.

#include <stdio.h>
#include <jpeglib.h>
#include <stdlib.h>

/* we will be using this uninitialized pointer later to store raw, uncompressd image */
unsigned char *raw_image = NULL;

/* dimensions of the image we want to write */
int width = 640;
int height = 480;
int bytes_per_pixel = 3;   /* or 1 for GRACYSCALE images */
int color_space = JCS_RGB; /* or JCS_GRAYSCALE for grayscale images */

/**
* read_jpeg_file Reads from a jpeg file on disk specified by filename and saves into the
* raw_image buffer in an uncompressed format.
*
* \returns positive integer if successful, -1 otherwise
* \param *filename char string specifying the file name to read from
*
*/

int read_jpeg_file( char *filename )
{
/* these are standard libjpeg structures for reading(decompression) */
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
/* libjpeg data structure for storing one row, that is, scanline of an image */
JSAMPROW row_pointer[1];

FILE *infile = fopen( filename, “rb” );
unsigned long location = 0;
int i = 0;

if ( !infile )
{
printf(“Error opening jpeg file %s\n!”, filename );
return -1;
}
/* here we set up the standard libjpeg error handler */
cinfo.err = jpeg_std_error( &jerr );
/* setup decompression process and source, then read JPEG header */
jpeg_create_decompress( &cinfo );
/* this makes the library read from infile */
jpeg_stdio_src( &cinfo, infile );
/* reading the image header which contains image information */
jpeg_read_header( &cinfo, TRUE );
/* Uncomment the following to output image information, if needed. */
/*–
printf( “JPEG File Information: \n” );
printf( “Image width and height: %d pixels and %d pixels.\n”, cinfo.image_width, cinfo.image_height );
printf( “Color components per pixel: %d.\n”, cinfo.num_components );
printf( “Color space: %d.\n”, cinfo.jpeg_color_space );
–*/
/* Start decompression jpeg here */
jpeg_start_decompress( &cinfo );

/* allocate memory to hold the uncompressed image */
raw_image = (unsigned char*)malloc( cinfo.output_width*cinfo.output_height*cinfo.num_components );
/* now actually read the jpeg into the raw buffer */
row_pointer[0] = (unsigned char *)malloc( cinfo.output_width*cinfo.num_components );
/* read one scan line at a time */
while( cinfo.output_scanline < cinfo.image_height )
{
jpeg_read_scanlines( &cinfo, row_pointer, 1 );
for( i=0; i<cinfo.image_width*cinfo.num_components;i++)
raw_image[location++] = row_pointer[0][i];
}
/* wrap up decompression, destroy objects, free pointers and close open files */
jpeg_finish_decompress( &cinfo );
jpeg_destroy_decompress( &cinfo );
free( row_pointer[0] );
fclose( infile );
/* yup, we succeeded! */
return 1;
}

/**
* write_jpeg_file Writes the raw image data stored in the raw_image buffer
* to a jpeg image with default compression and smoothing options in the file
* specified by *filename.
*
* \returns positive integer if successful, -1 otherwise
* \param *filename char string specifying the file name to save to
*
*/
int write_jpeg_file( char *filename )
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;

/* this is a pointer to one row of image data */
JSAMPROW row_pointer[1];
FILE *outfile = fopen( filename, “wb” );

if ( !outfile )
{
printf(“Error opening output jpeg file %s\n!”, filename );
return -1;
}
cinfo.err = jpeg_std_error( &jerr );
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile);

/* Setting the parameters of the output file here */
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = bytes_per_pixel;
cinfo.in_color_space = color_space;
/* default compression parameters, we shouldn’t be worried about these */

jpeg_set_defaults( &cinfo );
cinfo.num_components = 3;
//cinfo.data_precision = 4;
cinfo.dct_method    = JDCT_FLOAT;
jpeg_set_quality(&cinfo, 15, TRUE);
/* Now do the compression .. */
jpeg_start_compress( &cinfo, TRUE );
/* like reading a file, this time write one row at a time */
while( cinfo.next_scanline < cinfo.image_height )
{
row_pointer[0] = &raw_image[ cinfo.next_scanline * cinfo.image_width *  cinfo.input_components];
jpeg_write_scanlines( &cinfo, row_pointer, 1 );
}
/* similar to read file, clean up after we’re done compressing */
jpeg_finish_compress( &cinfo );
jpeg_destroy_compress( &cinfo );
fclose( outfile );
/* success code is 1! */
return 1;
}

int main()
{
char *infilename = “test.jpg”, *outfilename = “test_out.jpg”;

/* Try opening a jpeg*/
if( read_jpeg_file( infilename ) > 0 )
{
/* then copy it to another file */
if( write_jpeg_file( outfilename ) < 0 ) return -1;
}
else return -1;
return 0;
}

Este programa de ejemplo hace una llamada a la funcion ” read_jpeg_file() ” que nos abre un fichero ” test.jpg “, lo descomprime y mete el resultado en un buffer (raw_image). A continuación hace una llamada a la función ” write_jpeg_file() ” que se encarga de comprimir la imagen y almacenarla en un archivo ” test_out.jpg “.

Para modificar el ratio de compresión usamos esta función:

jpeg_set_quality(&cinfo, 15, TRUE);

la cual nos comprime a una calidad del 15% la imagen cinfo, para variar el ratio de compresión modificamos el 2º parametro, los valores que acepta son de 0 .. 100.

A continuación una imagen jpg y su resultado a una compresion de 10.

donde la imagen sin compresion ocupa 69 KB y la comprimida 13 KB, interesante resultado.

Para compilar este programa lo haremos de la siguiente forma:

$ gcc jpeg_sample.c -o jpeg_sample -ljpeg

Fuente: http://www.cim.mcgill.ca/~junaed/libjpeg.php

Lo que voy a hacer ahora es introducir estas funciones justo antes del envío de la imagen y justo despues de la recepción de la imagen en mi proyecto de fin de carrera, esperemos que de esta forma consiga muchos mas fotogramas por segundo sin el problema del ancho de banda, ya ire informando de los avances…

Saludos y gracias por la atención.

About admin