直方图是图像处理过程中的一种非常重要的分析工具。直方图从图像内部灰度级的角度对图像进行表述,包含十分丰富而重要的信息。从直方图的角度对图像进行处理,可以达到增强图像显示效果的目的。

1. 直方图的含义

从统计的角度讲,直方图是图像内灰度值的统计特性与图像灰度值之间的函数,直方图统计图像内各个灰度级出现的次数。从直方图的图形上观察,横坐标是图像中各像素点的灰度级,纵坐标是具有该灰度级(像素值)的像素个数。

在这里插入图片描述

在 OpenCV 的官网上,特别提出了要注意三个概念:DIMS、BINS、RANGE。

DIMS:表示在绘制直方图时,收集的参数的数量。一般情况下,直方图中收集的数据只有一种,就是灰度级。因此,该值为1。
RANGE:表示要统计的灰度级范围,一般为[0, 255]。0 对应的是黑色,255 对应的是白色。
BINS:参数子集的数目。在处理数据的过程中,有时需要将众多的数据划分为若干个组,再进行分析。

例如,在灰度图像中,将[0, 255]区间内的256个灰度级,按照每16 个像素一组划分为子集:
[0, 255] = [0, 15] ∪ [16, 31] ∪…∪[240, 255]

按照上述方式,整个灰度级范围可以划分为16 个子集,具体为:整个灰度级范围= bin1 ∪ bin2 ∪…∪ bin16

子集划分完以后,某灰度图像生成的直方图如图所示(图中的b1 代表bin1,b2 代表bin2,以此类推)
在这里插入图片描述

2. 绘制直方图

2.1 用cv2.calcHist()函数统计图像直方图信息

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

hist:返回的统计直方图,是一个一维数组,数组内的元素是各个灰度级的像素个数。
images:原始图像,该图像需要使用“[ ]”括起来。
channels:指定通道编号。通道编号需要用“[ ]”括起来,如果输入图像是单通道灰度图像,该参数的值就是[0]。对于彩色图像,它的值可以是[0]、[1]、[2],分别对应通道B、G、R。
mask:掩模图像。当统计整幅图像的直方图时,将这个值设为None。当统计图像某一部分的直方图时,需要用到掩模图像。
histSize:BINS 的值,该值需要用“[ ]”括起来。例如,BINS 的值是256,需要使用“[256]”
作为此参数值。
ranges:即像素值范围。例如,8位灰度图像的像素值范围是[0, 255]。
accumulate:累计(累积、叠加)标识,默认值为False。如果被设置为True,则直方图在开始计算时不会被清零,计算的是多个直方图的累积结果,用于对一组图像计算直方图。该参数允许从多个对象中计算单个直方图,或者实时更新直方图。该参数是可选的,一般情况下不需要设置。

2.2 plot()函数的使用

使用 matplotlib.pyplot 模块内的plot()函数,可以将函数cv2.calcHist()的返回值绘制为图像直方图。下面通过三个例子来学习plot()函数的基本使用方法。

#将给定的x= [0,1,2,3,4,5,6],y = [0.3,0.4,2,5,3,4.5,4],使用plot()函数绘制出来。
import matplotlib.pyplot as plt
x = [0,1,2,3,4,5,6]
y = [0.3,0.4,2,5,3,4.5,4]
plt.plot(x,y)

在这里插入图片描述

给定y = [0.3, 0.4, 2, 5, 3, 4.5, 4],使用plot()函数将其绘制出来,观察绘制结果。
import matplotlib.pyplot as plt
y = [0.3,0.4,2,5,3,4.5,4]
plt.plot(y)

在这里插入图片描述

#使用plot()函数将两组不同的值a= [0.3, 0.4, 2, 5, 3, 4.5, 4],b=[3, 5, 1, 2, 1, 5, 3]以不同的颜色绘制出来。
import matplotlib.pyplot as plt
a = [0.3,0.4,2,5,3,4.5,4]
b=[3,5,1,2,1,5,3]
plt.plot(a,color='r')
plt.plot(b,color='g')

在这里插入图片描述

2.3 绘制统计直方图

#使用函数plot()将函数cv2.calcHist()的返回值绘制为直方图。
import cv2
import matplotlib.pyplot as plt
o=cv2.imread("image\\boatGray.bmp")
histb = cv2.calcHist([o],[0],None,[256],[0,255])
plt.plot(histb,color='b')
plt.show()

在这里插入图片描述

#使用函数plot()和函数cv2.calcHist(),将彩色图像各个通道的直方图绘制在一个窗口内。
import cv2
import matplotlib.pyplot as plt
o=cv2.imread("image\\girl.bmp")
histb = cv2.calcHist([o],[0],None,[256],[0,255])
histg = cv2.calcHist([o],[1],None,[256],[0,255])
histr = cv2.calcHist([o],[2],None,[256],[0,255])
plt.plot(histb,color='b')
plt.plot(histg,color='g')
plt.plot(histr,color='r')
plt.show()

在这里插入图片描述

2.4 使用掩模绘制直方图

左图是原始图像O,中间的是掩模图像M,右图是使用掩模图像M 对原始图像O 进行掩模运算的结果图像R:

在这里插入图片描述

