OpenCV直方图计算

devtools/2024/9/23 10:30:26/
 返回:OpenCV系列文章目录(持续更新中......)
上一篇:OpenCV实现直方图均衡
下一篇 :OpenCV系列文章目录(持续更新中......)

在本教程中,您将学习如何:

  • 使用 OpenCV 函数 cv::split 将图像划分为其对应平面。
  • 使用 OpenCV 函数计算图像数组的直方图 cv::calcHist
  • 使用函数 cv::normalize 规范化数组

注意

在上一个教程(直方图均衡)中,我们讨论了一种特殊的直方图,称为图像直方图。现在我们将从更一般的概念中考虑它。请继续阅读!

什么是直方图?

  • 直方图是组织到一组预定义箱中的数据计数集合
  • 当我们说数据时,我们并没有将其限制为强度值(正如我们在上一教程直方图均衡中看到的那样)。收集的数据可以是您认为对描述图像有用的任何特征。
  • 让我们看一个例子。想象一下,矩阵包含图像的信息即强度在(0-255)范围内:

  • 如果我们想以有组织的方式计算这些数据,会发生什么?由于我们知道这种情况的信息值范围是 256 个值,因此我们可以将范围分割成子部分(称为),例如:

[0,255]=[0,15]∪[16,31]∪....∪[240,255]�����=���1∪���2∪....∪����=15

我们可以计算每个 \(bin_{i}\) 范围内的像素数。将其应用于上面的示例,我们得到下面的图像(轴 x 表示箱,轴 y 表示每个箱中的像素数)。

  • 这只是直方图如何工作以及为什么它有用的简单示例。直方图不仅可以计算颜色强度,还可以计算我们想要测量的任何图像特征(即渐变、方向等)。
  • 让我们确定直方图的某些部分:
    1. dims:要收集数据的参数数。在我们的示例中,dims = 1,因为我们只计算每个像素的强度值(在灰度图像中)。
    2. bins:是每个 dim 中的细分数量。在我们的示例中,bins = 16
    3. range:要测量的值的限值。在本例中:范围 = [0,255]
  • 如果要计算两个功能怎么办?在这种情况下,生成的直方图将是一个 3D 图(其中 x 和 y 将是每个特征的 \(bin_{x}\) 和 \(bin_{y}\),z 将是 \((bin_{x}, bin_{y})\) 的每个组合的计数数)。这同样适用于更多功能(当然它会变得更棘手)。

OpenCV 为您提供什么

为了简单起见,OpenCV 实现了函数 cv::calcHist ,它计算一组数组(通常是图像或图像平面)的直方图。它最多可以操作 32 个尺寸。我们将在下面的代码中看到它!

C++代码
 

  • 这个程序是做什么的?
    • 加载图像
    • 使用函数 cv::split 将图像拆分为 R、G 和 B 平面
    • 通过调用函数 cv::calcHist 计算每个 1 通道平面的直方图
    • 在窗口中绘制三个直方图
  • 可下载代码: 点击这里
  • 代码一览
  • :
    #include "opencv2/highgui.hpp"
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/imgproc.hpp"
    #include <iostream>using namespace std;
    using namespace cv;int main(int argc, char** argv)
    {CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );if( src.empty() ){return EXIT_FAILURE;}vector<Mat> bgr_planes;split( src, bgr_planes );int histSize = 256;float range[] = { 0, 256 }; //the upper boundary is exclusiveconst float* histRange[] = { range };bool uniform = true, 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, hist_h = 400;int bin_w = cvRound( (double) hist_w/histSize );Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );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 );}imshow("Source image", src );imshow("calcHist Demo", histImage );waitKey();return EXIT_SUCCESS;
    }

解释
 

加载源图像

 CommandLineParser parser( argc, argv, "{@input | lena.jpg | input image}" );Mat src = imread( samples::findFile( parser.get<String>( "@input" ) ), IMREAD_COLOR );if( src.empty() ){return EXIT_FAILURE;}

将源图像分隔到三个 R、G 和 B 平面中。为此,我们使用 OpenCV 函数cv::split :

 vector<Mat> bgr_planes;split( src, bgr_planes );
  • 我们的输入是要分割的图像(在这种情况下有三个通道),输出是 Mat 的向量)

  • 现在,我们已准备好开始配置每个平面的直方图。由于我们正在使用 B、G 和 R 平面,因此我们知道我们的值将在区间内范围内[0,255]
  • 确定箱数 (5, 10...):

 int histSize = 256;

设置值范围(正如我们所说,介于 0 和 255 之间)

 float range[] = { 0, 256 }; //the upper boundary is exclusiveconst float* histRange[] = { range };

我们希望我们的箱具有相同的大小(均匀),并在开始时清除直方图,因此:

 bool uniform = true, accumulate = false;

