直方图概念
图像的构成是有像素点构成的,每个像素点的值代表着该点的颜色(灰度图或者彩色图)。所谓直方图就是对图像的中的这些像素点的值进行统计,得到一个统一的整体的灰度概念。一般情况下直方图都是灰度图像,直方图x轴是灰度值(一般0~255),y轴就是图像中每一个灰度级对应的像素点的个数。直方图的好处就在于可以清晰了解图像的整体灰度分布,这对于后面依据直方图处理图像来说至关重要。
统计直方图
Opencv给我们提供的函数是cv2.calcHist(),该函数有5个参数:
hist = cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
#hist 是一个 256x1 的数组,每一个值代表了与次灰度值对应的像素点数目。
- images: 原图像(图像格式为 uint8 或 float32)。当传入函数时应该用中括号 [] 括起来,例如:[img]。
- channels: 同样需要用中括号括起来,它会告诉函数我们要统计那幅图像的直方图。如果输入图像是灰度图,它的值就是 [0];如果是彩色图像的话,传入的参数可以是 [0],[1],[2] 它们分别对应着通道 B,G,R。
- mask: 掩模图像。要统计整幅图像的直方图就把它设为 None。但是如果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像,并使用它。
- histSize:BIN 的数目。也应该用中括号括起来,例如:[256]。
- ranges: 像素值范围,通常为 [0,256]
什么是BIN呢?
直方图显示了每个灰度值对应的像素数。如果像素值为 0到 255,你就需要 256 个数来显示上面的直方图。但是,如果你不需要知道每一个像素值的像素点数目的,而只希望知道两个像素值之间的像素点数目怎么办呢?举例来说,我们想知道像素值在 0 到 15 之间的像素点的数目,接着是 16 到 31,....,240 到 255。我们只需要 16 个值来绘制直方图。那到底怎么做呢?你只需要把原来的 256 个值等分成 16 小组,取每组的
总和。而这里的每一个小组就被成为 BIN,即有 16 个 BIN。
使用 Numpy 统计直方图
Numpy 中的函数 np.histogram() 也可以帮我们统计直方图。
#img.ravel() 将图像转成一维数组,这里没有中括号。
hist,bins = np.histogram(img.ravel(),256,[0,256])
这里的 bins 是 257,因为 Numpy 计算bins 的方式为: 0-0.99,1-1.99,2-2.99 等。所以最后一个范围是 255-255.99。
Numpy 还 有 一 个 函 数 np.bincount(), 它 的 运 行 速 度 是np.histgram 的 十 倍。 所 以 对 于 一 维 直 方 图, 我 们 最 好 使 用 这 个函 数。
img = cv2.imread("/home/wl/4.jpg",0)
hist=np.bincount(img.ravel(),minlength=256)
注意:OpenCV 的 函 数 要 比 np.histgram() 快 40 倍。 所 以 坚 持 使 用OpenCV 函数。
绘制直方图
使用 Matplotlib的直方图绘制函数: matplotlib.pyplot.hist(),实例如下:
原图:
# coding=utf-8
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread("/home/wl/4.jpg",0)
plt.hist(img.ravel(),256,[0,256]);
plt.show()
直方图:
同时绘制多通道(BGR)的直方图
# coding=utf-8
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread("/home/wl/4.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()
结果:
使用掩模
要统计图像某个局部区域的直方图只需要构建一副掩模图像。将要统计的部分设置成白色,其余部分为黑色,就构成了一副掩模图像。然后把这个掩模图像传给函数就可以了。
# coding=utf-8
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread("/home/wl/4.jpg")
mask = np.zeros(img.shape[:2], np.uint8)
mask[200:400, 100:400] = 255
masked_img = cv2.bitwise_and(img,img,mask = 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()
结果: