Drawing Histograms in OpenCV

Here we’ll be generating the levels histograms you see in Photoshop. You load an image and the R, G and B histograms are calculated and rendered. We’ll make a very flexible function which you can reuse in your own projects too.

Loading and splitting the image

First, create a new project. Include the standard OpenCV headers:

#include <cv.h>
#include <highgui.h>

Next, we get to the main function:

void main()
{

The first thing to do: load an image

    IplImage* img = cvLoadImage("C:\\orangeman.jpg");

Next, we create and initialize a histogram:

    int numBins = 256;
    float range[] = {0, 255};
    float *ranges[] = { range };
 
    CvHistogram *hist = cvCreateHist(1, &numBins, CV_HIST_ARRAY, ranges, 1);
    cvClearHist(hist);

Here, we’re creating a uniform 1-D histogram with 256 bins. We supply the range as 0-255. The cvCreateHist function automatically divides this range into 256 bins.

Next, we split the original colour image into its channels. We allocate memory and use the cvSplit function to break it into constituent channels:

    IplImage* imgRed = cvCreateImage(cvGetSize(img), 8, 1);
    IplImage* imgGreen = cvCreateImage(cvGetSize(img), 8, 1);
    IplImage* imgBlue = cvCreateImage(cvGetSize(img), 8, 1);
 
    cvSplit(img, imgBlue, imgGreen, imgRed, NULL);

The BGR order in the cvSplit command is important. Usually when an image is loaded, this is how its stored in memory.

Rendering histograms

Using the red channel, we can calculate and draw its histogram:

    cvCalcHist(&imgRed, hist, 0, 0);
    IplImage* imgHistRed = DrawHistogram(hist);
    cvClearHist(hist);

The cvCalcHist function calculates the histogram for the image imgRed and stores it into hist. imgHistRed image holds the visual for the histogram. The DrawHistogram function draw it. We’ll get to it in a minute.

Finally, we clear the histogram. We’re done with the red channel, so we’ll reuse it for the green and blue channels too:

    cvCalcHist(&imgGreen, hist, 0, 0);
    IplImage* imgHistGreen = DrawHistogram(hist);
    cvClearHist(hist);
 
    cvCalcHist(&imgBlue, hist, 0, 0);
    IplImage* imgHistBlue = DrawHistogram(hist);
    cvClearHist(hist);

Then we display these histograms in their own little windows:

    cvNamedWindow("Red");
    cvNamedWindow("Green");
    cvNamedWindow("Blue");
 
    cvShowImage("Red", imgHistRed);
    cvShowImage("Green", imgHistGreen);
    cvShowImage("Blue", imgHistBlue);
 
    cvWaitKey(0);
}

The cvWaitKey ensures that the windows don’t close automatically. You need to press a key to continue.
With that, the main function is done. Now we’ll create the DrawHistogram function.

A function to draw histograms

Begin by defining the parameters:

IplImage* DrawHistogram(CvHistogram *hist, float scaleX=1, float scaleY=1)
{

The function takes one histgoram (that it needs to render) and the scale on the X and Y axes. By default the histogram size is 256×64. Using the scale factors, you can get whatever size you want.

The values in the histogram can be extremely varied. From values less than 0.1 to greater than 1000. We need to fit all these into an image with a finite number of pixels.

So we figure out the maximum value of the histogram. Using this maximum, we scale the other values so they fit into the vertical size of the image:

    float histMax = 0;
    cvGetMinMaxHistValue(hist, 0, &histMax, 0, 0);

Next, we create and blank out an image of the desired size:

    IplImage* imgHist = cvCreateImage(cvSize(256*scaleX, 64*scaleY), 8 ,1);
    cvZero(imgHist);

Then, we go through all bins and render out the graphic:

    for(int i=0;i<255;i++)
    {
        float histValue = cvQueryHistValue_1D(hist, i);
        float nextValue = cvQueryHistValue_1D(hist, i+1);
 
        CvPoint pt1 = cvPoint(i*scaleX, 64*scaleY);
        CvPoint pt2 = cvPoint(i*scaleX+scaleX, 64*scaleY);
        CvPoint pt3 = cvPoint(i*scaleX+scaleX, (64-nextValue*64/histMax)*scaleY);
        CvPoint pt4 = cvPoint(i*scaleX, (64-histValue*64/histMax)*scaleY);
 
        int numPts = 5;
        CvPoint pts[] = {pt1, pt2, pt3, pt4, pt1};
 
        cvFillConvexPoly(imgHist, pts, numPts, cvScalar(255));
    }

Finally, we return the image we created:

    return imgHist;
}

