Lossless Resizing Algorithm in C : VGA to QVA

At some point of time in an embedded engineer's life a need may arise to 'resize' an image. Resizing an image means changing its resolution.
The most common and well known resolutions which everybody encounters into their day-to-day life are:

                  VGA  -  640x480        (Vector Graphics Array)
                QVGA -  320 x 240      (Quarter Vector Graphics Array)
                  XGA  -  1024 x 768    (Extended Graphics Array)
                QXGA -  2048 x 1536  ('QUAD' (and not quarter) Extended Graphics Array)

                       and many more. Of these VGA and XGA are mostly used. For Example your desktop background is XGA resolution.

        Imagine you are using a phone or any other handheld device which has a frame buffer smaller than VGA or XGA resolutions. In layman's language suppose your LCD can show image only in the QVGA resolution and you have an image in VGA resolution which you want to display it on your LCD. For this you can use the following C code and cross compile it for your architecture.


        FILE *fIN, *fOUT;
        unsigned char ucBufInImage[ 640*480*3 ];                         //buffer to store raw input image.
        unsigned char ucBufOutImage[ 320*240*3 ];                      //buffer to store raw and resized output
        int iNewWidth,iNewWidth;
        int iRowIndex, iColumnIndex;
        int ind1, ind2, ind3;

        iNewWidth = 320;                            //width after resize
        iNewWidth = 240;                            //height after resize

       iRowIndex = 0;                                  //variable for maneuvering through rows
       iColIndex = 0;                                    //variable for maneuvering throughcolumns

       fIN = fopen("<Input VGA filename>", "rb");           //opening input file
       if(fIN == NULL)                                                  
                  fprintf( stderr, "Could not open the input file\n");
                  exit( EXIT_FAILURE );

       fread( ucBufInImage, 640*480*3, 1, fIN );             //putting contents of input file to a buffer

       fOUT = fopen("<Desired name of output QVGA file>", "wb");    //opening output file
       if(fOUT == NULL)
                  fprintf( stderr, "Could not open file for output.\n");
                  exit( EXIT_FAILURE );

       ind1 = 0;                       //various index variables
       ind2 = 1920;
       ind3 = 0;

       for( iRowIndex = 0; iRowIndex < iNewHeight; iRowIndex++ )   //outer for loop for the rows
              for( iColIndex = 0; iColIndex < ( iNewWidth );  iColIndex++,  ind1 += 6, ind2 += 6, ind3 += 3  )             //inner for loop for columns
               ucBufOutImage[ ind3 ] = ( ucBufInImage[ind1] + ucBufInImage[ind1 + 3] + ucBufInImage[ind2] + ucBufInImage[ind2 + 3] );                                          //averaging of RED components of adjacent four pixels

               ucBufOutImage[ ind3 + 1 ] = ( ucBufInImage[ind1 + 1] + ucBufInImage[ind1 + 4] + ucBufInImage[ind2 + 1] + ucBufInImage[ind2 + 4] );     //averaging of GREEN components of adjacent four pixels

               ucBufOutImage[ ind3 + 2 ] = ( ucBufInImage[ind1 + 2] + ucBufInImage[ind1 + 5] + ucBufInImage[ind2 + 2] + ucBufInImage[ind2 + 5] );     //averaging of BLUE components of adjacent four pixels


        ind1 = ind1 + 1920;              //incrementing the index for the next row
        ind2 = ind2 + 1920;              //incrementing the index for the next row

   fwrite( ucBufOutImage, 320*240*3, 1, fOUT );       //dumping the output to the file

  fclose( fIN );              //closing the input file
  fclose( fOUT );          //closing the output file


     There are two ways in which you could resize any image; first in which you just drop the extra pixel information and keep the amount of info you want in the resized image. This is known as 'lossy' resizing. In the second approach, one which i have used in the above code, is 'lossless' resizing in which we do not drop the extra information but instead we take an average of respective components of certain number of pixels to create fewer numbers.

     In the above code as we have to resize from VGA to QVGA, which is 1/4th of the original, so we take an average of four adjacent pixels to create one. This way we reduce the total size of the VGA image to 1/4th to create QVGA image. The four pixels are taken in the following way:

Resizing from 640 x 480 to 320 x 240

1 comment:

  1. Great work...Thanks for sharing this info...It helps me a lot...