5.1. 直方图-1:查找,绘制,分析!!!

5.1.1. 目标

学会
-使用OpenCV和Numpy函数查找直方图-使用OpenCV和Matplotlib函数绘制直方图-您将看到以下函数: 化学气相色谱仪()直方图() 等。

5.1.2. 理论

什么是直方图?你可以把直方图看作是一个图表,它给你一个关于图像强度分布的整体概念。它是一个在X轴上有像素值(范围从0到255,并不总是)和在Y轴上有相应数量像素的图像的绘图。

这只是理解图像的另一种方式。通过查看图像的直方图,可以直观地了解图像的对比度、亮度、强度分布等。现在几乎所有的图像处理工具都提供了直方图特性。下面是来自 Cambridge in Color website ,我建议您访问该网站了解更多详细信息。

你可以看到图像及其直方图。(请记住,此直方图是为灰度图像而不是彩色图像绘制的)。直方图的左区域显示图像中较暗像素的数量,右区域显示较亮像素的数量。从直方图中,你可以看到暗区比亮区多,中间色调的数量(像素值在中间范围,比如127左右)非常少。

5.1.3. 查找直方图

现在我们知道什么是直方图,我们可以研究如何找到这个。OpenCV和Numpy都有内置的函数。在使用这些函数之前,我们需要了解一些与直方图相关的术语。

BINS :上面的直方图显示每个像素值的像素数,即从0到255。你需要256个值来显示上面的直方图。但是考虑一下,如果不需要分别找到所有像素值的像素数,而是需要找到像素值间隔中的像素数,该怎么办?例如,您需要找到介于0到15、16到31、…、240到255之间的像素数。您只需要16个值来表示直方图。这就是在 OpenCV Tutorials on histograms .

所以你要做的就是把整个直方图分割成16个子部分,每个子部分的值就是其中所有像素的总和。每个子部分都称为“BIN”。在第一种情况下,256个(每个像素一个)的存储箱的数量,而在第二种情况下,只有16个。箱子用术语表示 组织大小 在OpenCV文档中。

DIMS :它是我们收集数据的参数数。在这种情况下,我们只收集一个方面的数据,即强度值。所以这里是1。

RANGE :它是要测量的强度值的范围。通常,它是 [0256年] ,即所有强度值。

一。OpenCV中的直方图计算

所以现在我们用 化学气相色谱仪() 函数来查找直方图。让我们熟悉一下函数及其参数:

[cv2.calcHist(图像、通道、掩码、histSize、范围[、hist[、累加])]

  1. 图像:它是uint8或float32类型的源图像。它应该用方括号括起来 [img] ”.

  2. 频道:也在方括号内。它是我们计算直方图的通道索引。例如,如果输入为灰度图像,则其值为 [0] . 对于彩色图像,可以通过 [0] , [1] 或 [2] 分别计算蓝色、绿色和红色通道的直方图。

  3. 蒙版:蒙版图像。为了找到完整图像的直方图,将其指定为“无”。但如果你想找到图像特定区域的直方图,你必须为它创建一个遮罩图像,并将其作为遮罩。(稍后我将展示一个示例。)

  4. histSize:这代表我们的箱子数量。需要用方括号括起来。全面来说,我们通过了 [256] .

  5. 范围:这是我们的范围。通常,它是 [0256年] .

所以让我们从一个样本图像开始。只需在灰度模式下加载图像并找到其完整的直方图。

>>> import cv2
>>> import numpy as np
>>> img = cv2.imread('/cvdata/home.jpg',0)
>>> hist = cv2.calcHist([img],[0],None,[256],[0,256])

hist是一个256x1数组,每个值对应于该图像中的像素数及其对应的像素值。

2。Numpy中的直方图计算

Numpy还提供了一个函数, 直方图() . 因此,您可以在下面的行中尝试,而不是calcHist()函数:

>>> hist,bins = np.histogram(img.ravel(),256,[0,256])

历史和我们之前计算的一样。但是容器将有257个元素,因为Numpy将容器计算为0-0.99、1-1.99、2-2.99等,所以最终范围是255-255.99。为了表示这一点,它们还在箱子的末端添加了256个。但我们不需要256。最多255个就足够了。

Numpy还有另一个功能, 二进制数() 比(大约10倍)np.histogram()快得多。所以对于一维直方图,你最好试试。别忘了设置 minlength = 256 在np.bincount中。例如, hist = np.bincount(img.ravel(),minlength=256)

注意

OpenCV函数比np.histogram()快(大约40倍)。所以请坚持使用OpenCV函数。

现在我们应该绘制柱状图,但是如何绘制呢?

5.1.4. 绘制直方图

有两种方法,
一。简而言之:使用Matplotlib绘图函数2。长途跋涉:使用OpenCV绘图功能

一。使用Matplotlib

Matplotlib附带一个直方图绘制函数:Matplotlib.pyplot.hist()

它直接找到直方图并绘制出来。不需要使用calcHist()或np.histogram()函数来查找直方图。请参见下面的代码:

>>> import cv2
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>>
>>> img = cv2.imread('/cvdata/home.jpg',0)
>>> plt.hist(img.ravel(),256,[0,256]); plt.show()
../_images/sec01-histogram-begins_6_0.png

你将得到如下的情节:

或者可以使用matplotlib的normal plot,这对BGR plot很好。为此,首先需要找到直方图数据。请尝试以下代码:

>>> %matplotlib inline
>>> import cv2
>>> import numpy as np
>>> from matplotlib import pyplot as plt
>>>
>>> img = cv2.imread('/cvdata/home.jpg')
>>> color = ('b','g','r')
>>> for i,col in enumerate(color):
>>>     histr = cv2.calcHist([img],[i],None,[256],[0,256])
>>>     plt.plot(histr,color = col)
>>>     plt.xlim([0,256])
>>> plt.show()
../_images/sec01-histogram-begins_8_0.png

结果:

你可以从上面的图表中推断出,蓝色在图像中有一些高值区域(显然应该是因为天空)

2。使用OpenCV

在这里,您可以调整直方图的值及其bin值,使其看起来像x,y坐标,这样您就可以使用cv2.line()或cv2.polyline()函数绘制它,以生成与上面相同的图像。OpenCV-Python2的官方样本已经提供了这个功能。 Check the Code

5.1.5. 面罩的使用

我们使用cv2.calcHist()查找完整图像的直方图。如果你想找到图像某些区域的直方图呢?只需在要查找直方图的区域上创建一个白色的遮罩图像,否则为黑色。然后把这个当作面具。

>>> img = cv2.imread('/cvdata/home.jpg',0)
>>>
>>> # create a mask
>>> mask = np.zeros(img.shape[:2], np.uint8)
>>> mask[100:300, 100:400] = 255
>>> masked_img = cv2.bitwise_and(img,img,mask = mask)
>>>
>>> # Calculate histogram with mask and without mask
>>> # Check third argument for mask
>>> hist_full = cv2.calcHist([img],[0],None,[256],[0,256])
>>> hist_mask = cv2.calcHist([img],[0],mask,[256],[0,256])
>>>
>>> plt.subplot(221), plt.imshow(img, 'gray')
>>> plt.subplot(222), plt.imshow(mask,'gray')
>>> plt.subplot(223), plt.imshow(masked_img, 'gray')
>>> plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask)
>>> plt.xlim([0,256])
>>>
>>> plt.show()
../_images/sec01-histogram-begins_10_0.png

看看结果。在直方图图中,蓝线表示全图的直方图,绿线表示遮罩区域的直方图。

5.1.6. 额外资源

  1. Cambridge in Color website

5.1.7. 练习