其中C++的函数原型如下:
void calcHist(const Mat* arrays, int narrays, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform=true, bool accumulate=false );
arrays。输入的图像的指针,可以是多幅图像,所有的图像必须有同样的深度(CV_8U or CV_32F)。同时一副图像可以有多个channes。
narrays。输入的图像的个数。
channels。用来计算直方图的channes的数组。比如输入是2副图像,第一副图像有0,1,2共三个channel,第二幅图像只有0一个channel,那么输入就一共有4个channes,如果int channels[3] = {3, 2, 0},那么就表示是使用第二副图像的第一个通道和第一副图像的第2和第0个通道来计算直方图。
mask。掩码。如果mask不为空,那么它必须是一个8位(CV_8U)的数组,并且它的大小的和arrays[i]的大小相同,值为1的点将用来计算直方图。
hist。计算出来的直方图
dims。计算出来的直方图的维数。
histSize。在每一维上直方图的个数。简单把直方图看作一个一个的竖条的话,就是每一维上竖条的个数。
ranges。用来进行统计的范围。比如
float rang1[] = {0, 20};
float rang2[] = {30, 40};
const float *rangs[] = {rang1, rang2};那么就是对0,20和30,40范围的值进行统计。
uniform。每一个竖条的宽度是否相等。
accumulate。存在多个图像时,是否累计计算像素值得个数。
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
char file[] = "1.jpg";
int main(int argc, char** argv)
{
Mat img = imread(file, -1);
pyrDown(img, img, Size(img.cols/2, img.rows/2));
imshow("1",img);
//创建映射关系表
vector<Mat> RGBpaltes;
split(img, RGBpaltes);
//直方图的相关参数设定
Mat b_hist, g_hist, r_hist;
float range[] = {0, 255};
const float * Hrange = {range};
int histSize = 256;
calcHist(&RGBpaltes[0], 1, 0, Mat(), b_hist, 1, &histSize, &Hrange, true, false);
calcHist(&RGBpaltes[1], 1, 0, Mat(), g_hist, 1, &histSize, &Hrange, true, false);
calcHist(&RGBpaltes[2], 1, 0, Mat(), r_hist, 1, &histSize, &Hrange, true, false);
//归一化
normalize(b_hist, b_hist, 0, 400, NORM_MINMAX, -1, Mat());
normalize(g_hist, g_hist, 0, 400, NORM_MINMAX, -1, Mat());
normalize(r_hist, r_hist, 0, 400, NORM_MINMAX, -1, Mat());
//画出图片。
int img_h = 700;//图片的高(行数)
int img_w = 512;//图片的宽(列数)
int line_w = img_w/histSize;//线宽
Mat histImage(img_h, img_w, CV_8UC3, Scalar(0,0,0));//图片(画布)大小
for (int i=1; i<histSize; i++)
{
// 两个点的规则。
// x坐标:条线*线宽;
// y坐标:由于图片的行计数是从上开始的而我们习惯从下开始计算y轴递增,因此我用图片的高 - 当前像素的累计计数值 - 最底下黑边高度。
line(histImage, Point((i-1)*line_w, img_h - cvRound(r_hist.at<float>(i-1)) - 200),
Point(i*line_w, img_h - cvRound(r_hist.at<float>(i)) - 200),Scalar(0,0,255), 2);
line(histImage, Point((i-1)*line_w, img_h - cvRound(g_hist.at<float>(i-1)) - 200),
Point(i*line_w, img_h - cvRound(g_hist.at<float>(i)) - 200),Scalar(0,255,0), 2);
line(histImage, Point((i-1)*line_w, img_h - cvRound(b_hist.at<float>(i-1)) - 200),
Point(i*line_w, img_h - cvRound(b_hist.at<float>(i)) - 200),Scalar(255,0,0), 2);
}
imshow("结果", histImage);imwrite("final.jpg", histImage);
//结果一的图中有一个问题:RGB 各通道的曲线会在一张图中,三个通道的最值不同,但却在同一个标准下归一化。
//换句话说,由于是会在一张图中,最终结果中达到最值的在三个通道中只能有一个点,而不能是三个通道有三个点。
//解决办法:找到每个通道的最大值:r_max g_max b_max, 然后再找出这三个值的最大值 MAX ,将
// cvRound(r_hist.at<float>(i-1)) 改为 cvRound( r_hist.at<float>(i-1)*r_max/MAX )
waitKey();
return 1;
}
原图
结果