OpenCV实战:直方图、掩膜与均衡化详解
本文深入解析OpenCV中图像直方图的计算原理,详细演示cv2.calcHist函数的参数用法。通过掩膜(mask)技术实现局部图像统计,并对比全局直方图均衡化与自适应均衡化(CLAHE)的效果,解决局部过曝或细节丢失问题,提供完整的Python代码示例。
一、图像直方图
1.1 定义
图像直方图是描述图像像素分布的重要统计特征,属于图像的基本属性之一。其横坐标表示像素值在[0,255]区间内的分布,纵坐标则表示对应像素值的出现次数或所占百分比。具体表现如图:


1.2 函数:cv2.calcHist([img1],[channels],mask,histSize,ranges)
img:表示输入的原始图像。
channels:指定统计的通道。若输入为灰度图,参数设为[0];若为彩色图,则分别传入[0]、[1]或[2]以对应B、G、R通道。
mask:用于指定统计区域。若需统计整幅图像的直方图,该参数设为None;若仅统计特定区域,则需构建一个与img尺寸相同的掩模图像(np数组),目标区域设为255,非目标区域设为0。
histSize:定义直方图的bin数量,通常设为[256],对应像素值范围[0,255]。
ranges:指定像素值的统计范围,通常为[0, 256],注意该范围遵循“顾头不顾尾”的原则。
1.3 代码实现:
(1)准备工作加灰度图显示:
import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
#显示图像
def cv_show(name,img):
cv2.imshow(name,img)
cv2.cv2.waitKey(0)
cv2.destroyAllWindows()
#导入图像
img1=cv2.imread("C:/Users/bwy/Desktop/lena.bmp",0)
hist=cv2.calcHist([img1],[0],None,[256],[0,256])
print(hist.shape)
plt.hist(img.ravel(),256)
plt.show()结果如图(灰度图):

(2)彩色图三个不同的通道:
img=cv2.imread("C:/Users/bwy/Desktop/7.png")
cv_show('img',img)
color=('b','g','r')
for i,col in enumerate(color):
histr=cv2.calcHist([img],[i],None,[256],[0,256])
plt.plot(histr,color=col)
plt.xlim([0,256])结果如图:

观察上述两个结果图可知,直方图分布往往极不均匀,并非理想的“矮胖”形态。因此,接下来我们将引入图像直方图均衡化技术。在此之前,先学习掩膜(mask)的相关操作。
二、掩膜(mask)
2.1掩模mask思想:
掩模的尺寸需与原图像保持一致。掩模仅包含0和255两种值:掩模中白色(255)覆盖的区域保留原图数据,黑色(0)覆盖的区域则置为0。若处理彩色图像,构建np数组时需忽略第三个维度(通道),仅保留前两个维度img.shape[:2],确保掩模尺寸与原图一致。由于mask本质为数组,可利用切片操作将需要保留的区域赋值为255(白色)。
2.2代码:
img.shape[:2]#(420, 607)
#创建mast
mask=np.zeros(img.shape[:2],np.uint8)
mask[100:300,200:400]=255
cv_show('mask',mask)结果如图:

masked_img=cv2.bitwise_and(img1,img1,mask=mask)
cv_show('masked_img',masked_img)结果如图:

2.3掩膜过程对比
plt.subplot(221),plt.imshow(img1)
plt.subplot(222),plt.imshow(mask)
plt.subplot(223),plt.imshow(masked_img)
plt.subplot(224),plt.plot(hist_full),plt.plot(hist_mask)
plt.xlim([0,256])
plt.show()结果如图:

三、直方图均衡化
直方图均衡化通过调整图像各像素的灰度值来改变直方图分布,旨在增强局部对比度,同时保持整体对比度不变。该方法特别适用于背景与前景均过亮或过暗的图像。
3.1对图像整体进行均衡化:
(1)进行均衡化后直方图前后对比显示:
img=cv2.imread("C:/Users/bwy/Desktop/lena.bmp",0)
plt.hist(img.ravel(),256)
plt.show()
equ=cv2.equalizeHist(img)
plt.hist(equ.ravel(),256)
plt.show()结果对比图:


(2)进行均衡化后图像前后对比显示:
img=cv2.imread("C:/Users/bwy/Desktop/lena.bmp",0)
equ=cv2.equalizeHist(img)
res=np.hstack((img,equ))
cv_show('res',res)然而,该方法存在一定局限性。以下图为例,你会发现:

图中人物面部过亮,导致细节丢失,无法观察清晰。针对这一问题,我们该如何解决?
3.2 自适应均衡化
1、定义:
自适应均衡化将整幅图像分割为多个小块,并对每个小块分别执行直方图均衡化。其缺点在于可能放大噪声。为避免此问题,需引入对比度限制(Contrast Limited)。
2、代码:
img2=cv2.imread("C:/Users/bwy/Desktop/1.png",0)
img2.shape#(508, 672)
img3=cv2.resize(img2,(400,300))
equ1=cv2.equalizeHist(img3)
clahe=cv2.createCLAHE(clipLimit=2.0,tileGridSize=(8,8))
res_clahe=clahe.apply(img3)
res=np.hstack((img3,equ1,res_clahe))
cv_show('res',res)结果如图:

以上即为OpenCV中直方图、掩膜及直方图均衡化的详细实现内容。如需了解更多OpenCV相关技巧,请参阅本站其他文章。
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













