Phone 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 classifying images.  It would be nice if we had an objective way to say “that image is really bright”.  It shouldn’t come as a surprise that this is actually pretty easy.

What is a Histogram?

Histogram is really just a fancy word for counting.  In our case, we are counting how many pixels are at each intensity level between black and white.  Let’s revisit our friendly orangutan.

image

The chart below the picture is his histogram.  The horizontal-axis represents the intensity while the vertical-axis represents the number of pixels with that intensity. 

Creating the Histogram

When you are converting an image to grayscale you can trivially create the histogram data with it.  The process is as simple as looping through every pixel (which we have to do to convert to grayscale anyway) and adding up the intensities.

//we are going to use the

//average of the r, g, and b

//values for our grayscale conversion

WriteableBitmap ToAverageGrayscale(WriteableBitmap bmp)

{

    WriteableBitmap grayscale =

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

 

    //there are 256 intensities

    //so a simple array of the ints

    //should suffice for holding the counts

    int[] histogramData = new int[256];

 

    //we will use this to determine

    //what the number of the highest

    //occurring intensity is

    //we are simply going to use this value

    //to scale our plot

    int maxCount = 0;

 

    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);

 

        //this is not rocket science

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

 

        //once again we repeat the intensity

        grayscale.Pixels[pixelIndex] = 255 << 24

            | intensity << 16

            | intensity << 8

            | intensity;

 

        //simply add another to the count

        //for that intensity

        histogramData[intensity]++;

 

        if (histogramData[intensity] > maxCount)

        {

            maxCount = histogramData[intensity];

        }

    }

 

    //this would typically be a completely

    //separate function, but it’s easier

    //in this case to perform the operation

    //with the grayscale conversion

    PlotHistogram(histogramData, maxCount);

    return grayscale;

}

 

public void PlotHistogram(int[] counts, int maxCount)

{

    //in MainPage we have a canvas that will

    //hold the histogram rectangles

    HistogramPlot.Children.Clear();

 

    //our tallest rectangle will be the height

    //of the canvas, so we want to scale the

    //them down from there

    double scale = HistogramPlot.Height / maxCount;

 

    //in our case we will always have 256 counts

    //but better safe than sorry

    double rectWidth = HistogramPlot.Width / counts.Length;

 

    for (int intensity = 0; intensity < counts.Length; intensity++)

    {

        //there is no magic going on here

        //for each intensity we are going to build

        //a rectangle with a height proportional to

        //its count

        Rectangle histRect = new Rectangle();

        histRect.Width = rectWidth;

        histRect.Height = counts[intensity] * scale;

        histRect.SetValue

            (Canvas.LeftProperty,

            intensity * rectWidth);

 

        histRect.SetValue

            (Canvas.TopProperty,

            HistogramPlot.Height – histRect.Height);

 

        //the gradient isn’t necessary

        //it just gives the fill a little

        //softer look

        LinearGradientBrush rectFill = new LinearGradientBrush();

        rectFill.GradientStops.Add(

            new GradientStop() {

                Color =

                Color.FromArgb(

                255,

                (byte)intensity,

                (byte)intensity,

                (byte)intensity),

            Offset = 0 });

 

        rectFill.GradientStops.Add(new GradientStop() {

            Color = Color.FromArgb(

            255,

            (byte)(.25 * intensity),

            (byte)(.25 * intensity),

            (byte)(.25 * intensity)),

            Offset = 1 });

 

        histRect.Fill = rectFill;

 

        //finally, let’s add it to the canvas

        HistogramPlot.Children.Add(histRect);

    }

}

It really is pretty simple. 

What now?

The histogram offers us an objective method for classifying images.  For instance, based on the histogram below we might say the crane is not too dark and not too light. Because it doesn’t use the entire range, however,  we might classify this as having low contrast.  Trust me, this will come in handy in future lessons.

image

Summary

Creating a histogram is really easy, and it gives us some basic statistics.  It doesn’t take a wild imagination to come up with some ways to use this information. Over the next few lessons we will do just that.

Download Code

http://cid-88e82fb27d609ced.office.live.com/embedicon.aspx/Blog%20Files/PhoneVision/PhoneVision%2008%20-%20Intro%20to%20Histograms.zip

Up next: Contrast Stretching

follow @azzlsoft