Phone Vision – 07 Grayscale

24 01 2011

Many useful image processing concepts are simpler and faster without color information, so now that you have a solid grasp of color, let’s remove it and take a look at the world in grayscale. 

Conversion

Grayscale is a measure of the intensity of the total light at a given point.  Because the ranges for red, green, and blue in the WriteableBitmap are from 0 to 255 it is convenient for us to set the grayscale ranges similarly where the absence of light (black) is 0 and maximum intensity (white) is 255.  We just need a method to extract this intensity from the color values.

I always go with my gut and it says we should be able to average the color intensities.  Time to put on the coding gloves.

WriteableBitmap ToAverageGrayscale(WriteableBitmap bmp)

{

    WriteableBitmap grayscale =

        new WriteableBitmap(bmp.PixelWidth, bmp.PixelHeight);

    for (int pixelIndex = 0;

        pixelIndex < bmp.Pixels.Length;

        pixelIndex++)

    {

        int pixelColor = bmp.Pixels[pixelIndex];

        byte red = (byte)((pixelColor & 0xFF0000) >> 16);

        byte green = (byte)((pixelColor & 0xFF00) >> 8);

        byte blue = (byte)(pixelColor & 0xFF);

 

        byte intensity = (byte)((red + green + blue) / 3);

 

        //notice how we repeat the intensity

        //across each color channel

        //this makes the output "color neutral"

        //i.e. gray

        grayscale.Pixels[pixelIndex] = 255 << 24

            | intensity << 16

            | intensity << 8

            | intensity;

    }

    return grayscale;

}

Easy peasy lemon squeezy.

image

This looks like mission accomplished to me.

However, we are going from over 16 million colors to 256 intensities.  Obviously we are going to lose information.  How do we know that we are keeping the best information? 

Any three numbers can represent six separate colors, but only one intensity.  the following example uses the numbers 255, 128, and 64:

image

six_colorssix_straight_gray

Simply averaging the numbers will work fine in many situations, but in this situation it breaks down. 

If we are trying to approximate the brightness a human perceives, mimicking human physiology is a better approach.  In the last lesson, the Bayer filter had twice as many green filters as red or blue because humans are more sensitive to green frequencies.   Green colors should then appear brighter than other colors right?

We can modify our code to be slightly more intelligent by weighting the average toward the green colors.

WriteableBitmap ToWeightedGrayscale(

    WriteableBitmap bmp,

    double redWeight,

    double greenWeight,

    double blueWeight)

{

    WriteableBitmap grayscale =

        new WriteableBitmap(bmp.PixelWidth, bmp.PixelHeight);

    for (int pixelIndex = 0;

        pixelIndex < bmp.Pixels.Length;

        pixelIndex++)

    {

        int pixelColor = bmp.Pixels[pixelIndex];

        byte red = (byte)((pixelColor & 0xFF0000) >> 16);

        byte green = (byte)((pixelColor & 0xFF00) >> 8);

        byte blue = (byte)(pixelColor & 0xFF);

 

        //notice that we are dividing by the sum of the weights

        //this can be avoided by ensuring the weights add to 1

        byte intensity = (byte)((red * redWeight

            + green * greenWeight

            + blue * blueWeight)

        / (redWeight + greenWeight + blueWeight));

 

        grayscale.Pixels[pixelIndex] =

            255 << 24

            | intensity << 16

            | intensity << 8

            | intensity;

    }

    return grayscale;

}

Weights that work well for human vision are red = .2, green = .7, and blue =.1 (rounded from Frequently Asked Questions about Color by Charles Poynton).

six_colors

six_weighted_gray

As you should expect, the green colors are brighter.  If you want a grayscale image to match the perceived brightness of the color image, this technique does the job.  Is it better than the simple average?  In our contrived example, yes.  In many cases, the simple average will suffice.  Here is the grayscale orangutan using both techniques.  Can you guess which is simple and which is weighted?

 

image

(hint: the bottom one is weighted)

 

Summary

 

Bottom line: there is no “right” answer.  If you’re trying to make your grayscale image “look” right, the weights used above may be a good path.  If speed is your game, you might try just using the  green channel alone.  No technique is right for every situation.  Remember, our end goal is for the phone, not a person, to understand the image.  Have fun and play around with the numbers.  Think about the advantages and disadvantages of different techniques. 

 

I highly recommend the Frequently Asked Questions about Color by Charles Poynton.  Warning: some of it is pretty math intensive.

 

Download Code

http://cid-88e82fb27d609ced.office.live.com/embedicon.aspx/Blog%20Files/PhoneVision/PhoneVision%2007%20-%20Grayscale.zip

 

Up next: Intro to Histograms

follow @azzlsoft

 


Actions

Information

3 responses

24 01 2011
Phone Vision 06 – RGB Color Intensities «

[…] Up next: Grayscale […]

25 01 2011
Tweets that mention Phone Vision – 07 Grayscale « -- Topsy.com

[…] This post was mentioned on Twitter by Electronics Perch, Indrajit Chakrabarty and Ginny Caughey, Azzl. Azzl said: See the world in grayscale with your WP7 phone. http://bit.ly/dKa0yM #wp7dev […]

27 01 2011
Phone Vision 08 – Intro to Histograms «

[…] Vision 08 – Intro to Histograms 27 01 2011 Now that we’ve finally manipulated a few images we’re starting to get somewhere.   Today we are going to take some strides in […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s




%d bloggers like this: