文章目录

  • 什么是图像直方图
  • calcHist函数参数
  • 绘制直方图流程
  • 绘制直方图实战
  • 最终效果
  • line函数解析(对应代码中的line)

什么是图像直方图

图像直方图是反映一个图像像素分布的统计表,其实横坐标代表了图像像素的种类,可以是灰度的,也可以是彩色的。纵坐标代表了每一种颜色值在图像中的像素总数或者占所有像素个数的百分比

calcHist函数参数

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 const Mat* images:输入图像int nimages:输入图像的个数const int* channels:需要统计直方图的第几通道(0表示第一通道)InputArray mask:掩膜,控制运算的范围。不懂的可以看这篇博文:[图像位操作(带mask解说)](https://blog.csdn.net/m0_60447786/article/details/125650689?spm=1001.2014.3001.5501)OutputArray hist:输出的直方图数组int dims:需要统计直方图通道的个数(一般都是1)const int* histSize:指的是直方图分成多少个区间,就是 bin的个数const float** ranges: 统计像素值得区间(相当于每一个横坐标区间的取值范围)bool uniform=true::是否对得到的直方图数组进行归一化处理bool accumulate=false:在多个图像时,是否累计计算像素值得个数
注意:后两个参数也可以了忽略,忽略的时候默认是 true false

calcHist函数只是计算直方图的数据,(直方图数据需要一个mat类型的变量来存储)

绘制直方图流程

1.读入图像
2.分开图像通道(不一定只有三个通道)
3.定义直方图的参数
4.使用calcHist()函数得到直方图数据
5.定义幕布参数
6.归一化直方图参数
7.将直方图数据画在幕布上
8.显示幕布

绘制直方图实战

源码如下:

#include<opencv2/opencv.hpp>
#include<iostream>
#include<vector>
using namespace std;
using namespace cv;
int main()
{//绘制图像直方图Mat src = imread("C:\\Users\\86151\\Desktop\\opencv\\picture\\4.jpg");imshow("src",src);if (src.empty()) //这里建议大家加上,形成习惯,有时候会帮助我们及时发现bug,博主亲身经历{cout << "no picture" << endl;return -1;}//提取三通道vector<Mat> all_channel;split(src,all_channel); //split函数将图像的三通道分别提取出来,放到all_channel数组里面//定义参数变量const int bin = 256;//因为图像一共有256个灰度级别,意思就是像素点0-255有256个,那么需要256个横坐标,所以bin赋值256。float bin_range[2] = { 0,255 };//每个通道的灰度级别0-255,也就是像素点的取值范围const float* ranges[1] = { bin_range };//这样做只是方便下面clacHist函数的传参//定义变量来存储直方图数据,一共提取出了三个通道:R G B,所以定义三个变量Mat b_hist;Mat g_hist;Mat r_hist;//计算得到直方图数据calcHist(&all_channel[0], 1, 0, Mat(), b_hist, 1, &bin, ranges, true, false);calcHist(&all_channel[1], 1, 0, Mat(), g_hist, 1, &bin, ranges, true, false);calcHist(&all_channel[2], 1, 0, Mat(), r_hist, 1, &bin, ranges, true, false);/*参数解析:all_channel[i]:传入要计算直方图的通道,根据函数原函数可以得出,要以引用的方式传入1:传入图像的个数,就一个0:表示传入一个通道Mat():没有定义掩膜,所以默认计算区域是全图像b/g/r_hist:用来存储计算得到的直方图数据1:对于当前通道需要统计的直方图个数,我们统计一个bin:直方图的横坐标有多少个,我们将其赋值为256,即统计每一个像素值的数量。要求用引用方式传入。ranges:每个像素点的灰度等级,要求以引用方式传入。true:进行归一化,false:计算多个图像的直方图时,不累加上一张图像的像素点数据。*///设置直方图画布的参数,直方图要花在一个“幕布”上,这个幕布也要设置参数int hist_w = 512;//画布的宽int hist_h = 400;//画布的高int bin_w = cvRound((double)hist_w/bin);//设置直方   图中每一点的步长,直方图有256个横坐标,每个坐标在画布中占多长,通过hist_w/bin计算得出。cvRound()函数是“四舍五入”的作用。Mat hist_canvas = Mat::zeros(hist_h, hist_w, CV_8UC3);//通过我们设置的参数创建出一个黑色的画布//对三个通道的直方图数据进行归一化处理,这是一个必要环节,后续仔细说明。normalize(b_hist, b_hist, 0, 255, NORM_MINMAX, -1, Mat());normalize(g_hist, g_hist, 0, 255, NORM_MINMAX, -1, Mat());normalize(r_hist, r_hist, 0, 255, NORM_MINMAX, -1, Mat());//以折线统计图的方式绘制三个通道的直方图在画布上for (int i = 1; i < 256; i++){line(hist_canvas, 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(0, 0, 255), 2, 8, 0);line(hist_canvas, 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(hist_canvas, 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(255, 0, 0), 2, 8, 0);}//展示到屏幕上imshow("result",hist_canvas);waitKey(0);destroyAllWindows();return 0;
}

最终效果

带有归一化的效果:

不带有归一化的效果:

由此可见,我们归一化的目的就是让数据同一在一个范围内,因为我们观察的就是各个像素值所占的比例,所以同时放缩到一个范围是不错的选择,易于观察。对normalize函数有疑问的也可以参考下这篇文章:normalize函数详解

line函数解析(对应代码中的line)

line函数解析:
hist_canvas : 要绘制的画布
第一个Point:bin_w* (i - 1)表示第一个点的横坐标,因为步长就是bin_w, 而且一共有256个横坐标区间,那么随着横坐标的移动,绘制直线的横坐标也要随之移动,所以使用(i - 1) * bin_w。b_hist.at(i - 1):表示取出这个像素点的数量n,然后通过hist_h(画布的高)减去n进行绘制,为什么要减去呢?因为我们一半的管理是从左下角作为图像的起始点(0,0),但是计算机是以图像的左上角点作为其实坐标(0, 0)的,所以用画布的高减去n,绘制出来就可以达到我们一般眼光看到的效果。
第二个Point : 画一条直线需要两点,所以第二个Point也需要,那么横坐标的话就是比上一点多一个bin_w,纵坐标的话也是一样的原理,只不过数值变化了。
通过这样的方式画出三个通道的全部直方图便可,后面的Scalar(255, 0, 0)表示颜色,第一个Scalar表示蓝色线,第二个是绿色线,第三个是红色线。(blue green red)

opencv-图形直方图(calcHist函数)详解(C++)相关推荐

  1. OpenCV-Python直方图计算calcHist函数详解

    ☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython ░ 一.引言 在<<数字图像处理>第三章学习总结感悟2:直方图处理: h ...

  2. Opencv中的imshow函数详解

    前言 使用opencv对图像进行处理之后,通常调用imshow函数来显示处理结果.但是,我们经常会发现显示结果和我们预期的结果有些差别.这是由于opencv经常会涉及到对多种图像数据类型的处理,如果我 ...

  3. 【opencv学习笔记】025之直方图计算 - calcHist函数详解

    前言 如果你想了解更多有关于计算机视觉.OpenCV.机器学习.深度学习等相关技术的内容,想与更多大佬一起沟通,那就扫描下方二维码加入我们吧! 1.calcHist函数是干什么滴? 这个问题嘛,看看标 ...

  4. OpenCV-Python图像直方图计算calcHist函数详解、示例及图形呈现

    ☞ ░ 前往老猿Python博文目录 https://blog.csdn.net/LaoYuanPython ░ 一.引言 在前面几篇直方图相关的文章中介绍了直方图均衡.直方图匹配.局部直方图处理.基 ...

  5. OpenCV之直方图绘制(calcHist函数详解)

    目录 1.直方图的定义 2.calcHist()函数说明 3.绘制直方图 3.1 读取原图像并检查图像是否读取成功 3.2 定义直方图参数并计算直方图 3.3 绘制直方图 4.关于BGR直方图的绘制 ...

  6. 详解为什么OpenCV的直方图计算函数calcHist()计算出的灰度值为255的像素个数为0

    在使用OpenCV的直方图计算函数calcHist()时,发现灰度值为255的像素个数总是为0. 哪怕图像中灰度值为255的像素个数不为0,使用OpenCV的直方图计算函数calcHist()计算出的 ...

  7. OpenCV 图像卷积:cv.filter2D() 函数详解

    API 照例,我们搬一下官网的 API: C++ void cv::filter2D(InputArray src,OutputArray dst,int ddepth,InputArray kern ...

  8. opencv imshow函数详解

    前言 使用opencv对图像进行处理之后,通常调用imshow函数来显示处理结果.但是,我们经常会发现显示结果和我们预期的结果有些差别.这是由于opencv经常会涉及到对多种图像数据类型的处理,如果我 ...

  9. OpenCV 图像缩放:cv.resize() 函数详解

    目录 系列前言 API 函数详解 参数列表 缩放方式其一 缩放方式其二 两种方式的优先级 关于插值方式 扩展 -- 相关函数 系列前言 这个系列是我第一个想要更下去的系列.每篇会全面介绍一个 Open ...

  10. python中减法运算函数_OpenCV-Python图像的减法运算cv2.subtract函数详解以及和矩阵减...

    OpenCV-Python图像的减法运算cv2.subtract函数详解以及和矩阵减 OpenCV-Python图像的减法运算cv2.subtract函数详解以及和矩阵减法的差异对比 ? ? 前往老猿 ...

最新文章

  1. C#调用非托管C++DLL:直接调用法
  2. 不死神兔c语言20月,不死神兔问题(斐波那契数列)
  3. 图像处理之一阶微分应用
  4. 关于exchange2003使用owa修改用户口令
  5. 揭开SAP Fiori编程模型规范里注解的神秘面纱 - @OData.publish工作原理解析
  6. filestorage 修改吧部分数据_数据库系统概论课后答案||第五版
  7. OceanBase再破纪录!核心成员陈萌萌:坚持HTAP就是坚持我们做数据库的初心
  8. 关于消息队列的一些问题
  9. SCAN及相关SSCAN,HSCAN和ZSCAN命令解析
  10. Mac 下的代码比对工具
  11. ev3pid巡线_据说这是最简单的乐高EV3巡线方法
  12. 终于交作业了,View Design 的设计资源上线啦,免费哦
  13. Jeffery C. Hill
  14. 从玉农业谋定国家龙头企业-林裕豪:对话农民丰收节交易会
  15. SparkSql 控制输出文件数量且大小均匀(distribute by rand())
  16. Chrome谷歌浏览器,清除css或js文件缓存的方法
  17. 天虹数科Java笔试题B
  18. 中软国际实习 dzy15
  19. 一个后端童鞋步入 vue 深渊引发的惨案: VSCode Vue开发 目录下多个路由访问重叠不生效问题解决
  20. Linux NFS网络文件系统

热门文章

  1. 偷偷爆料下各公司年终奖!(最新版)
  2. nginx 部署前端vue项目dist文件
  3. HashMap keySet与entrySet遍历分析
  4. Java - Map keyset
  5. Docker安装Redis并使用本地连接
  6. 中间件 mysql 异地多活_数据库的异地多活分析和方案
  7. NGS测序中PCR重复序列的判定方法
  8. Python基础之格式化输出
  9. 【Linux】一篇文章搞定 CPP模拟实现TCP协议下socket通信
  10. MySQL 基于maxscale服务构建数据读写分离