直方图
什么是直方图呢?
直方图是对数据集合统计,并将统计结果分布于一系列定义的bins中。这里的数据不仅仅是灰度值,统计数据可能是任何能够有效描述图像的特征,例如颜色、梯度/边缘、形状、纹理、局部特征点、视觉词汇等。
灰度直方图
通过直方图你可以对整幅图像的灰度分布有一个整体的了解。直方图的 x 轴是灰度值(0 到 255),y 轴是图片中具有同一个灰度值的点的数目。
灰度直方图其实就是对图像的另一种解释。通过直方图我们可以对图像的对比度,亮度,灰度分布等有一个直观的认识。几乎所有的图像处理软件都提供了直方图分析功能。在这里,直方图是根据灰度图像绘制的,而不是彩色图像。直方图的左边区域像是了暗一点的像素数量,右侧显示了亮一点的像素的数量。
使用OpenCV 统计直方图函数 cv2.calcHist 可以帮助我们统计一幅图像的直方图。
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
参数意义如下:
-
images: 原图像(图像格式为 uint8 或 float32)。当传入函数时应该用中括号 [] 括起来,例如:[img]。
-
channels: 同样需要用中括号括起来,它会告诉函数我们要统计那幅图像的直方图。如果输入图像是灰度图,它的值就是 [0];如果是彩色图像的话,传入的参数可以是 [0],[1],[2] 它们分别对应着通道 B,G,R。
-
mask: 掩模图像。要统计整幅图像的直方图就把它设为 None。但是如果你想统计图像某一部分的直方图的话,你就需要制作一个掩模图像,并使用它。(后边有例子)
-
histSize:BIN 的数目。也应该用中括号括起来,例如:[256]。
-
ranges: 像素值范围,通常为 [0,256]
例子:以灰度格式加载一幅图像并统计图像的直方图
import cv2
import matplotlib.pyplot as plt
import numpy as np
def img_show(name,img):
"""matplotlib图像显示函数
name:字符串,图像标题
img:numpy.ndarray,图像
"""
if len(img.shape) == 3:
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
plt.imshow(img,'gray')
#plt.xticks([])
#plt.yticks([])
plt.xlabel(name,fontproperties='FangSong',fontsize=12)
if __name__=="__main__":
img1 = cv2.imread("cute-dog.jpg",0)
#别忘了中括号[img1],[0],None,[256],[0,256],只有mask没有中括号
hist = cv2.calcHist([img1],[0],None,[256],[0,256])
plt.figure(figsize=(12,8),dpi=80)
plt.subplot(121)
img_show('原图',img1)
plt.subplot(122)
plt.plot(hist)
plt.xlim([0,256])
plt.ylim([0,800000])
plt.xlabel('直方图',fontproperties='FangSong',fontsize=12)
直方图1.png
使用 Matplotlib Matplotlib 中有直方图绘制函数:matplotlib.pyplot.hist()它可以直接统计并绘制直方图。
img1 = cv2.imread("cute-dog.jpg",0)
plt.figure(figsize=(12,8),dpi=80)
plt.subplot(121)
img_show('原图',img1)
plt.subplot(122)
plt.hist(img1.ravel(),256,[0,256])
plt.xlim([0,256])
plt.xlabel('直方图',fontproperties='FangSong',fontsize=12)
直方图2.png
例子:绘制BGR通道直方图
img1 = cv2.imread("cute-dog.jpg")
color = ('b','g','r')
# 对一个列表或数组既要遍历索引又要遍历元素时
# 使用内置enumerrate函数会有更加直接,优美的做法
# enumerate会将数组或列表组成一个索引序列。
# 使我们再获取索引和索引内容的时候更加方便
for i,col in enumerate(color):
print(i)
print(col)
hist = cv2.calcHist([img1],[i],None,[256],[0,256])
plt.plot(hist,color=col)
plt.xlim([0,256])
plt.ylim([0,800000])
plt.show()
直方图3.png
img1 = cv2.imread("cute-dog.jpg")
color = ('b','g','r')
for i,col in enumerate(color):
plt.hist(img1[:,:,i].ravel(),256,[0,256],color=col,alpha=1)
plt.xlim([0,256])
plt.ylim([0,800000])
plt.show()
直方图4.png
使用掩模
要统计图像某个局部区域的直方图只需要构建一副掩模图像。将要统计的部分设置成白色,其余部分为黑色,就构成了一副掩模图像。然后把这个掩模图像传给函数就可以了。
例子:统计图像某个局部区域的直方图
img1 = cv2.imread("cute-dog.jpg")
img = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
# 创建掩膜
mask = np.zeros(img.shape[:2],np.uint8)
mask[1000:4000,100:3200] = 255
img_mask = cv2.bitwise_and(img,img,mask =mask)
# 创建一个掩膜和一个无掩膜的直方图
hist_full = cv2.calcHist([img],[0],None,[256],[0,256])
hist_mask = cv2.calcHist([img_mask],[0],mask,[256],[0,256])
plt.figure(figsize=(10,8),dpi=80)
plt.subplot(221)
plt.imshow(img,'gray')
plt.subplot(222)
plt.imshow(mask,'gray')
plt.subplot(223)
plt.imshow(img_mask,'gray')
plt.subplot(224)
plt.plot(hist_full,label='original')
plt.plot(hist_mask,label='img_mask')
plt.legend()
plt.xlim([0,256])
plt.ylim([0,800000])
局部直方图.png
参考资料:
网址:Matplotlib基础教程
书籍:《数字图像处理》《OpenCV-Python-Toturial-中文版》
网友评论