# opencv学习系列——绘制给定图片的直方图分布

## 绘制给定图片的直方图分布

（代码在文末~~）

### 直方图显示

（1）先不考虑第四通道，给定一张3通道的图片，首先把多通道图片分成单通道，对每个通道计算直方图。计算直方图直接调用cv中的calcHist函数：
calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false )
（2）这里使用一张颜色比较丰富的图片为例：

（3）得到各个通道的直方图如下所示：

（4）三个通道的直方折线图放在一起如下所示：

### 直方图均值化

（5）直方图应用——直方图均值化

//彩色图像直方图均衡化

#include<opencv2/opencv.hpp>
#include<iostream>
#include<cmath>

using namespace cv;
using namespace std;

const char* output = "histogram iamge";

int main(int argc, char* argv)
{
Mat src, dst, dst1;
if (!src.data)
{
return -1;
}
char input[] = "input image";
namedWindow(input, 0);
namedWindow(output, 0);
resizeWindow(input, 600, 400);
imshow(input, src);

//分割通道
vector<Mat>channels;
split(src, channels);

Mat blue, green, red;
blue = channels.at(0);
green = channels.at(1);
red = channels.at(2);
//分别对BGR通道做直方图均衡化
equalizeHist(blue, blue);
equalizeHist(green, green);
equalizeHist(red, red);
//合并通道
merge(channels, dst);
resizeWindow(output, 600, 400);
imshow(output, dst);

waitKey(0);
return 0;
}

//获得直方图
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{

//----------------------example 1-------------------------------//
Mat src, dst;

if (!src.data)
{
cout << "load image failed" << endl;
return -1;
}

/// Separate the image in 3 places ( R, G and B )
vector<Mat> rgb_planes;

Mat hsv;
cvtColor(src, hsv, COLOR_BGR2HSV);
split(hsv, rgb_planes);

split(src, rgb_planes);

/// Establish the number of bins
int histSize = 256;

/// Set the ranges ( for R,G,B) )
float range[] = { 0, 255 };
const float* histRange = { range };

bool uniform = true; bool accumulate = false;

Mat r_hist, g_hist, b_hist;

/// Compute the histograms:
calcHist(&rgb_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate);
calcHist(&rgb_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate);
calcHist(&rgb_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate);

// Draw the histograms for R, G and B
int hist_w = 600; int hist_h = 400;
int bin_w = cvRound((double)hist_w / histSize);

Mat rgb_hist[3];
for (int i = 0; i < 3; ++i)
{
rgb_hist[i] = Mat(hist_h, hist_w, CV_8UC3, Scalar::all(0));
}

Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0));

/// Normalize the result to [ 0, histImage.rows-10]
normalize(r_hist, r_hist, 0, histImage.rows - 10, NORM_MINMAX);
normalize(g_hist, g_hist, 0, histImage.rows - 10, NORM_MINMAX);
normalize(b_hist, b_hist, 0, histImage.rows - 10, NORM_MINMAX);

/// Draw for each channel
for (int i = 1; i < histSize; i++)
{
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(r_hist.at<float>(i))),
Scalar(0, 0, 255), 1);
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(g_hist.at<float>(i))),
Scalar(0, 255, 0), 1);
line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
Point(bin_w * (i), hist_h - cvRound(b_hist.at<float>(i))),
Scalar(255, 0, 0), 1);
}

for (int j = 0; j < histSize; ++j)
{
int val = saturate_cast<int>(r_hist.at<float>(j));
rectangle(rgb_hist[0], Point(j * 2 + 10, rgb_hist[0].rows), Point((j + 1) * 2 + 10, rgb_hist[0].rows - val), Scalar(0, 0, 255), 1, 8);

val = saturate_cast<int>(g_hist.at<float>(j));
rectangle(rgb_hist[1], Point(j * 2 + 10, rgb_hist[1].rows), Point((j + 1) * 2 + 10, rgb_hist[1].rows - val), Scalar(0, 255, 0), 1, 8);

val = saturate_cast<int>(b_hist.at<float>(j));
rectangle(rgb_hist[2], Point(j * 2 + 10, rgb_hist[2].rows), Point((j + 1) * 2 + 10, rgb_hist[2].rows - val), Scalar(255, 0, 0), 1, 8);
}

/// Display
namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE);
namedWindow("wnd");
imshow("calcHist Demo", histImage);
imshow("wnd", src);

imshow("R", rgb_hist[0]);
imshow("G", rgb_hist[1]);
imshow("B", rgb_hist[2]);
waitKey();
}

10-28
08-20 3万+

01-29 1万+
12-26 717
04-21 109
04-21 6596
09-03 804
04-04 1852
11-18 1653