Color Distance

Using the Video4Linux API’s to capture an image I used a color distance algorithm that filtered out a specific color so that the color chosen appears “close” and other colors appear “far”. The color distance algorithm is calculated when the pixels are inputted and written to the .ppm file.

int ppm_save_yuyv(const char* name, int cols, int rows, void* buffer, int bufferSize)
{
    char header[128];
    sprintf(header, "P6\n%d %d 255\n", cols, rows);
    FILE* file = fopen (name, "w");
    if (file==0) return(-1);
    fputs(header, file);

    {
        int Y0, Y1, Cb, Cr;                             // gamma pre-corrected input [0;255]
        int y0,y1, pb, pr;                              // temporaries
        char r0,r1,g0,g1,b0,b1;                         // temporaries
        unsigned long long int sumH=0, sumW=0, sumD=0;     // use int64_t not 32-bit long int
        int dr,dg,db,distance;                            //dr,dg,db must be signed!

        int iterations = cols*rows/2;
        int i = 0,row = 0, col = 0;
        while( i < iterations )
        {
            unsigned int packed_value = *((int*)buffer+i);

            if(row>rows){row = 0; col++;}

            Y0 = (char)(packed_value & 0xFF);
            Cb = (char)((packed_value >> 8 ) & 0xFF);
            Y1 = (char)((packed_value >> 16 ) & 0xFF);
            Cr = (char)((packed_value >> 24 ) & 0xFF);

            // Strip sign values after shift (i.e. unsigned shift)
            Y0 = Y0 & 0xFF;
            Cb = Cb & 0xFF;
            Y1 = Y1 & 0xFF;
            Cr = Cr & 0xFF;

            y0 = 255*(Y0 - 16)/219;
            y1 = 255*(Y1 - 16)/219;
            pb = 255*(Cb - 128)/224;
            pr = 255*(Cr - 128)/224;

            // Generate first pixel
            r0 = clamp(( 298 * y0            + 409 * pr + 128) >> 8);
            g0 = clamp(( 298 * y0 - 100 * pb - 208 * pr + 128) >> 8);
            b0 = clamp(( 298 * y0 + 516 * pb            + 128) >> 8);

            // Generate next pixel - must reuse pb & pr as 4:2:2
            r1 = clamp(( 298 * y1            + 409 * pr + 128) >> 8);
            g1 = clamp(( 298 * y1 - 100 * pb - 208 * pr + 128) >> 8);
            b1 = clamp(( 298 * y1 + 516 * pb            + 128) >> 8);

            //calculate difference of each color component range of (0-255)
            dr = r0 - 255;
            dg = g0 - 0;
            db = b0 - 0;

            //calculate the distance using the difference of the color components and the max value for the colors (255)
            //update the color pixel to the distance calculated
            distance = 255 -floor(sqrt(dr*dr+dg*dg+db*db));
            if(distance<0){distance = 0;}
            r0 = distance;
            g0 = distance;
            b0 = distance;

            //update the weighted sums for center width and height
            sumH=sumH+row*distance;
             sumW=sumW+col*distance;
             sumD=sumD+distance;
            row++;

            //Same as above (since this function takes in and outputs 2 pixels at a time) make sure that your dr, dg, db
            //functions are the same as the ones above for r0,g0,b0.
            dr = r1 - 255;
            dg = g1 - 0;
            db = b1 - 0;

            distance = 255 - floor(sqrt(dr*dr+dg*dg+db*db));
            if(distance<0){distance = 0;}
            r1 = distance;
            g1 = distance;
            b1 = distance;

            sumH=sumH+row*distance;
             sumW=sumW+col*distance;
             sumD=sumD+distance;
            row++;

            //prints the updated pixel information to the .ppm file
            fprintf( file, "%c%c%c%c%c%c",r0,g0,b0,r1,g1,b1); // Output two pixels

            i++;
        }
    }

    fclose (file);
    return(0);
}

The following Images are the result of the color distance on red:

Unfiltered image:

Filtered image:

Print Friendly

One thought on “Color Distance

  1. Pingback: Quadrocopters.comColor Distance | Autonomous Quadrocopter