本文首发于“小白学视觉”微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究!


经过几个月的努力,小白终于完成了市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》。为了更让小伙伴更早的了解最新版的OpenCV 4,小白与出版社沟通,提前在公众号上连载部分内容,请持续关注小白。

我们可以将数字图像理解成一定尺寸的矩阵,矩阵中每个元素的大小表示了图像中每个像素的亮暗程度,因此统计矩阵中的最大值,就是寻找图像中灰度值最大的像素,计算平均值就是计算图像像素平均灰度,可以用来表示图像整体的亮暗程度。因此针对矩阵数据的统计工作在图像像素中同样具有一定的意义和作用。在OpenCV 4中集成了求取图像像素最大值、最小值、平均值、均方差等众多统计量的函数,接下来将详细介绍这些功能的相关函数。

寻找图像像素最大值与最小值

OpenCV 4提供了寻找图像像素最大值、最小值的函数minMaxLoc(),该函数的原型在代码清单3-7中给出。

代码清单3-7 minMaxLoc()函数原型
1.  void cv::minMaxLoc(InputArray  src,
2.                        double *   minVal,
3.                        double *   maxVal = 0,
4.                        Point *   minLoc = 0,
5.                        Point *   maxLoc = 0,
6.                        InputArray   mask = noArray()
7.                        )
  • src:需要寻找最大值和最小值的图像或者矩阵,要求必须是单通道矩阵
  • minVal:图像或者矩阵中的最小值。
  • maxVal:图像或者矩阵中的最大值。
  • minLoc:图像或者矩阵中的最小值在矩阵中的坐标。
  • maxLoc:图像或者矩阵中的最大值在矩阵中的坐标。
  • mask:掩模,用于设置在图像或矩阵中的指定区域寻找最值。

这里我们见到了一个新的数据类型Point,该数据类型是用于表示图像的像素坐标,由于图像的像素坐标轴以左上角为坐标原点,水平方向为x轴,垂直方向为y轴,因此Point(x,y)对应于图像的行和列表示为Point(列数,行数)。在OpenCV中对于2D坐标和3D坐标都设置了多种数据类型,针对2D坐标数据类型定义了整型坐标cv::Point2i(或者cv::Point)、double型坐标cv::Point2d、浮点型坐标cv::Point2f,对于3D坐标同样定义了上述的坐标数据类型,只需要将其中的数字“2”变成“3”即可。对于坐标中x、y、z轴的具体数据,可以通过变量的x、y、z属性进行访问,例如Point.x可以读取坐标的x轴数据。

该函数实现的功能是寻找图像中特定区域内的最值,函数第一个参数是输入单通道矩阵,需要注意的是,该变量必须是一个单通道的矩阵数据,如果是多通道的矩阵数据,需要用cv::Mat::reshape()将多通道变成单通道,或者分别寻找每个通道的最值,然后再进行比较寻找到全局最值。对于cv::Mat::reshape()的用法,在代码清单3-8中给出。第二到第五个参数分别是指向最小值、最大值、最小值位置和最大值位置的指针,如果不需要寻找某一个参数,可以将该参数设置为NULL,函数最后一个参数是寻找最值得掩码矩阵,用于标记寻找上述四个值的范围,参数默认值为noArray(),表示寻找范围是矩阵中所有数据。

代码清单3-8 Mat::reshape()函数原型
1.  Mat cv::Mat::reshape(int  cn,
2.                           int  rows = 0
3.                           )
  • cn:转换后矩阵的通道数。
  • rows:转换后矩阵的行数,如果参数为零,则转换后行数与转换前相同。

注意

如果矩阵中存在多个最大值或者最小值时,minMaxLoc()函数输出最值的位置为按行扫描从左向右第一次检测到最值的位置,同时输入参数时一定要注意添加取地址符。

为了让读者更加了解minMaxLoc()函数的原理和使用方法,在代码清单3-9中给出寻找矩阵最值的示例程序,在图3-6中给出了程序运行的最终结果,在图3-7给出了创建的两个矩阵和通道变换后的矩阵在Image Watch中查看的内容,。

