
/**
    Simple example of background segmentation for a Robocup football
    field.

    FIXME: the algorithm currently selects yellow pixels as well as
    green pixels.
*/

/**
    This program requires the PPM library (part of the netpbm package).
    Try "man libppm" for documentation.
*/

#include <stdio.h>
#include <ppm.h>

/**
    Process an image by marking "background" pixels red.
*/

void
ProcessImage(
    pixel     **pPixelIn,       /* Input pixel data */
    pixel     **pPixelOut,      /* Output pixel data */
    int         cCols,          /* Number of columns in input/output imgs */
    int         cRows,          /* Number of rows in input/output imgs */
    pixval      pixvalMax       /* Maximum pixel value */
);

/**
    Main
*/

int
main(
    int argc,                   /**< Number of input arguments */
    char *argv[]                /**< Input arguments */
)
{
    pixel **ppPixelIn;
    pixel **ppPixelOut;
    int cCols, cRows;
    pixval pixvalMax;
    FILE *pFile;

    /* Initialize the PPM library */

    ppm_init( &argc, argv );

    /* Open the PPM file */

    pFile = fopen( "field.ppm", "r" );
    if ( pFile == NULL ) {
        fprintf( stderr, "%s %d: could not open field.ppm\n", __FILE__,
                 __LINE__ );
        exit( -1 );
    }

    /* Read the image file in its entirety into memory */

    ppPixelIn =  ppm_readppm( pFile, &cCols, &cRows, &pixvalMax );
    if ( ppPixelIn == NULL ) {
        fprintf( stderr, "%s %d: could not read pixel data from field.ppm\n",
                 __FILE__, __LINE__ );
        exit( -1 );
    }
    fclose( pFile );

    /* Allocate a new PPM of the same size */

    ppPixelOut = ppm_allocarray( cCols, cRows );
    if ( ppPixelOut == NULL ) {
        fprintf( stderr, "%s %d: could not allocate pixel data\n",
                 __FILE__, __LINE__ );
        exit( -1 );
    }

    /* Process the input image, writing new data to the output image */

    ProcessImage( ppPixelIn, ppPixelOut, cCols, cRows, pixvalMax );

    /* Open output file */

    pFile = fopen( "fieldout.ppm", "w" );
    if ( pFile == NULL ) {
        fprintf( stderr, "%s %d: could not create fieldout.ppm\n",
                 __FILE__, __LINE__ );
        exit( -1 );
    }

    /* Write output image to the output file */

    ppm_writeppm( pFile, ppPixelOut, cCols, cRows, pixvalMax, 0 );
    fclose( pFile );

    return 0;
}


/**
    Process an image by marking "background" pixels red.
*/

void
ProcessImage(
    pixel **pPixelIn,
    pixel **pPixelOut,
    int cCols,
    int cRows,
    pixval pixvalMax
)
{
    int iRow, iCol;

    /* For each row and column of the image */

    for ( iRow = 0; iRow < cRows; iRow++ ) {
        for ( iCol = 0; iCol < cCols; iCol++ ) {

            /* Extract the red, green, and blue components of the pixel */

            pixval pixvalR = PPM_GETR( pPixelIn[iRow][iCol] );
            pixval pixvalG = PPM_GETG( pPixelIn[iRow][iCol] );
            pixval pixvalB = PPM_GETB( pPixelIn[iRow][iCol] );

            /**
                Call a pixel "green" (background) if:
                  1) green component is bigger than the red component
                  2) green component is twice as large as the blue component
                  3) green component is more than 1/4 the maximum pixel value

                This is not quite correct though.  It also selects yellow
                pixels.
            */

            if ( pixvalG > 0.9 * pixvalR && pixvalG > 2 * pixvalB &&
                 pixvalG > pixvalMax / 4) {

                /* This looks like a background pixel.  Change it to red. */

                pixvalR = pixvalMax;
                pixvalG = 0;
                pixvalB = 0;
            }

            /* Write the pixel value to the output image */

            PPM_ASSIGN( pPixelOut[iRow][iCol], pixvalR, pixvalG, pixvalB );
        }
    }
}