我们继续使用 OpenCV 函数 cv::calcHist 计算直方图:

 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 );
  • 其中参数为 (C++ 代码):
    • &bgr_planes[0]:源数组
    • 1:源数组的数量(在本例中我们使用 1.我们也可以在这里输入数组列表:)
    • 0:要测量的通道(暗淡)。在这种情况下,它只是强度(每个数组都是单通道的),所以我们只写 0。
    • Mat():要在源数组上使用的掩码(零表示要忽略的像素)。如果未定义,则不使用
    • b_hist:将存储直方图的 Mat 对象
    • 1:直方图维数。
    • histSize:每个使用维度的箱数
    • histRange:每个维度要测量的值范围
    • 均匀累积:箱大小相同,直方图在开始时被清除。
  • 创建图像以显示直方图:

 int hist_w = 512, hist_h = 400;int bin_w = cvRound( (double) hist_w/histSize );Mat histImage( hist_h, hist_w, CV_8UC3, Scalar( 0,0,0) );

请注意,在绘制之前,我们首先对直方图进行 cv::规范化,使其值落在输入的参数指示的范围内:

 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() );
  • 此函数接收以下参数(C++ 代码):
    • b_hist:输入数组
    • b_hist:输出规范化数组(可以相同)
    • 0 和 histImage.rows:在此示例中,它们是规范化 r_hist 值的下限和上限
    • NORM_MINMAX:指示规范化类型的参数(如上所述,它调整之前设置的两个限制之间的值)
    • -1:表示输出规范化数组的类型将与输入相同
    • 垫():可选面罩
  • 要访问箱(在本例中为此 1D 直方图),请注意:

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

我们使用表达式(C++代码):

b_hist.at<float>(i)

其中表示尺寸。如果它是 2D 直方图,我们会使用如下内容:最后,我们显示直方图并等待用户退出:

 imshow("Source image", src );imshow("calcHist Demo", histImage );waitKey();

结果

  1. 使用如下所示的图像作为输入参数:

  1. 生成以下直方图:


参考文献:

1、《Histogram Calculation》-----Ana Huamán


http://www.ppmy.cn/devtools/20071.html

相关文章

大创项目推荐 深度学习交通车辆流量分析 - 目标检测与跟踪 - python opencv

文章目录 0 前言1 课题背景2 实现效果3 DeepSORT车辆跟踪3.1 Deep SORT多目标跟踪算法3.2 算法流程 4 YOLOV5算法4.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; *…

sheng的学习笔记-AI-支持向量机(SVM)

目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 目录 什么是向量机 SVM算法原理 SVM基本模型 SVM对偶问题 什么是对偶问题&#xff1a; 为什么使用对偶问题 拉格朗日定理 拉格朗日乘子法 对偶问题算法 非线性SVM算法原理 核函数 常用核函数 软间隔与正则化 软…

书生·浦语大模型开源体系(四)笔记

&#x1f497;&#x1f497;&#x1f497;欢迎来到我的博客&#xff0c;你将找到有关如何使用技术解决问题的文章&#xff0c;也会找到某个技术的学习路线。无论你是何种职业&#xff0c;我都希望我的博客对你有所帮助。最后不要忘记订阅我的博客以获取最新文章&#xff0c;也欢…

MySQL常见的约束

什么是约束&#xff1f; 限制&#xff0c;限制我们表中的数据&#xff0c;保证添加到数据表中的数据准确和可靠性&#xff01;凡是不符合约束的数据&#xff0c;插入时就会失败&#xff0c;插入不进去的&#xff01; 比如&#xff1a;学生信息表中&#xff0c;学号就会约束不…

虚假新闻检测——Adapting Fake News Detection to the Era of Large Language Models

论文地址:https://arxiv.org/abs/2311.04917 1.概论 尽管大量的研究致力于虚假新闻检测,这些研究普遍存在两大局限性:其一,它们往往默认所有新闻文本均出自人类之手,忽略了机器深度改写乃至生成的真实新闻日益增长的现象;其二,它们倾向于将所有机器制造的新闻一概视作虚…

Python 中空间数据的 10 个基本操作

读取几何图形首先,让我们从阅读几何图形开始。 来自 csv geoms = pd.read_csv(geometries.csv) 想象一下文件在列几何体下包含多边形,我们现在必须将它们转换为几何类型(默认情况下它们将被读取为字符串)。通常,几何图形将以wkt格式,我们用shapely库进行转换 # if th…

txt大文件拆分(批量版)

之前的python程序只能拆分单个文件&#xff0c;这里重新加了个文件夹拆分的功能&#xff08;打包好的exe文件在文章末尾&#xff09; 使用步骤&#xff1a;运行代码–>把文件放到input文件夹里–>命令行界面回车–>output文件夹输出文件 outputPath "./output&q…

多目标应用:基于非支配排序粒子群优化算法NSPSO求解无人机三维路径规划(MATLAB代码)

一、无人机多目标优化模型 无人机三维路径规划是无人机在执行任务过程中的非常关键的环节&#xff0c;无人机三维路径规划的主要目的是在满足任务需求和自主飞行约束的基础上&#xff0c;计算出发点和目标点之间的最佳航路。 1.1路径成本 无人机三维路径规划的首要目标是寻找…