直方图的绘制——HS直方图和RGB三色直方图
在上一篇博文中我们探讨了直方图的计算,其实直方图可以看成概率密度分布的离散化表达方法,而要注意的是:二维直方图并不是一个通道一个通道的分别独立平行计算,而是将两个通道的数据整合起来计算出的二维直方图
1.1绘制直方图所需要掌握的一些基本函数:
split()和merge() //颜色通道的分离与合并
line() //画线的函数
rectangle() //画矩形的函数
normalized() //归一化函数
minMaxLoc() //找最大最小值的函数
1.2绘制H-S直方图
图像的HSV表示呢,H通道代表了色调,S通道代表了饱和度,V通道代表了明度
H的范围大概是0-180,S的范围大概是0-255,V的范围大概是0-255
要画H-S直方图,我们当然得先把原图像转化为HSV模型,用到颜色空间转化函数cvtColor():
cvtColor(scrimage, HSV_image, COLOR_BGR2HSV);
然后对于直方图的计算,请移步至我的上一篇博客:
https://blog.csdn.net/weixin_44586473/article/details/95614238
OpenCV3学习笔记——直方图专题1(直方图的概念以及计算)
好的,我们下面开始画图:
我们先找到直方图的binvalue的最大值:
double max_value = 0;
minMaxLoc(hist_image, 0, &max_value, 0, 0);
由于直方图的最大值可能比较大,我们的画布,图像等也要有一个放大的比例scale:
int scale = 10; //定义比例为10
下一步开始创建画布:(我们创建一个全0矩阵)
Mat histImage = Mat::zero(hue_bins*scale,sat_bins*scale, CV_8UC3);
//假定hue_bins,sat_bins等变量在之前已经被定义
然后我们就可以开始绘制了(注意:我们计算的特征有几个,就有几个for循环)
for(int i = 0; i < hue_bins; i++)
{
for(j = 0; j < sat_bins; j++)
{
float binvalue = hist_image.at<float>(i, j); //hist_image已经在计算直方图中定义了
int intensity = cvRound(binvalue*255/max_value); //强度
rectangle(histImage, Point(i*scale, j*scale), Point((i+1)*scale, (j+1)*scale), Scalar::all(intensity),CV_FILLED); //它是一行一行画的,CV_FILLED是填充矩形
}
}
来看看效果:
对于RGB三色直方图,绘制过程和原理和H-S直方图类似,只不过我们需要用split()函数将原图像的三个颜色通道分离,然后对每个通道单独计算直方图并且分别绘制,下面我直接上代码:
int main()
{
Mat src, dst ;
src = imread( "风景.jpg");
imshow("原始图" , src);
vector<Mat> rgb_planes;
split( src, rgb_planes );
int histSize = 255;
float range[] = { 0, 255 } ; //设置变化范围为0-255
const float* histRange = { range }; //这个将要作为第八个参数,它是每一个维度(特征)的范围组成的阵列
bool uniform = true; bool accumulate = false;
Mat r_hist, g_hist, b_hist;
/// 计算直方图:
calcHist( &rgb_planes[0], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate );//第一个参数是输入数组的地址 , 第二个参数是数组个数 第六个参数因为我们只统计了一个特征所以维度是1
calcHist( &rgb_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate );
calcHist( &rgb_planes[2], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate );
// 创建直方图画布
int hist_w = 400; int hist_h = 400;
int bin_w = cvRound( (double) hist_w/histSize );
Mat histImage( hist_w, hist_h, CV_8UC3, Scalar( 0,0,0) );
/// 将直方图归一化到范围 [ 0, histImage.rows ]
normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat() );
for( int i = 1; i < histSize; i++ ) //遍历每一个bins, 注意如果是二位直方图就要对每一个特征的bins循环
{
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), 2, 8, 0 );
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), 2, 8, 0 );
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), 2, 8, 0 );
}
namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE );
imshow("calcHist Demo", histImage );
waitKey(0);
}
我们来看看效果图:
好啦,直方图的绘制就先告一段落啦,下一篇博文中我将记录一下直方图的应用——直方图归一化,直方图的对比