import cv2
import numpy as np
import matplotlib.pyplot as plt
image=cv2.imread("image\\girl.bmp",cv2.IMREAD_GRAYSCALE)
mask=np.zeros(image.shape,np.uint8)
mask[200:400,200:400]=255
image2=cv2.bitwise_and(image,mask)
histImage=cv2.calcHist([image],[0],None,[256],[0,255])
histMI=cv2.calcHist([image],[0],mask,[256],[0,255])
plt.plot(histImage)
plt.plot(histMI)
cv2.imshow("origin",image)
cv2.imshow("after",image2)
cv2.waitKey()
cv2.destroyAllwindows()

在这里插入图片描述

在这里插入图片描述

3. 直方图均衡化

如果一幅图像拥有全部可能的灰度级,并且像素值的灰度均匀分布,那么这幅图像就具有高对比度和多变的灰度色调,灰度级丰富且覆盖范围较大。在外观上,这样的图像具有更丰富的色彩,不会过暗或过亮。

在这里插入图片描述

dst = cv2.equalizeHist( src )

#-----------导入使用的模块---------------
import cv2
import matplotlib.pyplot as plt
#-----------读取原始图像---------------
img = cv2.imread('image\\equ.bmp',cv2.IMREAD_GRAYSCALE)
#-----------直方图均衡化处理---------------
equ = cv2.equalizeHist(img)
#-----------显示均衡化前后的图像---------------
cv2.imshow("original",img)
cv2.imshow("result",equ)
#-----------显示均衡化前后的直方图---------------
plt.figure("原始图像直方图") #构建窗口
plt.hist(img.ravel(),256)
plt.figure("均衡化结果直方图") #构建新窗口
plt.hist(equ.ravel(),256)
#----------等待释放窗口---------------------
cv2.waitKey()
cv2.destroyAllWindows()

在这里插入图片描述

直方图均衡化使图像色彩更均衡、外观更清晰,也使图像更便于处理,它被广泛地应用在医学图像处理、车牌识别、人脸识别等领域。

4. pyplot 模块介绍

matplotlib.pyplot模块提供了一个类似于MATLAB绘图方式的框架,可以使用其中的函数方便地绘制图形。

4.1 subplot函数

模块 matplotlib.pyplot 提供了函数matplotlib.pyplot.subplot()用来向当前窗口内添加一个子窗口对象。该函数的语法格式为:

matplotlib.pyplot.subplot(nrows, ncols, index)

  • nrows 为行数。
  • ncols 为列数。
  • index 为窗口序号。

例如,subplot(2, 3, 4)表示在当前的两行三列的窗口的第4 个位置上,添加1 个子窗口:

在这里插入图片描述

需要注意的是,窗口是按照行方向排序的,而且序号是从“1”开始而不是从“0”开始的。如果所有参数都小于10,可以省略彼此之间的逗号,直接写三个数字。例如,上述subplot(2, 3, 4)可以直接表示为subplot(234)。

4.2 imshow函数

模块matplotlib.pyplot 提供了函数matplotlib.pyplot.imshow()用来显示图像。其语法格式为:
matplotlib.pyplot.imshow(X, cmap=None)

X 为图像信息,可以是各种形式的数值。
cmap 表示色彩空间。该值是可选项,默认值为null,默认使用RGB(A)色彩空间。
#使用函数matplotlib.pyplot.imshow()显示彩色图像。
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('image\\girl.bmp')
imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
plt.figure("显示结果")
plt.subplot(121)
plt.imshow(img),plt.axis('off')
plt.subplot(122)
plt.imshow(imgRGB),plt.axis('off')
在这里插入图片描述

左图是直接使用默认色彩空间参数模式显示的彩色图像的结果,图像没有正常显示出来。这是因为通过函数cv2.imread()读取的图像,其通道顺序是BGR模式的。而函数matplotlib.pyplot.imshow()的显示顺序是RGB模式的,所以显示出来的图像通道顺序是错乱的,因而无法正常显示。
#使用函数matplotlib.pyplot.imshow()显示灰度图像。
import cv2
import matplotlib.pyplot as plt
o = cv2.imread('image\\girl.bmp')
g=cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
plt.figure("灰度图像显示演示")
plt.subplot(221)
plt.imshow(o),plt.axis('off')
plt.subplot(222)
plt.imshow(o,cmap=plt.cm.gray),plt.axis('off')
plt.subplot(223)
plt.imshow(g),plt.axis('off')
plt.subplot(224)
plt.imshow(g,cmap=plt.cm.gray),plt.axis('off')

在这里插入图片描述

只有使用灰度图像作为参数, 并且将色彩空间参数值设置为“cmap=plt.cm.gray”,灰度图像才被正常显示。

#使用函数matplotlib.pyplot.imshow()以不同的参数形式显示灰度图像。
import cv2
import matplotlib.pyplot as plt
o = cv2.imread('image\\8.bmp')
g=cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
plt.figure("灰度图像显示演示")
plt.subplot(221); plt.imshow(g, cmap=plt.cm.gray)
plt.subplot(222); plt.imshow(g, cmap=plt.cm.gray_r)
plt.subplot(223); plt.imshow(g, cmap='gray')
plt.subplot(224); plt.imshow(g, cmap='gray_r')

上述代码中,色彩空间参数cmap 的参数值“plt.cm.gray_r”及“gray_r”中的“r”是英文“reverse”的缩写,表示逆转的意思。

在这里插入图片描述