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 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!


28 Comments
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?
Hmm.. not sure what you mean.. Just sent you a mail!
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
Thanks!
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
Hmm. Are you sure your code is correct?
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
Hmm… weird. “could you tell me I have to de in case of restricting only for greylevel images???” what do you mean?
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 ?
Zero out the image just after creating it –
cvZero(imgGrey). then calculate its histogram. See if this gets you a different result.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?
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.
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
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.
Is the fucntiong DrawHistogram() written by youself, or the souce code implemented in the Opencv Lib. Anyway, very impressive and helpful.
Written by me. It’s not a part of the OpenCV library.
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?
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.
Maybe a typecast will do the trick? Put your code on pastebin and we’ll try figure it out.
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?
Images are matrices too. You just pass a matrix instead of an image and things should work.
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…
This is weird. The documentation states you can pass a CvMat** as well
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.
You need to use cvCvtColor. It converts an image from one color space to another.
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?
thank you
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
[...] 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. [...]