代码清单3-9 myfindMinAndMax.cpp寻找矩阵中的最值
1.  #include <opencv2\opencv.hpp>
2.  #include <iostream>
3.  #include <vector>
4.
5.  using namespace std;
6.  using namespace cv;
7.
8.  int main()
9.  {10.     system("color F0");  //更改输出界面颜色
11.     float a[12] = { 1, 2, 3, 4, 5, 10, 6, 7, 8, 9, 10, 0 };
12.     Mat img = Mat(3, 4, CV_32FC1, a);  //单通道矩阵
13.     Mat imgs = Mat(2, 3, CV_32FC2, a);  //多通道矩阵
14.     double minVal, maxVal;  //用于存放矩阵中的最大值和最小值
15.     Point minIdx, maxIdx;  用于存放矩阵中的最大值和最小值在矩阵中的位置
16.
17.                            /*寻找单通道矩阵中的最值*/
18.     minMaxLoc(img, &minVal, &maxVal, &minIdx, &maxIdx);
19.     cout << "img中最大值是:" << maxVal << "  " << "在矩阵中的位置:" << maxIdx << endl;
20.     cout << "img中最小值是:" << minVal << "  " << "在矩阵中的位置:" << minIdx << endl;
21.
22.     /*寻找多通道矩阵中的最值*/
23.     Mat imgs_re = imgs.reshape(1, 4);  //将多通道矩阵变成单通道矩阵
24.     minMaxLoc(imgs_re, &minVal, &maxVal, &minIdx, &maxIdx);
25.     cout << "imgs中最大值是:" << maxVal << "  " << "在矩阵中的位置:" << maxIdx << endl;
26.     cout << "imgs中最小值是:" << minVal << "  " << "在矩阵中的位置:" << minIdx << endl;
27.     return 0;
28. }

图3-6 findMinAndMax.cpp程序运行结果 图3-7 Image Watch查看findMinAndMax.cpp程序中矩阵的内容

计算图像的均值和标准方差

图像的均值表示图像整体的亮暗程度,图像的均值越大图像整体越亮。标准方差表示图像中明暗变化的对比程度,标准差越大表示图像中明暗变化越明显。OpenCV 4提供了mean()函数用于计算图像的平均值,提供了meanStdDev()函数用于同时计算图像的均值和标准方差。接下来将详细的介绍这两个函数的使用方法。

代码清单3-10 mean()函数原型
1.  cv::Scalar cv::mean(InputArray  src,
2.                          InputArray  mask = noArray()
3.                          )
  • src:待求平均值的图像矩阵。
  • mask:掩模,用于标记求取哪些区域的平均值。

该函数用来求取图像矩阵的每个通道的平均值,函数的第一个参数用来输入待求平均值的图像矩阵,其通道数目可以在1到4之间。需要注意的是,该函数的返回值是一个cv::Scalar类型的变量,函数的返回值有4位,分别表示输入图像4个通道的平均值,如果输入图像只有1个通道,那么返回值的后三位都为0,例如输入该函数一个单通道平均值为1的图像,输出的结果为[1,0,0,0],可以通过cv::Scalar[n]查看第n个通道的平均值。该函数的第二个参数用于控制图像求取均值的范围,在第一个参数中去除第二个参数中像素值为0的像素,计算的原理如式(3.5)所示,当不输入第二个参数时,表示求取第一个参数全部像素的平均值。
N=∑I,mask(I)≠01Mc=(∑I,mask(I)≠0src(I)c)/N(3.5)\begin{array}{c} N = \sum {_{I,{\rm{mask}}(I) \ne 0}1} \\ {M_c} = \left( {\sum {_{I,{\rm{mask}}(I) \ne 0}{\rm{src}}{{(I)}_c}} } \right)/N \end{array} \tag{3.5}N=∑I,mask(I)​=0​1Mc​=(∑I,mask(I)​=0​src(I)c​)/N​(3.5)

其中 表示第c个通道的平均值, 表示第c个通道像素的灰度值。
meanStdDev()函数可以同时求取图像每个通道的平均值和标准方差,其函数原型在代码清单3-11中给出。

