OpenCV 4.13.0
开源计算机视觉库 (Open Source Computer Vision)
正在加载...
正在搜索...
未找到匹配项
直方图计算

上一个教程: 直方图均衡化
下一个教程: 直方图比较

原作者Ana Huamán
兼容性OpenCV >= 3.0

目标

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

  • 使用 OpenCV 函数 cv::split 将图像分割成对应的平面。
  • 通过使用 OpenCV 函数 cv::calcHist 计算图像数组的直方图
  • 使用函数 cv::normalize 归一化数组
注意
在上次教程 (直方图均衡化) 中,我们讨论了一种特殊的直方图,称为 图像直方图。现在我们将从更一般的概念来考虑它。继续阅读!

什么是直方图?

  • 直方图是收集到的数据 计数,这些数据被组织到一组预定义的 bins
  • 当我们说 数据 时,我们并不局限于强度值(正如我们在之前的教程 直方图均衡化 中看到的)。收集的数据可以是任何你认为对描述图像有用的特征。
  • 我们来看一个例子。假设一个矩阵包含图像信息(即强度范围 \(0-255\))
  • 如果我们想以一种有组织的方式 计数 这些数据会发生什么?由于我们知道此案例中信息值的 范围 是 256 个值,我们可以将我们的范围分段(称为 bins),例如

    \[\begin{array}{l} [0, 255] = { [0, 15] \cup [16, 31] \cup ....\cup [240,255] } \\ range = { bin_{1} \cup bin_{2} \cup ....\cup bin_{n = 15} } \end{array}\]

    并且我们可以计算落在每个 \(bin_{i}\) 范围内的像素数量。将此应用于上述示例,我们得到下图(x 轴表示 bins,y 轴表示每个 bin 中的像素数量)。

  • 这只是一个关于直方图如何工作以及为什么它有用的简单示例。直方图不仅可以统计颜色强度,还可以统计我们想要测量的任何图像特征(例如梯度、方向等)。
  • 我们来识别直方图的几个部分
    1. dims:您想要收集数据的参数数量。在我们的示例中,dims = 1,因为我们只计算每个像素的强度值(在灰度图像中)。
    2. bins:它是每个 dims 中的 细分 数量。在我们的示例中,bins = 16
    3. range:要测量的值的限制。在此案例中:range = [0,255]
  • 如果您想统计两个特征呢?在这种情况下,您的结果直方图将是一个 3D 图(其中 x 和 y 将是每个特征的 \(bin_{x}\) 和 \(bin_{y}\),而 z 将是每个 \((bin_{x}, bin_{y})\) 组合的计数)。同样也适用于更多特征(当然会变得更复杂)。

OpenCV 为您提供什么

出于简单目的,OpenCV 实现了函数 cv::calcHist,它计算一组数组(通常是图像或图像平面)的直方图。它可以处理多达 32 个维度。我们将在下面的代码中看到它!

代码

  • 这个程序做什么?
    • 加载图像
    • 使用函数 cv::split 将图像分割成 R、G 和 B 平面
    • 通过调用函数 cv::calcHist 计算每个单通道平面的直方图
    • 在一个窗口中绘制三个直方图

解释

  • 加载源图像

  • 将源图像分成其三个 R、G 和 B 平面。为此我们使用 OpenCV 函数 cv::split

    我们的输入是要分割的图像(此案例中有三个通道),输出是一个 Mat 向量

  • 现在我们准备开始配置每个平面的 直方图。由于我们处理的是 B、G 和 R 平面,我们知道我们的值将在区间 \([0,255]\) 范围内
  • 确定 bin 的数量(5、10...)

  • 设置值的范围(如我们所说,介于 0 到 255 之间)

  • 我们希望我们的 bins 具有相同的大小(均匀),并且在开始时清除直方图,所以

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

  • 其中参数是(C++ 代码
    • &bgr_planes[0]: 源数组
    • 1:源数组的数量(在本例中我们使用 1。我们也可以在此处输入数组列表)
    • 0:要测量的通道(dim)。在此案例中它只是强度(每个数组是单通道),所以我们只写 0。
    • Mat():用于源数组的掩码(零表示要忽略的像素)。如果未定义则不使用
    • b_hist:存储直方图的 Mat 对象
    • 1:直方图维度。
    • histSize: 每个使用的维度中的 bin 数量
    • histRange: 每个维度的测量值范围
    • uniformaccumulate:bin 大小相同,并且直方图在开始时被清除。
  • 创建图像以显示直方图

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

  • 此函数接收这些参数(C++ 代码
    • b_hist: 输入数组
    • b_hist: 输出归一化数组(可以是同一个)
    • 0histImage.rows:对于此示例,它们是归一化 r_hist 值的下限和上限
    • NORM_MINMAX: 指示归一化类型的参数(如上所述,它将值调整到之前设置的两个限制之间)
    • -1: 表示输出归一化数组将与输入具有相同的类型
    • Mat(): 可选掩码
  • 请注意,要访问 bin(在此案例中是 1D-直方图)

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

    b_hist.at<float>(i)

    其中 \(i\) 表示维度。如果它是 2D 直方图,我们将使用类似

    b_hist.at<float>( i, j )
  • 最后,我们显示直方图并等待用户退出

结果

  1. 使用如下图所示的图像作为输入参数
  1. 生成以下直方图