计算机视觉(opencv)实战十六——图像像素直方图 与 掩膜
图像直方图与掩膜的应用
一、直方图的基本概念
直方图(Histogram)是图像处理中常用的一种工具,用于统计和展示图像中 像素值的分布情况。
以灰度图为例,像素值范围为 0(黑色)到 255(白色),直方图的横坐标表示像素值,纵坐标表示该像素值出现的次数。
在 OpenCV 中,计算直方图的常用函数是:
cv2.calcHist(images, channels, mask, histSize, ranges)
参数说明:
images:输入图像,需要用中括号括起来,例如
[img]
。支持uint8
或float32
格式。channels:通道索引。灰度图为
[0]
;彩色图像可以是[0]
(蓝)、[1]
(绿)、[2]
(红)。mask:掩膜图像。如果为
None
,统计整张图像的直方图;如果传入掩膜,就只统计掩膜区域内的像素。histSize:直方图的柱数(即 BIN 数)。例如
[256]
表示把像素值分成 256 个区间;[16]
表示分成 16 个区间。ranges:像素取值范围,常用
[0, 256]
。
直方图可以帮助我们快速了解图像的整体亮度、对比度、以及色彩分布,是图像增强和分割的重要工具。
# cv2.calcHist(images,channels,mask,histSize,ranges) 计算图像的直方图,用于表示图像中像素灰度级的分布情况。 # images: 原图像图像格式为 uint8 或 float32。当传入函数时应 用中括号 [] 括来例如[img] # channels: 表示传入的图像通道数。如果输入图像是灰度图它的值就是 [0]。 # 如果是彩色图像 的传入的参数可以是 [0][1][2] 它们分别对应着 BGR。 # mask: 掩模图像。统计整副图像的直方图就把它为None。但是如果你想统计图像某一部分的直方图,你就制作一个掩模图像并使用它。 # histSize:BINS 的数目。也需用中括号括来 (分成多少个区间) # BINS :上面的直方图显示了每个像素值的像素数,即从0到255。即您需要256个值才能显示上述直方图。 # 但是请考虑一下,如果您不需要单独查找所有像素值的像素数,而是在像素值间隔内查找像素数, # 该怎么办?例如,您需要找到介于 0 到 15 之间的像素数,然后是 16 到 31、32到47、...、240 到 255。 # 您只需要 16 个值来表示直方图。 # 因此,只需将整个直方图拆分为 16 个子部分,每个子部分的值就是其中所有像素计数的总和。 # 这每个子部分都称为"BIN"。在第一种情况下,条目数为256(每个像素一个),而在第二种情况下,它只有16。BINS 在 OpenCV 文档中由术语histSize表示。 # ranges: 像素值范围常为 [0 256]
二、使用 NumPy 和 Matplotlib 绘制直方图
下面的例子展示了如何用 NumPy 的 ravel()
将图像拉平成一维数组,并用 Matplotlib 绘制直方图:
import cv2
from matplotlib import pyplot as pltphone = cv2.imread('phone.png', cv2.IMREAD_GRAYSCALE)
a = phone.ravel()
plt.hist(a, bins=256)
plt.show()
ravel()
:将多维数组展平成一维数组。plt.hist()
:统计像素分布并绘制直方图。
结果是一幅灰度直方图,能直观反映出整幅图的灰度分布。
三、使用 OpenCV 计算直方图
相比 plt.hist
,OpenCV 的 cv2.calcHist
提供了更灵活的统计方法:
phone_hist = cv2.calcHist([phone], [0], None, [256], [0,256])
plt.plot(phone_hist)
plt.show()
这里没有使用掩膜(mask=None
),所以直方图统计了整张图像的像素。
在彩色图像中,可以分别计算三个通道的直方图:
img = cv2.imread('face.jpg')
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.show()
这样绘制出的三条曲线分别表示蓝色、绿色和红色通道的像素分布。
四、掩膜(Mask)的概念与使用
在很多应用中,我们并不需要统计整幅图像的直方图,而是只关心某一部分区域。这时候就需要用到 掩膜(Mask)。
掩膜是一幅 黑白图像(单通道,数值为 0 或 255):
白色(255)区域表示要保留的部分。
黑色(0)区域表示忽略的部分。
例如:
import cv2
import numpy as np
from matplotlib import pyplot as pltphone = cv2.imread('phone.png',cv2.IMREAD_GRAYSCALE)
cv2.imshow('phone',phone)
cv2.waitKey(0)
mask = np.zeros(phone.shape[:2],np.uint8)
mask[50:350,100:470] = 255
cv2.imshow('mask',mask)
cv2.waitKey(0)
这段代码生成了一张与原图大小相同的全黑图像,并在指定区域填充为白色,作为掩膜。
我们可以用 cv2.bitwise_and()
将掩膜应用到原图上,直观地看到选中的区域:
Phone_mask = cv2.bitwise_and(phone, phone, mask=mask)
cv2.imshow('phone_mask', Phone_mask)
cv2.waitKey(0)
五、带掩膜的直方图
在 cv2.calcHist
中传入掩膜参数,就能只统计掩膜范围内的像素分布:
phone_hist_mask = cv2.calcHist([phone], [0], mask, [256], [0,256])
plt.plot(phone_hist_mask)
plt.show()
这样绘制的直方图只反映掩膜区域的像素特征,而忽略其他部分。
六、应用场景
图像增强:通过观察直方图分布,可以决定是否进行直方图均衡化来增强对比度。
目标检测:使用掩膜提取特定区域的颜色直方图,作为目标特征进行匹配。
图像分割:根据局部直方图判断区域的灰度或颜色特性,从而分割目标。
七、总结
直方图:反映图像像素值的分布情况,是图像分析的基本工具。
掩膜:用于限定直方图统计的区域,让我们能专注于关心的部分。
OpenCV 与 Matplotlib 提供了灵活的直方图绘制方式,既能全局统计,也能局部分析。
掌握直方图与掩膜,不仅能帮助理解图像的亮度和对比度,还能为后续的图像处理、特征提取和机器视觉任务打下基础。