十三、直方图处理
直方图从图像内部灰度级的角度对图像进行表述,包含十分丰富而重要的信息。
13.1 直方图含义
直方图是图像内灰度值的统计特性与图像灰度值之间的函数,直方图统计图像内各个灰度级出现的次数。从直方图的图形上观察,横坐标是图像中各像素点的灰度级,纵坐标是具有该灰度级(像素值)的像素个数。
下图为直方图:
归一化直方图,x轴仍为灰度级别,y轴则为灰度级出现的频率
下图为归一化直方图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lqOpa6JZ-1659623450452)(D:\python\opencv学习笔记\opencv3 笔记\笔记图片\十三章\归一化直方图.png)]
DIMS:表示在绘制直方图时,收集的参数的数量。一般情况下,直方图中收集的数据只有一种,就是灰度级。因此,该值为1。
RANGE:表示要统计的灰度级范围,一般为[0,255]。0对应的是黑色,255对应的是白色。
BINS:参数子集的数目。在处理数据的过程中,有时需要将众多的数据划分为若干个组,再进行分析。
13.2 绘制直方图
13.2.1 Numpy绘制直方图
根据数据源喝灰度级分组绘制直方图
matplotlib.pyplot.hist (X,BINS)
X:数据源。要使用ravel ()函数将图像处理为一维数据源之后才可以使用
BINS: 灰度级的分组情况
13.2.2 OpenCV绘制直方图
cv2.calcHist()用来计算图像的统计直方图,该函数能统计各个灰度级的像素点个数。利用plot ()函数,可以将函数cv2.calcHist()的统计结果绘制成直方图。
(1)cv2.calcHist()函数统计图像直方图信息
hist=cv2.calcHist (images,channels,mask,histSize,ranges,accumulate)
hist: 返回的统计直方图,一维数组,数组元素为各灰度级像素点的个数
images: 原始图像,要用[]括起来
channels: 指定通道编号,要用[]括起来
mask: 掩模图像
histSize: BINS的值,要用[]括起来
ranges: 像素值范围
accumulate: 累计标识,默认为False,当为True时,直方图在计算时不会被清零
(2)plot()函数的使用
plot()函数将cv2.calcHist()的返回值绘制成图像直方图
示例:绘制彩色图像三个通道的直方图
import cv2
import matplotlib.pyplot as plt
o=cv2.imread ("bgra.png")
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 ()
结果:
13.2.3 掩模绘制直方图
使用掩模绘制直方图时,仅获取掩模参数mask指定区域的直方图
掩模处理:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-smV4XrLs-1659623450453)(D:\python\opencv学习笔记\opencv3 笔记\笔记图片\十三章\掩模处理.png)]
(1)构造掩模图像
先构造一个像素值都是0的二维数组,再将数组中指定区域的像素值设定为255,就得到了掩模图像。
mask=np.zeros ([600,600],np.uint8)
mask[200:400,200:400]=255
示例:绘制掩模图像直方图,蓝色为正常图像直方图,黄色为掩模结果图像直方图
import cv2
import numpy as np
import matplotlib.pyplot as plt
image=cv2.imread ( "boat.png",cv2.IMREAD_GRAYSCALE)
mask=np.zeros (image.shape,np.uint8)
mask[200:400,200:400]=255 #绘制掩模图像
histlmage=cv2.calcHist ([image],[0],None,[256],[0,255]) #正常图像的直方图
histMl=cv2.calcHist ([image],[0],mask,[256],[0,255]) #掩模图像的直方图
plt.plot (histlmage)
plt.plot (histMl)
plt.show()
结果:
13.3 直方图均衡化
如果一幅图像拥有全部可能的灰度级,并且像素值的灰度均匀分布,那么这幅图像就具有高对比度和多变的灰度色调,灰度级丰富且覆盖范围较大。在外观上,这样的图像具有更丰富的色彩,不会过暗或过亮。
直方图均衡化的主要目的是将原始图像的灰度级均匀地映射到整个灰度级范围内,得到一个灰度级分布均匀的图像。
13.3.1 直方图均衡化原理
(1)计算累计直方图
(2)对累计直方图进行区间转换
例如:图像的统计直方图
灰度级 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
像素个数 | 9 | 9 | 6 | 5 | 6 | 3 | 3 | 8 |
归一化累计统计直方图为:
灰度级 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
累计概率 | 0.18 | 0.37 | 0.49 | 0.59 | 0.71 | 0.78 | 0.84 | 1.00 |
1.在原有范围内实现均衡化
用当前灰度级的累计概率乘以当前灰度级的最大值7,得到新的灰度级,并作为均衡化的结果。
灰度级 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
累计概率 | 0.18 | 0.37 | 0.49 | 0.59 | 0.71 | 0.78 | 0.84 | 1.00 |
均衡化值(新的灰度值) | 1 | 3 | 3 | 4 | 5 | 5 | 6 | 7 |
所以,由此可得,原来的0灰度级对应现在的1灰度级,原来的1和2灰度级对应现在的3灰度级,以此类推。
均衡化后对应灰度级的像素个数:
均衡化后的灰度级 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
0 | 9 | 0 | 15 | 5 | 9 | 3 | 8 |
左图诶均衡化前的图,右图为均衡化后的直方图
2.在更广泛的范围内实现均衡化
用当前灰度级的累计概率乘以更广泛范围灰度级(255)的最大值,得到新的灰度级,并作为均衡化的结果。
灰度级 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
累计概率 | 0.18 | 0.37 | 0.49 | 0.59 | 0.71 | 0.78 | 0.84 | 1.00 |
均衡化值 | 47 | 94 | 125 | 151 | 182 | 198 | 213 | 255 |
均衡化后灰度级在[0,255]内保持均匀
总结:一种是累计概率乘以当前最大灰度级,另一种是乘以更广泛的灰度级最大值
13.3.2 直方图均衡化处理
dst=cv2.equalizeHist (src)
src: 8位单通道原始图像
dst: 直方图均衡化处理的结果
示例:实现直方图的均衡化
#-----------导入使用的模块-
import cv2
import matplotlib.pyplot as plt
#---读取原始图像---
img=cv2.imread ('linghtlena.png',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)
plt.show()
#--等待释放窗口--
cv2.waitKey ()
cv2.destroyAllWindows ()
结果:
lena图像对比: (左边是原来,右边是均衡化后的)
直方图对比: (左边是原来,右边是均衡化后的)
13.4 pyplot模块介绍
13.4.1 subplot函数
用来在当前窗口添加子窗口
matplotlib.pyplot.subplot (nrows,ncols,index)
nrows: 行数
ncols: 列数
index: 窗口序号
当参数都小于10的时候,可以省略逗号,用subplot(234)表示
示例:
import cv2
import matplotlib.pyplot as plt
img=cv2.imread ('lena.png',cv2.IMREAD_GRAYSCALE)
equ=cv2.equalizeHist (img)
plt.figure ( "subplot示例")
plt.subplot (121) ,plt.hist (img.ravel () ,256) #一行两列的窗口,第一个
plt.subplot (122) ,plt.hist (equ.ravel () ,256) #一行两列的窗口,第二个
plt.show()
结果:
13.4.2 imshow函数
显示图像
matplotlib.pyplot.imshow (x,cmap=None)
x: 图像信息
cmap: 色彩空间,默认值为null
示例:
imshow显示的顺序是RGB模式,所以img图像是BGR模式会导致显示错误,只有吧BGR模式转为RGB模式才可以正常显示,如imgRGB。
import cv2
import matplotlib.pyplot as plt
img=cv2.imread ('bgra.png') #imread读取的图像是BGR模式
imgRGB=cv2.cvtColor (img,cv2.COLOR_BGR2RGB)
plt.figure("显示结果")
plt.subplot (121)
plt.imshow (img),plt.axis ('off') #在窗口1显示img图像
plt.subplot (122)
plt.imshow (imgRGB),plt.axis ('off') #在子窗口显示imgRGB图像
plt.show()
结果:
示例:修改参数cmap
import cv2
import matplotlib.pyplot as plt
o=cv2.imread ( 'bgra.png')
g=cv2.cvtColor (o,cv2.COLOR_BGR2GRAY)
plt.figure ("灰度图像显示演示")
plt.subplot (221)
plt.imshow (o),plt.axis ('off') #BGR彩色图像,默认参数RGB
plt.subplot (222)
plt.imshow (o,cmap=plt.cm.gray) ,plt.axis ('off') #BGR彩色图像,参数灰度
plt.subplot (223)
plt.imshow (g) ,plt.axis ( 'off') #灰度图像,参数默认
plt.subplot (224)
plt.imshow (g,cmap=plt.cm.gray) ,plt.axis ( 'off') #灰度图像,灰度参数
plt.show()
结果:
只有最后一个图像是正确显示的,其他都显示不正确。