代码清单3-11 meanStdDev()函数原型
1.  void cv::meanStdDev(InputArray  src,
2.                          OutputArray  mean,
3.                          OutputArray  stddev,
4.                          InputArray  mask = noArray()
5.                          )
  • src:待求平均值的图像矩阵。
  • mean:图像每个通道的平均值,参数为Mat类型变量。
  • stddev:图像每个通道的标准方差,参数为Mat类型变量。
  • mask:掩模,用于标记求取哪些区域的平均值和标准方差。

该函数的第一个参数与前面mean()函数第一个参数相同,都可以是1-4通道的图像,不同之处在于该函数没有返回值,图像的均值和标准方差输出在函数的第二个和第三个参数中,区别于mean()函数,用于存放平均值和标准方差的是Mat类型变量,变量中的数据个数与第一个参数通道数相同,如果输入图像只有一个通道,该函数求取的平均值和标准方差变量中只有一个数据。该函数计算原理如式(3.6)所示。

N=∑I,mask(I)≠01Mc=(∑I,mask(I)≠0src(I)c)/Nstddevc=∑I,mask(I)≠0(src(I)c−Mc)2/∑I,mask(I)≠0(src(I)c−Mc)2N/N(3.6)\begin{array}{c} N = \sum {_{I,{\rm{mask}}(I) \ne 0}1} \\ {M_c} = \left( {\sum {_{I,{\rm{mask}}(I) \ne 0}{\rm{src}}{{(I)}_c}} } \right)/N\\ stdde{v_c} = \sqrt {{{\sum {_{I,{\rm{mask}}(I) \ne 0}{{\left( {{\rm{src}}{{(I)}_c} - {M_c}} \right)}^2}} } \mathord{\left/ {\vphantom {{\sum {_{I,{\rm{mask}}(I) \ne 0}{{\left( {{\rm{src}}{{(I)}_c} - {M_c}} \right)}^2}} } N}} \right. }/N}} \end{array} \tag{3.6}N=∑I,mask(I)​=0​1Mc​=(∑I,mask(I)​=0​src(I)c​)/Nstddevc​=∑I,mask(I)​=0​(src(I)c​−Mc​)2/∑I,mask(I)​=0​(src(I)c​−Mc​)2N/N​​(3.6)

我们在代码清单3-12中给出了利用上面两个函数计算代码清单3-9中img和imgs两个矩阵的平均值和标准方差,并在图3-8给出了程序运行的结果。

代码清单3-12 myMeanAndmearStdDev.cpp计算矩阵平均值和标准方差
1.  #include <opencv2\opencv.hpp>
2.  #include <iostream>
3.  #include <vector>
4.
5.  using namespace std;
6.  using namespace cv;
7.  int main()
8.  {9.      system("color F0");  //更改输出界面颜色
10.     float a[12] = { 1, 2, 3, 4, 5, 10, 6, 7, 8, 9, 10, 0 };
11.     Mat img = Mat(3,4, CV_32FC1, a);  //单通道矩阵
12.     Mat imgs = Mat(2, 3, CV_32FC2, a);  //多通道矩阵
13.
14.     cout << "/* 用meanStdDev同时求取图像的均值和标准方差 */" << endl;
15.     Scalar myMean;
16.     myMean = mean(imgs);
17.     cout << "imgs均值=" << myMean << endl;
18.     cout << "imgs第一个通道的均值=" << myMean[0] << "    "
19.           << "imgs第二个通道的均值=" << myMean[1] << endl << endl;
20.
21.     cout << "/* 用meanStdDev同时求取图像的均值和标准方差 */" << endl;
22.     Mat myMeanMat, myStddevMat;
23.
24.     meanStdDev(img, myMeanMat, myStddevMat);
25.     cout << "img均值=" << myMeanMat << "    " << endl;
26.     cout << "img标准方差=" << myStddevMat << endl << endl;
27.     meanStdDev(imgs, myMeanMat, myStddevMat);
28.     cout << "imgs均值=" << myMeanMat << "    " << endl << endl;
29.     cout << "imgs标准方差=" << myStddevMat << endl;
30.     return 0;
31. }

