图像处理学习笔记之直方图的计算与绘制
2017-05-03 17:29
489 查看
图像直方图包含丰富的图像细节信息,反映了图像像素点的概率分布情况,它统计了每一个强度值具有的像素个数。灰度级范围是[0,L-1]的数字图像的直方图是离散函数h(rk)=nk,其中是rk第k级灰度值,nk是图像中灰度为rk的像素个数。在实践中,经常用乘积MN表示的图像像素总数除它的每个分量来归一化直方图,M、N是图像的行列数。因此归一化后的直方图由p(rk)=nk/MN给出。直方图的横坐标表示灰度级,纵坐标表示图像中该灰度级出现的次数(频率)。
一般来说,在暗图像中,直方图的分量集中在灰度级较低的一侧。亮图像的直方图分量集中在灰度级值较高的一侧。低对比度的图像具有较窄的直方图,且集中于灰度级的中部。高对比度的图像中直方图的分量覆盖了很宽的灰度级范围。
图1 亮图像及其灰度直方图
图2 暗图像及其灰度直方图
图3 高对比度图像及其灰度直方图
图4 低对比度图像及其灰度直方图
opencv中提供了calchist函数用于计算图像的直方图。其声明如下:
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:用来计算直方图的通道维数数组,第一个数组的通道由0到arrays[0].channels()-1列出,第二个数组的通道从arrays[0].channels()到arrays[0].channels()+arrays[1].channels()-1以此类推
mask:可选的掩膜,如果该矩阵不是空的,则必须是8位的并且与arrays[i]的大小相等,掩膜的非零值标记需要在直方图中统计的数组元素;
hist:输出直方图,是一个稠密或者稀疏的dims维的数组
dims:直方图的维数,必须为正,并且不大于CV_MAX_DIMS(当前的OpenCV版本中为32,即最大可以统计32维的直方图);
histSize:用于指出直方图数组每一维的大小的数组,即指出每一维的bin的个数的数组
ranges:用于指出直方图每一维的每个bin的上下界范围数组的数组,当直方图是均匀的(uniform =true)时,对每一维i指定直方图的第0个bin的下界(包含即[)L0和最后一个即第histSize[i]-1个bin的上界(不包含的即))U_histSize[i]-1,也就是说对均匀直方图来说,每一个ranges[i]都是一个两个元素的数组【指出该维的上下界】。当直方图不是均匀的时,每一个ranges[i]数组都包含histSize[i]+1个元素:L0,U0=L1,U1=L1,...,U_histSize[i]-2
= L_histSize[i]-1,U_histSize[i]-1.不在L0到U_histSize[i]-1之间的数组元素将不会统计进直方图中
uniform:直方图是否均匀的标志;【指定直方图每个bin统计的是否是相同数量的灰度级】
accumulate:累加标
一般来说,在暗图像中,直方图的分量集中在灰度级较低的一侧。亮图像的直方图分量集中在灰度级值较高的一侧。低对比度的图像具有较窄的直方图,且集中于灰度级的中部。高对比度的图像中直方图的分量覆盖了很宽的灰度级范围。
图1 亮图像及其灰度直方图
图2 暗图像及其灰度直方图
图3 高对比度图像及其灰度直方图
图4 低对比度图像及其灰度直方图
opencv中提供了calchist函数用于计算图像的直方图。其声明如下:
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:用来计算直方图的通道维数数组,第一个数组的通道由0到arrays[0].channels()-1列出,第二个数组的通道从arrays[0].channels()到arrays[0].channels()+arrays[1].channels()-1以此类推
mask:可选的掩膜,如果该矩阵不是空的,则必须是8位的并且与arrays[i]的大小相等,掩膜的非零值标记需要在直方图中统计的数组元素;
hist:输出直方图,是一个稠密或者稀疏的dims维的数组
dims:直方图的维数,必须为正,并且不大于CV_MAX_DIMS(当前的OpenCV版本中为32,即最大可以统计32维的直方图);
histSize:用于指出直方图数组每一维的大小的数组,即指出每一维的bin的个数的数组
ranges:用于指出直方图每一维的每个bin的上下界范围数组的数组,当直方图是均匀的(uniform =true)时,对每一维i指定直方图的第0个bin的下界(包含即[)L0和最后一个即第histSize[i]-1个bin的上界(不包含的即))U_histSize[i]-1,也就是说对均匀直方图来说,每一个ranges[i]都是一个两个元素的数组【指出该维的上下界】。当直方图不是均匀的时,每一个ranges[i]数组都包含histSize[i]+1个元素:L0,U0=L1,U1=L1,...,U_histSize[i]-2
= L_histSize[i]-1,U_histSize[i]-1.不在L0到U_histSize[i]-1之间的数组元素将不会统计进直方图中
uniform:直方图是否均匀的标志;【指定直方图每个bin统计的是否是相同数量的灰度级】
accumulate:累加标
int main() { Mat src, dst; src = imread("1.jpg"); if (!src.data) { return -1; } /// 通道分离 vector<Mat> bgr_planes; split(src, bgr_planes); int histSize = 256; /// 设置范围 float range[] = { 0, 256 }; const float* histRange = { range }; bool uniform = true; bool accumulate = false; Mat b_hist, g_hist, r_hist; /// 计算直方图: calcHist(&bgr_planes[0], 1, 0, Mat(), b_hist, 1, &histSize, &histRange, uniform, accumulate); calcHist(&bgr_planes[1], 1, 0, Mat(), g_hist, 1, &histSize, &histRange, uniform, accumulate); calcHist(&bgr_planes[2], 1, 0, Mat(), r_hist, 1, &histSize, &histRange, uniform, accumulate); // 创建画布 int hist_w = 512; int hist_h = 400; int bin_w = cvRound((double)hist_w / histSize); Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(0, 0, 0)); /// 归一化到 [ 0, histImage.rows ] 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()); /// 画直方图 for (int i = 1; i < histSize; i++) { 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); 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(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); } namedWindow("calcHist Demo", CV_WINDOW_AUTOSIZE); imshow("calcHist Demo", histImage); waitKey(0); return 0; }
相关文章推荐
- OpenCV学习笔记——图像处理之直方图ImgProc
- 图像处理opencv直方图均值化-学习笔记2
- C#数字图像处理算法学习笔记(二)--点运算与直方图
- OpenCV学习笔记(八)——图像处理之直方图ImgProc
- opencv学习之(五)-直方图计算和绘制图像直方图
- opencv学习之(五)-直方图计算和绘制图像直方图
- 【小白笔记】PHP学习之路 (29) --图像处理、绘制像素、矩形、多边形
- Python OpenCV学习笔记之:灰度图像的直方图计算
- 【OpenCV学习笔记】二十一、直方图计算及绘制(一)
- OpenCV学习笔记(八)——图像处理之直方图ImgProc
- Python OpenCV学习笔记之:计算彩色图像各通道的直方图及图像区域直方图
- 【OpenCV学习笔记】二十二、直方图计算及绘制(二)
- Opencv学习笔记——绘制图像的像素直方图
- OpenCV 2 学习笔记(15): 绘制图像直方图
- 基础学习笔记之opencv(19):有关图像序列的直方图计算
- opencv2学习笔记:4.2计算图像直方图
- matlab图像处理学习笔记1
- 【Matlab图像处理】学习笔记:读取16进制RGB文档转为彩色图片
- 我的OpenCV学习笔记(三):利用操作像素完成简单的图像处理:加入椒盐噪声、图像翻转、改变对比度、图像锐化
- OpenCV学习笔记5 - 图像绘制功能