OpenCV直方图-1:找到,绘制,分析!

目标

学会

  • 使用OpenCV和Numpy函数查找直方图
  • 使用OpenCV和Matplotlib函数绘制直方图
  • 您将看到以下功能:cv2.calcHist()np.histogram()

理论

什么是直方图?你可以把直方图看作一个图形或图表,这样你就可以对图像的强度分布有一个全面的了解。它是一个在X轴上有像素值(从0到255,并不总是)的图形,以及Y轴上图像中相应的像素数。

这只是理解图像的另一种方式。通过查看一幅图像的直方图,你就可以得到图像的对比度、亮度、强度分布等方面的直觉。现在几乎所有的图像处理工具都提供了直方图上的功能。

Histogram Example

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

查找直方图

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

BINS :上面的直方图显示每个像素值的像素数,即从0到255。即需要256个值才能显示上面的直方图。但是请考虑一下,如果您不需要分别找到所有像素值的像素数,而需要在像素值的间隔中找到像素数呢?例如,您需要找到位于0到15之间的像素数,然后是16到31,…,240到255之间的像素数。您将只需要16个值来表示直方图。这就是给出的例子中所显示的。所以你只需把整个直方图分割成16个子部分,每个子部分的值就是所有像素计数的总和。这每一个子部分都叫做“BIN”。在第一种情况下,256个BINS 的数目(每个像素一个),而在第二个情况下,只有16个。

DIMS :这是我们收集数据的参数。在这种情况下,我们只收集一件事的数据,强度值。这里是1。

RANGE :它是你要测量的强度值的范围。通常情况下,它是[0,256](所有强度值)。

1.OpenCV中的直方图计算

所以现在我们用cv2.calcHist()函数查找直方图。让我们熟悉一下函数及其参数:

cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])

扫描二维码关注公众号,回复: 2750975 查看本文章
  1. images:它是uint 8型或浮动32型的源图像,应该放在方括号中,即“[img]”。
  2. channels:它也放在方括号内。它是我们计算直方图的信道指数。例如,如果输入是灰度图像,则其值为[0]。对于彩色图像,可以通过[0]、[1]或[2]分别计算蓝色、绿色或红色通道的直方图。
  3. maskmask图像。为了找到完整图像的直方图,它被赋予“None”。但是如果你想要找到图像的特定区域的直方图,你必须为它创建一个掩码图像,并将它作为掩码。
  4. histSize:这代表我们的BIN计数。必须放在方括号内。 
  5. ranges:这是我们的范围。通常是[0,256]。

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

img = cv2.imread('home.jpg',0)
hist = cv2.calcHist([img],[0],None,[256],[0,256])

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

2.Numpy中的直方图计算

Numpy还为您提供了一个函数,np.histogram()。因此,您可以尝试下面的代码行,而不是calasHist()函数:

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

#img.ravel() 将图像转成一维数组,这里没有中括号。

hist 和我们以前计算的一样。但是bins将有257个元素,因为Numpy计算回收箱为0-0.99,1-1.99,2-2.99等等。所以最后的范围是255-255.99。为了表示这一点,他们还在bins的末端增加了256。但我们不需要那256个。最多255就足够了。

作图直方图

有两种方法,

  1. 使用Matplotlib绘图功能
  2. 使用OpenCV绘图功能

1.使用Matplotlib

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

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

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('home.jpg',0)
plt.hist(img.ravel(),256,[0,256]); plt.show()

您将得到如下情节:

Histogram Plotting in Matplotlib

或者您可以使用matplotlib的普通绘图,这对BGR绘图很有好处。为此,您需要首先找到直方图数据。试试下面的代码:

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('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()

结果:

Histogram Plotting in Matplotlib

您可以从上面的图表中发现,蓝色在图像中有一些高值的区域(显然应该是由于天空的缘故)。

2.使用OpenCV

在这里,您可以调整直方图的值以及它的bin值,使其看起来像x,y坐标,这样就可以使用cv2.line()或cv2.polyline()函数来生成与上面相同的图像。

Mask的应用

我们使用cv2.calcHist()来查找整个图像的直方图。如果您想要找到图像的某些区域的直方图怎么办?只需在要查找直方图和黑色的区域上创建一个白色的掩码图像即可。 

img = cv2.imread('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()

看看结果。在直方图中,蓝色线显示全图像的直方图,绿线显示Mask区域的直方图。

Histogram Example

猜你喜欢

转载自blog.csdn.net/rongpeisheng666/article/details/81632261