图3-8 meanAndmearStdDev.cpp程序运行结果

OpenCV 4开发详解
往期推荐
【OpenCV 4开发详解】Windows系统中安装OpenCV 4
【OpenCV 4开发详解】Ubuntu系统中安装OpenCV 4
【OpenCV 4开发详解】opencv_contrib扩展模块的安装
【OpenCV 4开发详解】Image Watch插件的使用
【OpenCV 4开发详解】安装过程中问题解决方案
【OpenCV 4开发详解】了解OpenCV的模块架构
【OpenCV 4开发详解】Mat类介绍
【OpenCV 4开发详解】Mat类构造与赋值
【OpenCV 4开发详解】4种读取Mat类元素的的方法
【OpenCV 4开发详解】图像的读取与显示
【OpenCV 4开发详解】视频加载与摄像头调用
【OpenCV 4开发详解】图像与视频的保存
【OpenCV 4开发详解】保存和读取XML和YMAL文件
【OpenCV 4开发详解】颜色模型与转换
【OpenCV 4开发详解】多通道分离与合并
经过几个月的努力,市面上第一本OpenCV 4入门书籍《OpenCV 4开发详解》将春节后由人民邮电出版社发行。如果小伙伴觉得内容有帮助,希望到时候多多支持!
关注小白的小伙伴可以提前看到书中的内容,我们创建了学习交流群,欢迎各位小伙伴添加小白微信加入交流群,添加小白时请备注“学习OpenCV 4”。

【OpenCV 4开发详解】图像像素统计相关推荐

  1. 【OpenCV 4开发详解】两图像间的像素操作

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  2. 【OpenCV 4开发详解】图像二值化

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  3. 【OpenCV 4开发详解】图像腐蚀

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  4. 【OpenCV 4开发详解】图像距离变换

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  5. 【OpenCV 4开发详解】图像连通域分析

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  6. 【OpenCV 4开发详解】图像噪声的种类与生成

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  7. 【OpenCV 4开发详解】图像卷积

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  8. 【OpenCV 4开发详解】图像直方图绘制

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  9. 【OpenCV 4开发详解】图像金字塔

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

最新文章

  1. POJ 1207 The 3n + 1 problem
  2. Confluence 6 系统运行信息中的 JVM 内存使用情况
  3. HTTP缓存原理介绍
  4. 怎么解决input中readonly属性的iOS一直存在光标问题
  5. MySQL启动出现The server quit without updating PID file错误解决办法
  6. MVC---------ViewBag
  7. 把.Net开发环境迁移到Linux上去
  8. 空间两条直线的夹角公式(两向量的夹角公式)
  9. EnableQ,细腻让其与众不同
  10. git大坑---cleanup
  11. 批量生成奖状的简单程序
  12. 一个空间多个php网站,一个空间多个域名多个网站的办法汇总
  13. byte 16进制 2进制理解
  14. RealityCapture场景建模笔记
  15. PHP执行shell_exec方法失败
  16. Python爬虫之js加密破解,抓取网易云音乐评论生成词云
  17. QA的职责和角色定位
  18. 国家名称映射和省市名称映射
  19. 卷起来了!往届最快1.5个月完成见刊检索的IEEE学术会议
  20. Linux中软件的安装方式

热门文章

  1. 微信真要做操作系统了?
  2. 11月最佳机器学习开源项目Top10!
  3. AI量身定制:如何打造符合“中国特色教育”的内容推荐体系?
  4. 23 种设计模式的通俗解释
  5. 面试官问:你来讲下Netty通信中的粘包、拆包?
  6. 大白话带你认识Kafka
  7. 我的面试标准:第一能干活,第二Java基础要好,第三最好熟悉些分布式框架!...
  8. 特征工程(三)Doc2Vec
  9. 画出漂亮的神经网络图!神经网络可视化工具集锦搜集
  10. 北大校友“炼丹”分享:OpenAI如何训练千亿级模型?