Home | History | Annotate | Download | only in histogram_calculation
      1 Histogram Calculation {#tutorial_histogram_calculation}
      2 =====================
      3 
      4 Goal
      5 ----
      6 
      7 In 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
     14 histogram 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 
     56 For simple purposes, OpenCV implements the function @ref cv::calcHist , which calculates the
     57 histogram of a set of arrays (usually images or image planes). It can operate with up to 32
     58 dimensions. We will see it in the code below!
     59 
     60 Code
     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 
     73 Explanation
     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 
    202 Result
    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