# calHist() - Calculate histogram using openCV and C++

In practically every element of computer vision, histograms are used. For threshold, we employ gray-scale histograms. For white balance, we employ histograms. For object tracking in photos, such as with the CamShift technique, we use colour histograms. Color histograms are used as features, and colour histograms in several dimensions are included.

In a more abstract sense, they form the HOG and SIFT descriptors from histograms of visual gradients.

A histogram is also a bag-of-visual-words representation, which is widely employed in image search engines and machine learning. And, more than likely, this isn’t the first time you’ve seen histograms in your studies.

So, why do histograms come in handy?

Because histograms depict a set of data frequency distribution. And it turns out that looking at these frequency distributions is a dominant method to develop simple image processing techniques... as well as really powerful machine learning algorithms.

This blog post will summarize image histograms, as well as how to calculate colour histograms from video using openCV and C++.

## What is Histogram ?

You might think of a histogram as a graph or plot that shows how an image’s intensity distribution is distributed. It’s a graph with pixel values (usually ranging from 0 to 255) on the X-axis and the number of pixels in the picture on the Y-axis.

It’s just a different way of looking at the image. When you look at the histogram of an image, you may get a sense of the image’s contrast, brightness, intensity distribution, and so on.

Almost all image processing software today includes a histogram feature.

## calHist() function in openCV

`cv.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])`

So now we use calcHist() function to find the histogram. Let’s familiarize with the function and its parameters :

1. images : this is the uint8 or float32 source image.

[img]” should be written in square brackets.

1. channels: It is the channel index for which the histogram is calculated.

If the input is a gray-scale image, the value is [0].

To calculate the histogram of the blue, green, or red channel in a colour image, pass [0], [1], or [2].

1. mask: It is given as “None” to find the histogram of the entire image.

But if you want to find histogram of a particular region of image, create a mask image for that and give it as a mask.

1. histSize: Our BIN count is represented by histSize. Must be enclosed in square brackets. We pass [256] for full scale.

2. range: It’s usually [0,256].

## Code

``` #include "opencv2/highgui.hpp" #include "opencv2/imgcodecs.hpp" #include "opencv2/imgproc.hpp" #include <iostream> const int histSize = 256; void drawHistogram(cv::Mat& b_hist,cv::Mat& g_hist,cv::Mat& r_hist) { int hist_w = 512; int hist_h = 400; int bin_w = cvRound((double)hist_w / histSize); cv::Mat histImage(hist_h, hist_w, CV_8UC3, cv::Scalar(0, 0, 0)); cv::normalize(b_hist, b_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat()); cv::normalize(g_hist, g_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat()); cv::normalize(r_hist, r_hist, 0, histImage.rows, cv::NORM_MINMAX, -1, cv::Mat()); for (int i = 1; i < histSize; i++) { cv::line( histImage, cv::Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))), cv::Point(bin_w * (i), hist_h - cvRound(b_hist.at<float>(i))), cv::Scalar(255, 0, 0), 2, 8, 0); cv::line( histImage, cv::Point(bin_w * (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))), cv::Point(bin_w * (i), hist_h - cvRound(g_hist.at<float>(i))), cv::Scalar(0, 255, 0), 2, 8, 0); cv::line( histImage, cv::Point(bin_w * (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))), cv::Point(bin_w * (i), hist_h - cvRound(r_hist.at<float>(i))), cv::Scalar(0, 0, 255), 2, 8, 0); } cv::namedWindow("calcHist Demo", cv::WINDOW_AUTOSIZE); cv::imshow("calcHist Demo", histImage); } int main(int argc, char **argv) { cv::Mat src, dst; cv::VideoCapture cap; if (argc != 2) cap.open(0); else cap.open(argv[1]); if (!cap.isOpened()) { std::cerr << "Failed to load webcam/Video ...\n"; return -1; } for (;;) { if(!cap.read(src)) { std::cerr << "Cannot read file\n"; break; } cv::imshow("Src", src); std::vector<cv::Mat> bgr_planes; cv::split(src, bgr_planes); float range[] = {0, 256}; const float *histRange = {range}; bool uniform = true; bool accumulate = false; cv::Mat b_hist, g_hist, r_hist; cv::calcHist(&bgr_planes[0], 1, 0, cv::Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate); cv::calcHist(&bgr_planes[1], 1, 0, cv::Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate); cv::calcHist(&bgr_planes[2], 1, 0, cv::Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate); drawHistogram(b_hist,g_hist,r_hist); if (cv::waitKey(30) == 27) break; } return 0; } ```

## Explanation

• We start the code by first reading our input file, which is a video frame by frame using `cap.read()` method.

• Using split() function we divide multi-channel array (i.e RGB) into separate single-channel array which we store in `bgr_planes`.

• Then we calculate histogram of each plane and stores value in the variable `b_hist`,`g_hist`,`r_hist`.

• In our histogram we want our bins to have same size and we want to clear our histogram at the beginning therefore, we set `uniform` and `accumulate` to `true.

• After calculating histogram we create an image `histImage` to display our histogram.

• Then we simply draw the line using cv::line at each pixel for each channel i.e `b_hist`,`g_hist`,`r_hist`.