接上篇OpenCV Python 直方图的使用。在opencv中使用掩模对图像进行处理是一个十分常用的方法。本篇是记录掩模操作的原理及使用。小白入门,如有不正确的地方希望大佬指正。
提示:需要引入numpy
个人理解,掩模就是一层玻璃板,你可以指定哪一部分是透明的,哪一部分是不透明的,然后将掩模罩在需要处理的图片上。上图就很容易理解了:
左边的是原图,中间的就是掩模,而右边的则是将原图与掩模经行按位与操作之后的得到的图像。
在掩模运算中使用了“与”和“或”运算,利用电路图就可以很好的理解。
与运算和串联电路是相对应的。如上图左侧串联电路,只有当两个开关都是闭合时,电路才是接通的,对应到数值运算上,只有参与运算的数值都为1时,与运算结果才是1。
或运算和并联电路相对应,任意一个开关闭合,电路都是接通的,对应到数值运算上,参与或运算的数值只要有一个值是1,或运算的结果就是1。
掩模操作主要用到的是按位“与运算”。其语法格式为dst = cv2.bitwise_and(src1,src2[,mask]])
在进行按位与运算时,需要先将参与运算的值转换为二进制数,然后将对应位上的值经行与运算。
按位与操作有以下特点:
1、将任何数值N与数值0经行按位与操作,都将会得到数值0。
2、将任何数值N(这里仅考虑8位值)与数值255(8位二进制数是1111 1111)进行按位与操作,都会得到数值N本身。
举个易于理解的小栗子:
上述运算是直接对两个数值进行运算的,理解起来比较方便。在实际处理中,要先将像素点处理成二进制,在进行按位与操作。 并且通常将掩模图像白色区域设置为255。(下面细说)
按位与运算深度剖析:
如上例,将像素值35和像素值126分别转成二进制后经行按位与操作。当二者都为”1“时,结果才为真,否者为假,即”0“。
根据与运算的法则,任意一个数值与数值1进行与运算,结果等于其自身的值。因此,任意一个8位像素值与二进制数”1111 1111“进行按位与运算,得到的都是自身的值。二进制”1111 1111“对应的十进制数是”255“,所以任意一个8位像素值与”255“进行按位与运算,得到的都是自身原来的值。这就是为什么实际应用中构建掩模用255的原因。
综上,将一幅图片与掩模经行按位与操作之后,得到的图像有以下两部分:
1、与掩模图像中黑色背景位置对应的部分,该部分的像素值被置为0。
2、与掩模图像中白色背景位置对应的部分,该部分像素保留原有值。
理解掩模运算的原理之后,我们来试着构造掩模吧。
在构造掩模图像时,通常先构造一个像素值都是0的二维数组,再将数组中指定区域的像素设定为255,就得到了掩模图像。
举个例子:
import cv2
import numpy as np
mask = np.zeros([300,300],np.uint8) #用numpy生成一个全为0的,300*300的二维数组
mask[50:200,50:200]=255 #将其中的50~200行,50~200列赋值为255
cv2.imshow("mask",mask)
cv2.waitKey()
cv2.destroyAllWindows()
像这样就创建了一个大小为300*300,其中50到200行、50到200列为白色的掩模图像。
注意对两张图像进行按位与操作前提是要两张图像的大小相同,所以对图像进行掩模操作的时候要构造原图大小的二维数组
举个例子:
import cv2
import numpy as np
img = cv2.imread(r"D:\lesson\lena.jpg")
print(img.shape) #打印一下shape值
mask = np.zeros(img.shape,np.uint8) #构建与原图shape值相同的mask
mask[50:200,50:200]=255
img1 = cv2.bitwise_and(img,mask) #将图像与掩模经行按位与操作
cv2.imshow("img",img)
cv2.imshow("mask",mask)
cv2.imshow("img1",img1)
cv2.waitKey()
cv2.destroyAllWindows()