一、 函数原型

void 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 );

函数作用:计算一个或多个数组的直方图

参数解释images输入图像nimages输入图像个数channels用来计算直方图的dims通道的列表mask可选的掩码hist输出直方图dims直方图的维数(不大于CV_MAX_DIMS)histSize每个维度的直方图尺寸的数组(256)ranges每个维度的直方图范围的数组[dims]的阵列(0-255)uniform表示直方图是否是统一的标志accumulate累积标志

uniform:是否对灰度值范围进行均匀划分的标志 ccumulate:累积标志。如果它被设置,直方图在开始分配时不会被清除。 分配时不会被清除。这个特性使你可以从几组数组中计算出一个单一的直方图,或者更新直方图。

数组,或者及时更新柱状图。

二、参数具体解释

1. channels

用来计算直方图的dims通道的列表。 第一个通道索引值:0到images[0].channels()-1的数字

(如果是三通道,就是0 ~(3-1) 即 0 ~ 2)

第二个通道索引值:images[0].channels() 到 images[0].channels() + images[1].channels()-1

例:三张三通道图像, 则第一张图像三个通道索引值:0、1、2 第一张图像三个通道索引值:3、4、5 第一张图像三个通道索引值:6、7、8 计算二维直方图(第一张图像第二通道,第二张图象第三通道) const int channels[1] = { 0,5 };

2. mask

可选的操作掩码矩阵, 如果是空矩阵则表示图像中所有位置的像素都计入直方图中, 如果矩阵不为空,则该操作掩码矩阵必须与输入图像尺寸相同且数据类型为CV_8U。当矩阵不为空的时候,那些掩码值不为0的掩码对应的像素被纳入统计范围,而那些掩码值为0的掩码对应的像素则不被纳入统计。 空矩阵:Mat();

3. dims

需要计算的直方图的维度(不大于CV_MAX_DIMS) 一般为数组channels大小(三通道为3),当写为1的时候计算的是通道索引数组中的第1个通道的直方图,当写为2的时候计算的是通道索引数组中的第1个通道和第2个通道的二维直方图。

4. histSize

每个维度的直方图尺寸,直方图中每个dims维度需要分成多少个区间(如果把直方图看作一个一个竖条的话,就是竖条的个数);

例如: 计算二维直方图(第一张图像第二通道,第二张图象第一通道)两个图象分别为RGB和HSV const int histSize[2] = { 256 ,181 }; 可以分为256个区间(也就是一个像素值一个区间) const int histSize[2] = { 3 ,3 }; (也可以分为3个区间,也就是256/3个像素值一个区间,画出来的直方图就是三个点两个折线)

5. ranges

例如: 计算二维直方图(第一张图像第二通道,第二张图象第一通道)两个图象分别为RGB和HSV(也就是一维根据第一个图象决定,二维根据第二个图像决定) float hranges1[2] = { 0,255 }; float hranges2[2] = { 0,180 }; const float* ranges[2] = { hranges1, hranges2};

三、 代码

1. 一维直方图

// 图像直方图

void QuickDemo::showHistogram(Mat& image)

{

// 三通道分离

std::vector bgr_plane; // Mat有三个通道

split(image, bgr_plane);

// 定义参数变量

const int channels[1] = { 0 };

const int bins[1] = { 256 }; // 每个维度分成256个区间

float hranges[2] = { 0,255 };

const float* ranges[1] = { hranges };

Mat b_hist;

Mat g_hist;

Mat r_hist;

// 计算Blue,GReen,Red通道的直方图

// 输入图像 输入图像个数 统计直方图第几通道 输出直方图维度 每个维度分成多少区间 统计像素值的区间

calcHist(&bgr_plane[0], 1, channels,Mat() , b_hist, 1, bins, ranges);

calcHist(&bgr_plane[1], 1, channels,Mat() , g_hist, 1, bins, ranges);

calcHist(&bgr_plane[2], 1, channels,Mat() , r_hist, 1, bins, ranges);

// 显示直方图

int hist_w = 512;

int hist_h = 400;

int bin_w = cvRound((double)hist_w / bins[0]); // 一个区间的长度(总长度/区间)

Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3); // 定义一个Mat图像显示直方图

// 1. 归一化直方图数据

normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());

normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());

normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());

// 2. 绘制直方图曲线

for (int i = 1; i < bins[0]; i++) // 分别绘制每个区间

{

line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at(i - 1))),

Point(bin_w * (i), hist_h - cvRound(b_hist.at(i))), Scalar(255, 0, 0), 2, 8, 0);

line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at(i - 1))),

Point(bin_w * (i), hist_h - cvRound(g_hist.at(i))), Scalar(0, 255, 0), 2, 8, 0);

line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at(i - 1))),

Point(bin_w * (i), hist_h - cvRound(r_hist.at(i))), Scalar(0, 0, 255), 2, 8, 0);

}

// 3. 显示出来

namedWindow("一维直方图", WINDOW_AUTOSIZE);

imshow("一维直方图", histImage);

}

2. 二维直方图

// 二维直方图

void QuickDemo::showHistogram_2d_demo(Mat& image)

{

// 直方图矩阵计算

Mat hsv, hs_hist; // hsv:将图像转换为HSV类型 hs_hist:直方图计算输出矩阵

cvtColor(image, hsv, COLOR_BGR2HSV);

int hs_channels[] = {0,1}; // 参数channels:需要统计直方图的第几通道;h s

int hbins = 30, sbins = 32; // 参数histSize:直方图中每个dims维度需要分成多少个区间(如果把直方图看作一个一个竖条的话,就是竖条的个数);

int hist_bins[] = { hbins, sbins };

float h_range[] = { 0, 180 }, s_range[] = { 0,255 };

const float* hs_ranges[] = { h_range,s_range }; // ranges:统计像素值的区间;

calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges, true, false);

// 直方图输出

double maxVal;

minMaxLoc(hs_hist, 0, &maxVal, 0, 0); // 获取像素最大值

int scale = 10; // 确定输出直方图图像大小范围

Mat hist2d_image = Mat::zeros(sbins * scale, hbins * scale, CV_8UC3); // 用作输出的图像

for (int h = 0; h < hbins; h++) // 参数histSize:直方图中每个dims维度需要分成多少个区间(如果把直方图看作一个一个竖条的话,就是竖条的个数);

{

for (int s = 0; s < sbins; s++)

{

float binVal = hs_hist.at(h, s); // 获取像素值

int intensity = cvRound(binVal * 255 / maxVal); // 实现将hs_hist中对应第h行第s列的数值限制到0到255。如果只除以maxval(用minMaxLoc找到的矩阵中的最大值)就是归一化,限制到0到1,但乘上255就限制到255了。

rectangle(hist2d_image, Point(h * scale, s * scale), Point((h + 1) * scale - 1, (s + 1) * scale - 1), Scalar::all(intensity), -1);

}

}

applyColorMap(hist2d_image, hist2d_image, COLORMAP_JET);

imshow("hs 二维直方图", hist2d_image);

imwrite("D:\\software\\hist_2d.png", hist2d_image);

}

参考链接

对OpenCV的图像直方图计算函数calcHist()进行透彻解析OpenCV4 C++ 快速入门视频30讲 - 系列合集

好文推荐

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: