直方图的概念
图像直方图反映了图像中的灰度分布规律。它描述每个灰度级具有的像元个数,但不包含这些像元在图像中的位置信息。任何一幅特定的图像都有唯一的直方图与之对应,但不同的图像可以有相同的直方图。如果一幅图像有两个不相连的区域组成,并且每个区域的直方图已知,则整幅图像的直方图是两个区域直方图的和。根据直方图的形态可以大致推断图像质量的好坏。由于图像包含有大量的像元,其像元灰度值的分布应符合概率统计分布规律。假定像元的灰度值是随机分布的,那么其直方图应该是正态分布。
图像的灰度值是离散变量,因此直方图表示的是离散的概率分布。若以各灰度级的像元数占总像元数的比例值为纵坐标轴做出图像的直方图,将直方图中各条形的最高点连成一条外轮廓线,纵坐标的比例值即为某灰度级出现的概率密度,轮廓线可近似看成图像相应的连续函数的概率分布曲线。
绘制直方图
计算直方图的方式有两种,一种是使用OpenCV函数,一种是使用Numpy函数。
OpenCV中利用cv2.calcHist(images,channels,mask,histSize,ranges[,hist[,accumulate]])来计算直方图,其中images、channels、mask、histSize、ranges分别为原图像(图像格式为 uint8 或 float32)、通道类型、掩模图像、BIN 的数目、像素值范围。
Numpy中有两个函数都可以计算直方图,分别为np.histogram(a,bins=10,range=None,weights=None,density=False)和np.bincount(x, weights=None, minlength=0)。在np.histogram()方法中参数a是待统计数据的数组,参数bins指定统计的区间个数,参数range是一个长度为2的元组,表示统计范围的最小值和最大值,默认值None,即表示范围由数据的范围决定,参数weights为数组的每个元素指定了权值,np.histogram()会对区间中数组所对应的权值进行求和,参数density为True时,返回每个区间的概率密度;若为False,则返回每个区间中元素的个数。在np.bincount()方法中,参数x为输入数组,参数weights为权重数组,参数minlength为输出阵列的最小BIN数。
示例代码
# -*- coding: utf-8 -*-
# By:Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
#读取图像
src = cv2.imread('lena-hd.png')
#计算256灰度级的图像直方图
hist = cv2.calcHist([src], [0], None, [256], [0,255])
#输出直方图大小、形状、数量
print(hist.size)
print(hist.shape)
print(hist)
#设置字体
matplotlib.rcParams['font.sans-serif']=['SimHei']
#显示原始图像和绘制的直方图
plt.subplot(121)
plt.imshow(src, 'gray')
plt.axis('off')
plt.title("(a)Lena灰度图像")
plt.subplot(122)
plt.plot(hist, color='r')
plt.xlabel("x")
plt.ylabel("y")
plt.title("(b)直方图曲线")
plt.show()