PythonOpenCV-直方图-直方图
0. 简介
直方图是一种重要的图像分析工具,它用于描述图像内部的灰度级信息,可直观地反映图像的对比度、亮度、强度分布等特征。
1. 直方图基础
从统计学的角度来看,直方图用于统计图像内各个灰度级出现的次数。
直方图的横坐标表示图像像素的灰度级,纵坐标表示像素灰度级的数量。
在使用 OpenCV 处理直方图时,应注意下列 3个概念:
- RANGE:要统计的灰度级范围。直方图中像素的灰度级范围一般为[0, 255],0 表示黑色,255 表示白色
- BINS: 灰度级的分组数量。在处理直方图时,将灰度级按一定范围进行划分得到的子集数量为 BINS。例如,灰度图像的灰度级范围为[0, 255],按 16 个灰度级分为一组,可分成 16个子集,则 BINS 为 16
- DIMS:绘制直方图时采集的参数数量。一般的直方图只采集灰度级,所以 DIMS 为1
1-1. 用 hist()函数绘制直方图
matplotlib.pyplot.hist()函数可根据图像绘制直方图,其基本格式如下:
matplotlib.pyplot.hist(src, bins)
参数说明:
src:用于绘制直方图的图像数据,必须是一维数组。通常,OpenCV 中的 BGR 图像是三维数组,可用 ravel()函数将其转换为一维数组。
bins:灰度级分组数量
代码示例:
import cv2 as cv import matplotlib.pyplot as plt img_src = cv.imread('../Image/gate.jpg') cv.imshow('src', img_src) plt.hist(img_src.ravel(), 256) plt.show() cv.waitKey(0)
运行结果:
1-2. 用calcHist()函数查找直方图
可直接调用OpenCV的cv2.calcHist()函数查找直方图,再利用matplotlib.pyplot的 plot()函数绘制直方图。
cv2.calcHist()函数的基本格式如下:
hist = cv2.calcHist(image, channels, mask, histSize, ranges)
参数说明:
hist:返回的直方图,是一个一维数组,其大小为 256,保存了原图像中各个灰度级的数量
image:原图像,实际参数需用方括号括起来
channels:通道编号。灰度图像的通道编号为[0],BGR 图像的通道编号为[0][1][2]
mask:掩模图像,为 None 时统计整个图像,否则统计部分图像
histSize: BINS 的值,实际参数需用方括号括起来,如[256]
ranges:像素值范围,8 位灰度图像为[0, 255]
代码示例:
import cv2 as cv import matplotlib.pyplot as plt img_src = cv.imread('../Image/gate.jpg') cv.imshow('src', img_src) hist_b = cv.calcHist([img_src], [0], None, [256], [0, 255]) # 计算B通道的直方图 hist_g = cv.calcHist([img_src], [1], None, [256], [0, 255]) hist_r = cv.calcHist([img_src], [2], None, [256], [0, 255]) plt.plot(hist_b, color='b') # 绘制B通道的直方图 plt.plot(hist_g, color='g') plt.plot(hist_r, color='r') plt.show() cv.waitKey(0)
运行结果:
1-3. 应用掩模的直方图
cv2.calcHist()函数的 mask 参数用于指定掩模图像。
掩模图像为黑底,其中的白色区域可视为透明区域,将其覆盖到原图像上,原图像中可显示出来的部分为掩模结果图像。
指定掩模图像时,calcHist()函数只计算掩模结果图像的直方图。
代码示例:
import cv2 as cv import numpy as np import matplotlib.pyplot as plt img_src = cv.imread('../Image/gate.jpg') cv.imshow('src', img_src) w, h, d = img_src.shape mask = np.zeros((w, h), np.uint8) w1 = np.intp(w/4) w2 = np.intp(w*0.75) h1 = np.intp(h/4) h2 = np.intp(h*0.75) mask[w1: w2, h1: h2] = 255 # 设置掩模白色区域 hist_b = cv.calcHist([img_src], [0], mask, [256], [0, 255]) # 计算B通道的直方图 hist_g = cv.calcHist([img_src], [1], mask, [256], [0, 255]) hist_r = cv.calcHist([img_src], [2], mask, [256], [0, 255]) plt.plot(hist_b, color='b') # 绘制B通道的直方图 plt.plot(hist_g, color='g') plt.plot(hist_r, color='r') plt.show() cv.waitKey(0)
运行结果:
1-4. NumPy中的直方图
NumPy的 histogram()函数可用于计算直方图,其基本格式如下:
hist, bin_edges = np.histogram(src, bins, range)
参数说明:
hist:返回的直方图
bin_edges:返回的灰度级分组数量边界值
src:原图转换成的一维数组
bins:灰度级分组数量
range:像素值范围
代码示例:
import cv2 as cv import numpy as np import matplotlib.pyplot as plt img_src = cv.imread('../Image/gate.jpg') cv.imshow('src', img_src) hist_b, e1 = np.histogram(img_src[0].ravel(), 256, [0, 256]) # 计算B通道的直方图 hist_g, e2 = np.histogram(img_src[1].ravel(), 256, [0, 256]) hist_r, e3 = np.histogram(img_src[2].ravel(), 256, [0, 256]) plt.plot(hist_b, color='b') # 绘制B通道的直方图 plt.plot(hist_g, color='g') plt.plot(hist_r, color='r') plt.show() cv.waitKey(0)
运行结果:
2. 直方图均衡化
直方图均衡化通过调整图像的灰度来提高图像的对比度。
2-1. 普通直方图均衡化
普通直方图均衡化主要是指将原图像的灰度级均匀地映射到全部灰度级范围内。
OpenCV 的 cv2.equalizeHist(src)函数用于实现普通直方图均衡化,其基本格式如下:
dst = cv2.equalizeHist(src)
参数说明:
dst:直方图均衡化后的图像
src:原图像,必须是 8 位的单通道图像
代码示例:
import cv2 as cv import matplotlib.pyplot as plt img_src = cv.imread('../Image/gate.jpg', 0) cv.imshow('src', img_src) plt.figure('original hist') plt.hist(img_src.ravel(), 256) equalize_hist = cv.equalizeHist(img_src) cv.imshow('equalizeHist', equalize_hist) plt.figure('equalize hist') plt.hist(equalize_hist.ravel(), 256) plt.show() cv.waitKey(0)
运行结果:
2-2. 限制对比度自适应直方图均衡化
普通直方图均衡化用于对图像全局进行调整,不能有效提高图像的局部对比度
为了提高图像的局部对比度,可将图像分成若干子块,对子块进行直方图均衡化,这就是自适应直方图均衡化
自适应直方图均衡化可能会造成图像的局部对比度过高,从而导致图像失真
为了解决此问题,可对局部对比度进行限制,这就是限制对比度自适应直方图均衡化
OpenCV的 cv2.createCLAHE()函数用于创建CLAHE 对象,其基本格式如下:
retval = cv2.createCLAHE([clipLimit[, tileGridSize]])
参数说明:
retval:返回的CLAHE 对象
clipLimit:对比度受限的闻值,默认值为 40.0
tileGridSize:直方图均衡化的网格大小,默认值为(8,8)
调用CLAHE对象的apply()方法,将其应用到图像中进行均衡化
代码示例:
import cv2 as cv import matplotlib.pyplot as plt img_src = cv.imread('../Image/gate.jpg', 0) # 单通道 cv.imshow('src', img_src) equalize_hist = cv.equalizeHist(img_src) # 均衡化 cv.imshow('equalizeHist', equalize_hist) clahe = cv.createCLAHE(clipLimit=5) # 创建CLAHE对象 clahe_hist = clahe.apply(img_src) # 应用CLAHE对象 cv.imshow('CLAHE', clahe_hist) cv.waitKey(0)
运行结果:
3. 二维直方图
3-1. OpenCV中的二维直方图
OpenCV 仍使用 cv2.calcHist()函数来查找颜色直方图,只是在指定参数时与之前讲解的有所区别。
参数说明:
image:参数指定的原图应从BGR色彩空间转换为 HSV色彩空间,实际参数需用方括号括起来
channels:参数设置为[0,1]时,表示同时处理色相和饱和度
histSize:参数设置 BINS 值为[180,256]时,表示色相为 180,饱和度为 256
ranges:参数设置为[0,180,0,256]时,表示色相值的取值范围为[0,180],饱和度的取值范围为[0,256]
cv2.calcHist()函数返回的颜色直方图可直接使用 cv2.imshow()函数显示
代码示例:
import cv2 as cv img_src = cv.imread('../Image/gate.jpg') # 单通道 cv.imshow('src', img_src) img_HSV = cv.cvtColor(img_src, cv.COLOR_BGR2HSV) # 转换色彩空间 hist = cv.calcHist([img_HSV], [0, 1], None, [100, 256], [0, 100, 0, 256]) # 计算颜色直方图 cv.imshow('2Dhist', hist) cv.waitKey(0)
运行结果:
cv2.calcHist()函数返回的颜色直方图是一个大小为 180x 256 的二维数组,用 cv2.imshow()函数显示时是一幅灰度图像,不能直接显示出颜色的分布情况。
可以使用 matplotlib.pyplot.imshow()函数绘制具有不同颜色的二维直方图,示例代码如下:
import cv2 as cv import matplotlib.pyplot as plt img_src = cv.imread('../Image/gate.jpg') # 单通道 cv.imshow('src', img_src) img_HSV = cv.cvtColor(img_src, cv.COLOR_BGR2HSV) # 转换色彩空间 hist = cv.calcHist([img_HSV], [0, 1], None, [100, 256], [0, 100, 0, 256]) # 计算颜色直方图 plt.imshow(hist, interpolation='nearest') # 绘制彩色直方图 plt.show() cv.waitKey(0)
运行结果:
3-2. NumPy中的二维直方图
NumPy的 histogram2D()函数用于计算二维直方图,其基本格式如下:
hist, xedges, yedges=np.histogram2D(x, y, bins, range)
参数说明:
hist:返回的直方图
xeopes:返国的x的直方图的BINS边界值
yedges:返回的y的直方图的BINS边界值
x和y:原图对应通道转换成的一维数组
bins:BNS的值,如[180,256]
range:像素值范里,格式为“[[0,180], [0,256]]”
代码示例:
import cv2 as cv import numpy as np import matplotlib.pyplot as plt img_src = cv.imread('../Image/gate.jpg') # 单通道 cv.imshow('src', img_src) img_HSV = cv.cvtColor(img_src, cv.COLOR_BGR2HSV) # 转换色彩空间 h, s, v = cv.split(img_HSV) hist, x, y = np.histogram2d(h.ravel(), s.ravel(), [180, 256], [[0, 180], [0, 256]]) # 计算颜色直方图 cv.imshow('2Dhist', hist) plt.imshow(hist, interpolation='nearest') # 绘制彩色直方图 plt.show() cv.waitKey(0)
运行结果:
/*-------------------------------------------------------------------------------------------------------
笔者说明:
该笔记来源于本人学习Python + OpenCv时的资料,
分享出来只是为了供大家学习,并且为了自己以后想要用的时候方便寻找。
时间:2023年8月23日
------------------------------------------------------------------------------------------------------------*/