目录
掩膜
OpenCV 中图像掩膜(Mask)实现的原理是通过一个与原始图像大小相同的二进制图像(掩膜图像)来对原始图像进行操作。具体原理如下:
- 掩膜图像:掩膜图像是一个二值图像,其像素值通常只有 0 和 1(或者对应灰度值为 0 和 255)。其中,值为 1(或 255)的像素位置表示感兴趣的区域,而值为 0 的像素位置表示要忽略的区域。
- 操作过程:将原始图像与掩膜图像进行逐像素的逻辑运算(通常是乘法运算)。对于原始图像中的每个像素,如果掩膜图像中对应位置的像素值为 1,则该像素在结果图像中保持原始值;如果掩膜图像中对应位置的像素值为 0,则结果图像中该像素的值被设置为 0(或其他指定的背景值)。通过这种方式,就可以提取出原始图像中与掩膜图像中感兴趣区域相对应的部分,而将其他区域屏蔽掉。
例如,假设有一个彩色图像和一个掩膜图像,掩膜图像中白色区域(值为 1)对应着要保留的图像部分,黑色区域(值为 0)对应着要去除的部分。将彩色图像的每个像素与掩膜图像的对应像素相乘,那么彩色图像中对应掩膜图像白色区域的像素将保持不变,而对应黑色区域的像素将变为黑色(RGB 值为 0,0,0),从而实现了对彩色图像的掩膜操作。
这种掩膜操作在图像处理中有很多应用,如图像分割、目标提取、图像滤波等。通过设计不同的掩膜图像,可以灵活地对图像进行各种处理和分析。
bitwise_and原理
在 OpenCV 里,bitwise_and
是一个极为常用的按位与操作函数。按位与操作指的是对两个输入数组(一般为图像)的对应位进行逻辑与运算,最后得到一个新的数组。
原理
按位与操作是对两个输入数组的每个对应位执行逻辑与运算。逻辑与运算的规则是:仅当两个对应位都为 1 时,结果位才为 1;否则,结果位为 0。以两个 8 位二进制数 01011010
和 11001100
为例,按位与运算的结果是 01001000
。
cv2.bitwise_and():对图像(灰度图像或彩色图像均可)每个像素值进行二进制"与"操作,1&1=1,1&0=0,0&1=0,0&0=0
bitwise_and(src1, src2, dst=None, mask=None)
参数 src1、src2:为输入图像或标量,标src1和src2相与。
dst:可选输出变量,如果需要使用非None则要先定义,且其大小与输入变量相同
mask:图像掩膜,可选参数,用于指定要更改的输出图像数组的元素,mask为0的值,src1和src2相与的值都为0, 非0的值,为src1和src2相与的值,可选的操作掩码,是一个 8 位单通道数组,用于指定哪些像素需要进行操作。。
掩膜的实现
1、基于像素操作
遍历原始图像和掩膜图像的每个像素,根据掩膜像素的值来决定原始图像对应像素的处理。如果掩膜像素值为 0,则忽略原始图像对应像素;如果为 1,则保留或对其进行相应处理。
import cv2
# 读取原始图像和掩膜图像
# 假设原始图像是彩色图像,以默认的彩色模式读取
img = cv2.imread('original_image.jpg')
# 掩膜图像通常以灰度模式读取,因为其像素值主要用于表示0(不处理)和非0(处理)的逻辑
mask = cv2.imread('mask.jpg', 0)
# 进行掩膜操作,使用cv2.bitwise_and函数,它会对原始图像和自身进行按位与操作,
# 并根据掩膜来决定哪些像素参与运算。当掩膜像素为0时,结果图像对应像素为0;当掩膜像素为非0时,
# 结果图像对应像素取原始图像的像素值
result = cv2.bitwise_and(img, img, mask=mask)
# 显示结果图像
cv2.imshow('Result', result)
# 等待用户按键
cv2.waitKey(0)
# 关闭所有打开的窗口
cv2.destroyAllWindows()
在上述代码中,首先使用cv2.imread
函数分别读取原始图像和掩膜图像。然后通过cv2.bitwise_and
函数实现掩膜操作,最后使用cv2.imshow
等函数进行图像的显示和窗口管理。
2、使用形态学操作
形态学操作是基于形状的图像处理技术,常用于图像的预处理和后处理,也可用于创建和优化掩膜。常见的形态学操作包括腐蚀、膨胀、开运算(先腐蚀后膨胀)、闭运算(先膨胀后腐蚀)等。例如,使用腐蚀操作可以去除掩膜中的一些小噪声点,使用膨胀操作可以扩大掩膜中物体的边界。
import cv2
import numpy as np
# 读取掩膜图像,以灰度模式读取
mask = cv2.imread('mask.jpg', 0)
# 定义一个结构元素(内核),这里使用5x5的矩形内核
kernel = np.ones((5, 5), np.uint8)
# 腐蚀操作,去除掩膜中的小噪声点和边界的毛刺
eroded_mask = cv2.erode(mask, kernel, iterations=1)
# 膨胀操作,可以扩大掩膜中物体的边界,连接一些断开的部分
dilated_mask = cv2.dilate(eroded_mask, kernel, iterations=1)
# 显示原始掩膜、腐蚀后的掩膜和膨胀后的掩膜
cv2.imshow('Original Mask', mask)
cv2.imshow('Eroded Mask', eroded_mask)
cv2.imshow('Dilated Mask', dilated_mask)
cv2.waitKey(0)
cv2.destroyAllWindows()
在上述代码中,首先读取掩膜图像,然后定义了一个结构元素kernel
。接着使用cv2.erode
函数进行腐蚀操作,使用cv2.dilate
函数进行膨胀操作。通过这些操作,可以对掩膜进行优化,使其更符合实际需求。
3、基于阈值处理
基于阈值处理是将灰度图像转换为二值掩膜图像的常用方法。通过设定一个阈值,将图像中像素值大于阈值的设为一个值(通常为 255,表示白色,即处理区域),像素值小于阈值的设为另一个值(通常为 0,表示黑色,即不处理区域)。对于灰度图像,可以通过设定一个阈值将其转换为二值掩膜图像。像素值大于阈值的设为 1,小于阈值的设为 0。
import cv2
# 读取灰度图像,这里假设原始图像已经是灰度图像,如果不是,需要先进行灰度转换
gray_img = cv2.imread('gray_image.jpg', 0)
# 设定阈值,这里使用127作为阈值
threshold_value = 127
# 进行阈值处理,cv2.THRESH_BINARY表示二值化操作,即将大于阈值的像素设为255,小于阈值的像素设为0
ret, binary_mask = cv2.threshold(gray_img, threshold_value, 255, cv2.THRESH_BINARY)
# 显示原始灰度图像和二值化后的掩膜图像
cv2.imshow('Original Gray Image', gray_img)
cv2.imshow('Binary Mask', binary_mask)
cv2.waitKey(0)
cv2.destroyAllWindows()
在上述代码中,首先读取灰度图像,然后设定一个阈值。接着使用cv2.threshold
函数进行阈值处理,得到二值化的掩膜图像。最后通过cv2.imshow
函数显示原始图像和生成的掩膜图像。
案例
1、读取原图并绘制掩膜
phone = cv2.imread('phone.png',cv2.IMREAD_GRAYSCALE)
cv2.imshow('phone',phone)
cv2.waitKey(0)
#获得一个与原图像相同大小的零阵
mask = np.zeros(phone.shape[:2],np.uint8) #创建黑白图像,用于制作mask
#通过ROI截取一个纯白色的窗口
mask[50:350,100:470] = 255
cv2.imshow('mask',mask)
cv2.waitKey(0)

2、掩膜的实现
Phone_mask = cv2.bitwise_and(phone,phone,mask=mask)
cv2.imshow('phone_mask',Phone_mask)
cv2.waitKey(0)

3、绘制掩膜的直方图
phone_hist_mask = cv2.calcHist([phone],[0],mask,[256],[0,256])
plt.plot(phone_hist_mask)#使用calcHist的值绘制曲线图
plt.show()

应用
- 图像分割:可以将图像中的特定区域分离出来。例如,在医学图像中,通过创建一个掩膜来圈定肿瘤区域,从而将肿瘤从周围的正常组织中分割出来,便于后续的分析和诊断。
- 感兴趣区域提取:当我们只对图像中的某个特定部分感兴趣时,使用掩膜可以提取出该区域,而忽略其他部分。比如在一幅风景图像中,我们只希望处理天空部分,就可以创建一个天空区域的掩膜,然后仅对天空部分进行颜色调整、特效添加等操作。
- 图像保护:在对图像进行某些处理(如滤波、增强等)时,使用掩膜可以保护图像中的某些重要区域不被改变。例如,在对一幅有文字的图像进行背景模糊处理时,通过掩膜保护文字区域,使得文字不会被模糊掉。