1Histogram Calculation {#tutorial_histogram_calculation} 2===================== 3 4Goal 5---- 6 7In this tutorial you will learn how to: 8 9- Use the OpenCV function @ref cv::split to divide an image into its correspondent planes. 10- To calculate histograms of arrays of images by using the OpenCV function @ref cv::calcHist 11- To normalize an array by using the function @ref cv::normalize 12 13@note In the last tutorial (@ref tutorial_histogram_equalization) we talked about a particular kind of 14histogram called *Image histogram*. Now we will considerate it in its more general concept. Read on! 15 16### What are histograms? 17 18- Histograms are collected *counts* of data organized into a set of predefined *bins* 19- When we say *data* we are not restricting it to be intensity values (as we saw in the previous 20 Tutorial). The data collected can be whatever feature you find useful to describe your image. 21- Let's see an example. Imagine that a Matrix contains information of an image (i.e. intensity in 22 the range \f$0-255\f$): 23 24 ![](images/Histogram_Calculation_Theory_Hist0.jpg) 25 26- What happens if we want to *count* this data in an organized way? Since we know that the *range* 27 of information value for this case is 256 values, we can segment our range in subparts (called 28 **bins**) like: 29 30 \f[\begin{array}{l} 31 [0, 255] = { [0, 15] \cup [16, 31] \cup ....\cup [240,255] } \\ 32 range = { bin_{1} \cup bin_{2} \cup ....\cup bin_{n = 15} } 33 \end{array}\f] 34 35 and we can keep count of the number of pixels that fall in the range of each \f$bin_{i}\f$. Applying 36 this to the example above we get the image below ( axis x represents the bins and axis y the 37 number of pixels in each of them). 38 39 ![](images/Histogram_Calculation_Theory_Hist1.jpg) 40 41- This was just a simple example of how an histogram works and why it is useful. An histogram can 42 keep count not only of color intensities, but of whatever image features that we want to measure 43 (i.e. gradients, directions, etc). 44- Let's identify some parts of the histogram: 45 -# **dims**: The number of parameters you want to collect data of. In our example, **dims = 1** 46 because we are only counting the intensity values of each pixel (in a greyscale image). 47 -# **bins**: It is the number of **subdivisions** in each dim. In our example, **bins = 16** 48 -# **range**: The limits for the values to be measured. In this case: **range = [0,255]** 49- What if you want to count two features? In this case your resulting histogram would be a 3D plot 50 (in which x and y would be \f$bin_{x}\f$ and \f$bin_{y}\f$ for each feature and z would be the number of 51 counts for each combination of \f$(bin_{x}, bin_{y})\f$. The same would apply for more features (of 52 course it gets trickier). 53 54### What OpenCV offers you 55 56For simple purposes, OpenCV implements the function @ref cv::calcHist , which calculates the 57histogram of a set of arrays (usually images or image planes). It can operate with up to 32 58dimensions. We will see it in the code below! 59 60Code 61---- 62 63- **What does this program do?** 64 - Loads an image 65 - Splits the image into its R, G and B planes using the function @ref cv::split 66 - Calculate the Histogram of each 1-channel plane by calling the function @ref cv::calcHist 67 - Plot the three histograms in a window 68- **Downloadable code**: Click 69 [here](https://github.com/Itseez/opencv/tree/master/samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp) 70- **Code at glance:** 71 @include samples/cpp/tutorial_code/Histograms_Matching/calcHist_Demo.cpp 72 73Explanation 74----------- 75 76-# Create the necessary matrices: 77 @code{.cpp} 78 Mat src, dst; 79 @endcode 80-# Load the source image 81 @code{.cpp} 82 src = imread( argv[1], 1 ); 83 84 if( !src.data ) 85 { return -1; } 86 @endcode 87-# Separate the source image in its three R,G and B planes. For this we use the OpenCV function 88 @ref cv::split : 89 @code{.cpp} 90 vector<Mat> bgr_planes; 91 split( src, bgr_planes ); 92 @endcode 93 our input is the image to be divided (this case with three channels) and the output is a vector 94 of Mat ) 95 96-# Now we are ready to start configuring the **histograms** for each plane. Since we are working 97 with the B, G and R planes, we know that our values will range in the interval \f$[0,255]\f$ 98 -# Establish number of bins (5, 10...): 99 @code{.cpp} 100 int histSize = 256; //from 0 to 255 101 @endcode 102 -# Set the range of values (as we said, between 0 and 255 ) 103 @code{.cpp} 104 /// Set the ranges ( for B,G,R) ) 105 float range[] = { 0, 256 } ; //the upper boundary is exclusive 106 const float* histRange = { range }; 107 @endcode 108 -# We want our bins to have the same size (uniform) and to clear the histograms in the 109 beginning, so: 110 @code{.cpp} 111 bool uniform = true; bool accumulate = false; 112 @endcode 113 -# Finally, we create the Mat objects to save our histograms. Creating 3 (one for each plane): 114 @code{.cpp} 115 Mat b_hist, g_hist, r_hist; 116 @endcode 117 -# We proceed to calculate the histograms by using the OpenCV function @ref cv::calcHist : 118 @code{.cpp} 119 /// Compute the histograms: 120 calcHist( &bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate ); 121 calcHist( &bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate ); 122 calcHist( &bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate ); 123 @endcode 124 where the arguments are: 125 126 - **&bgr_planes[0]:** The source array(s) 127 - **1**: The number of source arrays (in this case we are using 1. We can enter here also 128 a list of arrays ) 129 - **0**: The channel (*dim*) to be measured. In this case it is just the intensity (each 130 array is single-channel) so we just write 0. 131 - **Mat()**: A mask to be used on the source array ( zeros indicating pixels to be ignored 132 ). If not defined it is not used 133 - **b_hist**: The Mat object where the histogram will be stored 134 - **1**: The histogram dimensionality. 135 - **histSize:** The number of bins per each used dimension 136 - **histRange:** The range of values to be measured per each dimension 137 - **uniform** and **accumulate**: The bin sizes are the same and the histogram is cleared 138 at the beginning. 139 140-# Create an image to display the histograms: 141 @code{.cpp} 142 // Draw the histograms for R, G and B 143 int hist_w = 512; int hist_h = 400; 144 int bin_w = cvRound( (double) hist_w/histSize ); 145 146 Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) ); 147 @endcode 148-# Notice that before drawing, we first @ref cv::normalize the histogram so its values fall in the 149 range indicated by the parameters entered: 150 @code{.cpp} 151 /// Normalize the result to [ 0, histImage.rows ] 152 normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); 153 normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); 154 normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() ); 155 @endcode 156 this function receives these arguments: 157 158 - **b_hist:** Input array 159 - **b_hist:** Output normalized array (can be the same) 160 - **0** and\**histImage.rows: For this example, they are the lower and upper limits to 161 normalize the values ofr_hist*\* 162 - **NORM_MINMAX:** Argument that indicates the type of normalization (as described above, it 163 adjusts the values between the two limits set before) 164 - **-1:** Implies that the output normalized array will be the same type as the input 165 - **Mat():** Optional mask 166 167-# Finally, observe that to access the bin (in this case in this 1D-Histogram): 168 @code{.cpp} 169 /// Draw for each channel 170 for( int i = 1; i < histSize; i++ ) 171 { 172 line( histImage, Point( bin_w*(i-1), hist_h - cvRound(b_hist.at<float>(i-1)) ) , 173 Point( bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)) ), 174 Scalar( 255, 0, 0), 2, 8, 0 ); 175 line( histImage, Point( bin_w*(i-1), hist_h - cvRound(g_hist.at<float>(i-1)) ) , 176 Point( bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)) ), 177 Scalar( 0, 255, 0), 2, 8, 0 ); 178 line( histImage, Point( bin_w*(i-1), hist_h - cvRound(r_hist.at<float>(i-1)) ) , 179 Point( bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)) ), 180 Scalar( 0, 0, 255), 2, 8, 0 ); 181 } 182 @endcode 183 we use the expression: 184 @code{.cpp} 185 b_hist.at<float>(i) 186 @endcode 187 where \f$i\f$ indicates the dimension. If it were a 2D-histogram we would use something like: 188 @code{.cpp} 189 b_hist.at<float>( i, j ) 190 @endcode 191 192-# Finally we display our histograms and wait for the user to exit: 193 @code{.cpp} 194 namedWindow("calcHist Demo", WINDOW_AUTOSIZE ); 195 imshow("calcHist Demo", histImage ); 196 197 waitKey(0); 198 199 return 0; 200 @endcode 201 202Result 203------ 204 205-# Using as input argument an image like the shown below: 206 207 ![](images/Histogram_Calculation_Original_Image.jpg) 208 209-# Produces the following histogram: 210 211 ![](images/Histogram_Calculation_Result.jpg) 212