1D Histogram on OpenCV

I started working on OpenCV this week, and it had been quite a journey.
I started with some easy programs. However, there is a new (at least for me is new) version of OpenCV with wrappers for C++. Therefore, the examples in the web, most of the time, do not work as they are.
So, today I will show you some of the work I’ve done deciphering the examples that work with the C code for the new wrappers.
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.
The idea is the same, but I change the functionality to work with OpenCV v2.2.
First, you need to create the histogram options, I think is really annoying, but it gives you more control over your final histogram.
int nbins = 256; // lets hold 256 levels
int hsize[] = { nbins }; // just one dimension
float range[] = { 0, 255 };
const float *ranges[] = { range };
int chnls[] = {0};
with this code, you create only one dimensional histogram with 256 bins in the range of 0 to 255, and you specify to work with the channel 0 (the only channel). If you need more dimensions just add them in the hsize and ranges variables. If you see further, the histogram computation is designed to work with several dimensions, that’s why we need to pass arrays to it.
Then you just need to compute the histogram using
<pre> calcHist(&colors[0], 1, chnls, Mat(), hist,1,hsize,ranges);</pre>
Note that the histogram image hist must be a MatND or a SparceMat. Then to render the histogram just compute the rectangles for each bin using the fillConvexPoly function. The full code looks like this. You can download the files here, please change the extension to rar to use them. It contains a CMakeLists to build it using CMake.
HTH
, I hope to be posting more on this topics soon.
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
Mat imHist(Mat hist, float scaleX=1, float scaleY=1){
double maxVal=0;
minMaxLoc(hist, 0, &maxVal, 0, 0);
int rows = 64; //default height size
int cols = hist.rows; //get the width size from the histogram
Mat histImg = Mat::zeros(rows*scaleX, cols*scaleY, CV_8UC3);
//for each bin
for(int i=0;i<cols-1;i++) {
float histValue = hist.at<float>(i,0);
float nextValue = hist.at<float>(i+1,0);
Point pt1 = Point(i*scaleX, rows*scaleY);
Point pt2 = Point(i*scaleX+scaleX, rows*scaleY);
Point pt3 = Point(i*scaleX+scaleX, (rows-nextValue*rows/maxVal)*scaleY);
Point pt4 = Point(i*scaleX, (rows-nextValue*rows/maxVal)*scaleY);
int numPts = 5;
Point pts[] = {pt1, pt2, pt3, pt4, pt1};
fillConvexPoly(histImg, pts, numPts, Scalar(255,255,255));
}
return histImg;
}
int main( int argc, char** argv ) {
// check for supplied argument
if( argc < 2 ) {
cout << "Usage: loadimg <filename>\n" << endl;
return 1;
}
// load the image, load the image in grayscale
Mat img = imread( argv[1], CV_LOAD_IMAGE_COLOR );
// always check
if( img.data == NULL ) {
cout << "Cannot load file " << argv[1] << endl;
return 1;
}
//Hold the histogram
MatND hist;
Mat histImg;
int nbins = 256; // lets hold 256 levels
int hsize[] = { nbins }; // just one dimension
float range[] = { 0, 255 };
const float *ranges[] = { range };
int chnls[] = {0};
// create colors channels
vector<Mat> colors;
split(img, colors);
// compute for all colors
calcHist(&colors[0], 1, chnls, Mat(), hist,1,hsize,ranges);
histImg = imHist(hist,3,3);
imshow("Blue",histImg);
calcHist(&colors[1], 1, chnls, Mat(), hist,1,hsize,ranges);
histImg = imHist(hist,3,3);
imshow("Green",histImg);
calcHist(&colors[2], 1, chnls, Mat(), hist,1,hsize,ranges);
histImg = imHist(hist,3,3);
imshow("Red",histImg);
// show image
imshow("Image", img);
// wait until user press a key
waitKey(0);
// no need to release the memory, Mat do it for you
return 0;
}





nice work..