Two things to remember with this function.

  • You’re allocating memory in the function. So no need to do it anywhere else
  • Since the memory is allocated withing the image and not released, you must ensure it gets released when its work is done

How the rendering works?

To draw the histogram, the cvFillConvexPoly function is used. This function can draw filled polygons. You pass the array of points and the number of points along with the color and it does its job.

The polygon used to render the histogramThe points pt1…pt4 are calculated and this polygon is rendered using the cvFillConvexPoly function. This is done for every single bin.

This polygon method produces relatively better results than simply drawing a straight vertical line at the center of a bin. If you did  the latter, you’d get a result like the black part. With the polygon method, values “in-between” get rendered as well.

Summary

With this post, you have a handy function that you can use to render out any 1D histogram. Just make sure it is 1D and not a sparse histogram. I haven’t added any checks for that.

Got any ideas/suggestions/criticism? Leave a comment below!

Issues? Suggestions? Visit the Github issue tracker for AI Shack

Back to top

28 Comments

  1. pafe
    Posted September 30, 2010 at 6:33 pm | Permalink

    Hi! How can be possible to create histograms for y and x axes of the same image, for example for iris detection, where it is necessary to create two histograms to underline the deepness of image?

    • Posted October 2, 2010 at 10:35 am | Permalink

      Hmm.. not sure what you mean.. Just sent you a mail!

  2. Leandro Batista
    Posted November 6, 2010 at 12:39 am | Permalink

    Hi there,

    Your clear and tidy explanation have just helped me here. Thanks. Futhermore, your website is oustanding. Congratulations.

    Once more,
    Thanks
    Leandro Batista, Brasilia – Brazil

  3. Yve Meh
    Posted January 16, 2011 at 8:12 pm | Permalink

    Hi, It’s so interessting site !

    I’ve tried your code on gray level image, taking one chanel
    but always I have a reuslt the same histogram, other words identical histogram for different images?
    could you give me some suggestions ??

    thanks in advance

    • Posted January 19, 2011 at 9:51 pm | Permalink

      Hmm. Are you sure your code is correct?

      • Yve
        Posted January 24, 2011 at 3:02 am | Permalink

        thanx for ur reply
        yes I’m sure
        all what I did is the same what you suggested in the code on only one chanel !! I still have identical Histogram for different images

        could you tell me I have to de in case of restricting only for greylevel images???

        thanks

        • Posted January 28, 2011 at 7:01 pm | Permalink

          Hmm… weird. “could you tell me I have to de in case of restricting only for greylevel images???” what do you mean?

  4. Yve
    Posted February 4, 2011 at 10:34 pm | Permalink

    What I ment is when I try to draw a histogram of an grey images using your code I get always the same result, just could you help please

    see the modified code : and tell me where is the problem ?

    int numBins = 256;
    float range[] = {0, 255};
    float *ranges[] = { range };	
     
    CvHistogram *hist = cvCreateHist(1, &numBins, CV_HIST_ARRAY, ranges, 1);
    cvClearHist(hist);
     
    IplImage* imgGrey = cvCreateImage(cvGetSize(src1), 8, 1);	
    cvCalcHist(&imgGrey, hist, 0, 0);
     
    IplImage* imgHistGrey = DrawHistogram(hist);	// Draw it using the same your own finction
    cvClearHist(hist);	
     
    cvNamedWindow(Grey);
    cvShowImage(Grey, imgHistGrey );	
    cvWaitKey(0);
    • Posted February 11, 2011 at 2:02 pm | Permalink

      Zero out the image just after creating it – cvZero(imgGrey). then calculate its histogram. See if this gets you a different result.

      • kay
        Posted September 18, 2011 at 12:08 pm | Permalink

        hi, thanks 4 nice post.
        what is mean “Zero out the image just after creating it”. what should i do? what code must be added?

        • Posted January 10, 2012 at 11:29 pm | Permalink

          By that I mean setting each pixel to zero. There might be some garbage values on pixels, so just to be sure set all pixels to zero.

  5. AMN
    Posted February 9, 2011 at 3:07 am | Permalink

    Hi
    Firstly I thank u for this useful web site really I appreciate it, secondely if u don’t mind I would like to ask u a question :
    Can we draw a histogram of a set of integer like an array or matrix ?and witch instruction can we use it?
    Thanks again I’m waitting your answer

    • Posted February 9, 2011 at 3:13 pm | Permalink

      I don’t think there’s any instruction for doing that. You’ll have to write code for it. Or maybe you could convert your array into an IplImage and then follow the code here.

  6. yu zhao
    Posted April 20, 2011 at 7:46 am | Permalink

    Is the fucntiong DrawHistogram() written by youself, or the souce code implemented in the Opencv Lib. Anyway, very impressive and helpful.

    • Posted April 29, 2011 at 7:59 pm | Permalink

      Written by me. It’s not a part of the OpenCV library.

      • yu zhao
        Posted April 30, 2011 at 6:56 am | Permalink

        I am studying the image segmentation recently. So what segmentation functions dose opencv provide for us? As far as I have known, cvKMeans2(), cvPyrMeanShiftFiltering(), cvPyrSegmentation.
        And how to evaluate the results of the segmentation. Is there some objective criteria?

  7. Jeffrey
    Posted May 17, 2011 at 8:10 am | Permalink

    Hi,I got a problem when I runnning your program.
    It displays ” error C2440: ‘initializing’ : cannot convert from ‘struct CvPoint’ to ‘int’ ”
    I do not know how to debug this,so I need your help.
    I use Visual C++6.0 and OpenCV 1.0.

    • Posted June 17, 2011 at 4:40 pm | Permalink

      Maybe a typecast will do the trick? Put your code on pastebin and we’ll try figure it out.

  8. Tsieki
    Posted July 11, 2011 at 5:11 pm | Permalink

    Nice site! very helpful!

    I ‘d like to ask you how we can make the histogram of a 2d matrix in opencv?

    Everything that i have found so far is about images. Is there a way to calculate histograms of matrices as well?

    • Posted July 13, 2011 at 9:16 am | Permalink

      Images are matrices too. You just pass a matrix instead of an image and things should work.

      • Tsieki
        Posted July 13, 2011 at 12:40 pm | Permalink

        Thanks for your reply!

        I use the command

        CvMat* x_matrix = cvCreateMat ( 1, ParticleNum, CV_32FC1);
        cvCalcHist( & x_matrix, hist, 0, NULL);

        isn’t it correct? and i get the error:

        “error C2664: ‘cvCalcHist’ : cannot convert parameter 1 from ‘CvMat **__w64 ‘ to ‘IplImage **’”
        it seems as if it doesn’t work for CvMat… :(

  9. Arvin
    Posted July 20, 2011 at 10:49 pm | Permalink

    Hi, I think this is a very interesting and useful blog you have here. Keep it up. I’m currently working on a Histogram Equalizer Project and I’m new to OpenCV. I can’t figure out how to get the RGB values of an image to transform them to HSI. Can you help me with getting the RGB values of the image?

    Thanks a lot.

    • Posted August 9, 2011 at 7:45 pm | Permalink

      You need to use cvCvtColor. It converts an image from one color space to another.

  10. donny
    Posted August 24, 2011 at 7:23 pm | Permalink

    i have change from BGR to GRAY using cvCvtColor, then i set threshold value to segment the image and it will produce 2 group of pixel. one consist of all pixel with gray level
    values > Threshold and another one consist of pixels with values <=Threshold.
    how can i segment the image and then find the hitogram for both?

  11. wassim
    Posted September 23, 2011 at 5:12 pm | Permalink

    thank you :-)

  12. Fadime
    Posted September 24, 2011 at 3:04 pm | Permalink

    Hi,if you don’t mind can i ask a question about my project
    how can i access black and white values of a picture’s pixels? I want to read barkod with OpenCV.

One Trackback

  • By 1D Histogram on OpenCV « La Consigna on April 29, 2011 at 6:16 pm

    [...] OK, lets see. I wanted to do a simple histogram visualization of an image. But, all the examples in the web deal with two dimensional histograms, or with the old syntax. After checking a couple of webs I came up with a solution inspired by this post. [...]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>