【1】引言
前序已经对使用cv2.bitwise_and()函数实现图像按位与运算进行了反复探究:
python学opencv|读取图像(四十三)使用cv2.bitwise_and()函数实现图像按位与运算-CSDN博客
python学opencv|读取图像(四十四)原理探究:bitwise_and()函数实现图像按位与运算-CSDN博客
在这两篇文章中,我们不仅获得了按位与计算的图像效果,而且知道了bitwise_and()函数,先对各个像素点的BGR数值进行二进制转化,然后按位进行与运算,最后把与运算结果又转回为十进制数据,由此实现了图像的按位与运算叠加效果。
不过在这两篇文章中,使用的掩模都是图片自带的,cv2.bitwise_and()函数支持在两种图片之外在增加掩模操作,今天我们就继续探索一下在cv2.bitwise_and()函数中添加掩模参数后的图像转化效果。
【2】代码测试
代码测试包括cv2.bitwise_and()函数不带和带掩模矩阵两种方式。
【2.1】无掩模矩阵
首先是引入模块和读取图像:
python
import cv2 as cv # 引入CV模块
import numpy as np #引入numpy模块
# 读取图片-直接转化灰度图
src = cv.imread('srcx.png') #读取图像
dst=src#输出图像
然后定义第二张带掩模的图像:
python
# 定义图像
image = np.zeros(src.shape, np.uint8) # 定义一个竖直和水平像素与初始图像等大的全0矩阵
print('像素大小为',src.shape)
image[100:200, :, :] = 255 # 第一个通道值
image[:,100:350,: ] = 200 # 第二个通道值
image[:, :, 0] = 55 # 第三个通道值
然后进行按位与计算:
python
#按位与运算
img=cv.bitwise_and(src,image) #与运算
之后为了看清楚这种按位与计算,进行了BGR值读取和二进制的按位与计算:
python
#显示BGR值
print("dst像素数为[150,150]位置处的BGR=", dst[150,150]) # 获取像素数为[100,100]位置处的BGR
print("image像素数为[150,150]位置处的BGR=", image[150,150]) # 获取像素数为[100,100]位置处的BGR
print("img像素数为[150,150]位置处的BGR=", img[150,150]) # 获取像素数为[100,100]位置处的BGR
a=np.zeros((1,3),np.uint8) #定义矩阵
a=dst[150,150] #将像素点BGR直接赋值给矩阵
b=np.zeros((1,3),np.uint8) #定义矩阵
b=image[150,150] #将像素点BGR直接赋值给矩阵
c=np.zeros((1,3),np.uint8) #定义矩阵
#二进制按位与计算
for i in range(3): #计数
print('a','[0,',i,']=',a[i],'的二进制转化值=', bin(a[i]), ',b=','[0,',i,']=', b[i],'的二进制转化值=',bin(b[i])) #输出二进制转化值
c[0,i]=np.bitwise_and(a[i],b[i]) #赋值按位与计算值
print('c',[0,i],'=',c[0,i]) #输出按位与计算值
#输出矩阵结果
print('a=',a) #输出矩阵
print('b=',b) #输出矩阵
print('c=',c) #输出矩阵
然后把所有图像显示和保存好:
python
#合并图像
himg=np.hstack((src,img))
# 显示和保存定义的图像
cv.imshow('display-and-src', dst) # 显示图像
cv.imshow('display-and', img) # 显示图像
cv.imwrite('display-and.png', img) # 保存图像
cv.imshow('display-and-image', image) # 显示图像
cv.imwrite('display-and-image.png', image) # 保存图像
cv.imshow('display-and-himg', himg) # 显示图像
cv.imwrite('display-and-himg.png', himg) # 保存图像
cv.waitKey() # 图像不关闭
cv.destroyAllWindows() # 释放所有窗口
此处使用的初始图像是:
++图1 初始图像srcx.png++
第二张带掩模的图像为:
++图2 第二张带掩模的图像display-and-image.png++
按位与运算后的图像:
++图3 按位与运算后的图像display-and.png++
相应的,获得的特定像素点BGR值为:
++图4 像素点[150,150]处BGR按位与计算过程++
上述图像清晰展示了按位与计算前后图像的变化,按位与计算是对二进制数展开的计算。
此时的完整代码为:
python
import cv2 as cv # 引入CV模块
import numpy as np #引入numpy模块
# 读取图片-直接转化灰度图
src = cv.imread('srcx.png') #读取图像
dst=src#输出图像
# 定义图像
image = np.zeros(src.shape, np.uint8) # 定义一个竖直和水平像素与初始图像等大的全0矩阵
print('像素大小为',src.shape)
image[100:200, :, :] = 255 # 行掩模
image[:,100:350,: ] = 200 # 列掩模
image[:, :, 0] = 55 # 第一个通道值
#按位与运算
img=cv.bitwise_and(src,image) #与运算
#显示BGR值
print("dst像素数为[150,150]位置处的BGR=", dst[150,150]) # 获取像素数为[100,100]位置处的BGR
print("image像素数为[150,150]位置处的BGR=", image[150,150]) # 获取像素数为[100,100]位置处的BGR
print("img像素数为[150,150]位置处的BGR=", img[150,150]) # 获取像素数为[100,100]位置处的BGR
a=np.zeros((1,3),np.uint8) #定义矩阵
a=dst[150,150] #将像素点BGR直接赋值给矩阵
b=np.zeros((1,3),np.uint8) #定义矩阵
b=image[150,150] #将像素点BGR直接赋值给矩阵
c=np.zeros((1,3),np.uint8) #定义矩阵
#二进制按位与计算
for i in range(3): #计数
print('a','[0,',i,']=',a[i],'的二进制转化值=', bin(a[i]), ',b=','[0,',i,']=', b[i],'的二进制转化值=',bin(b[i])) #输出二进制转化值
c[0,i]=np.bitwise_and(a[i],b[i]) #赋值按位与计算值
print('c',[0,i],'=',c[0,i]) #输出按位与计算值
#输出矩阵结果
print('a=',a) #输出矩阵
print('b=',b) #输出矩阵
print('c=',c) #输出矩阵
#合并图像
himg=np.hstack((src,img))
# 显示和保存定义的图像
cv.imshow('display-and-src', dst) # 显示图像
cv.imshow('display-and', img) # 显示图像
cv.imwrite('display-and.png', img) # 保存图像
cv.imshow('display-and-image', image) # 显示图像
cv.imwrite('display-and-image.png', image) # 保存图像
cv.imshow('display-and-himg', himg) # 显示图像
cv.imwrite('display-and-himg.png', himg) # 保存图像
cv.waitKey() # 图像不关闭
cv.destroyAllWindows() # 释放所有窗口
【2.2】有掩模矩阵
有掩模矩阵需要先定义一个掩模矩阵,如果我们回溯官网,会发现官网对掩模矩阵的定义有一个要求:必须是单通道矩阵。
官网链接和相关说明如下:
++图5 掩模矩阵内必须是单通道数组++
为此,需要把初始图像做一次灰度转化,然后再定义掩模矩阵:
python
# 读取图片-直接转化灰度图
src = cv.imread('srcx.png') #读取图像
dst=src #输出图像
gray_src=cv.cvtColor(src,cv.COLOR_BGR2GRAY) #转化为灰度图
dstg=gray_src #输出图像
print('初始图像像素大小为',src.shape)
print('初始图像灰度图像素大小为',gray_src.shape)
掩模矩阵定义:
python
#定义掩模矩阵
mask = np.zeros((gray_src.shape), np.uint8) # 定义一个竖直和水平像素与初始图像等大的全0矩阵
mask[350:500, :] = 255 # 水平区域
mask[:,350:500] = 200 # 竖直区域
为进行对比,带不带掩模矩阵的按位与操作均执行:
python
#按位与运算
img=cv.bitwise_and(src,image) #与运算
img2=cv.bitwise_and(src,image,mask=mask) #与运算
然后,需要选取初始图像、带掩模的第二图像和掩模矩阵互相重合的点作为特定像素点,读取相关点的BGR值:
python
#显示BGR值
print("dst像素数为[300,180]位置处的BGR=", dst[300,180]) # 获取像素数为[100,100]位置处的BGR
print("image像素数为[300,180]位置处的BGR=", image[300,180]) # 获取像素数为[100,100]位置处的BGR
print("img像素数为[300,180]位置处的BGR=", img[300,180]) # 获取像素数为[100,100]位置处的BGR
print("img2像素数为[300,180]位置处的BGR=", img2[300,180]) # 获取像素数为[100,100]位置处的BGR
a=np.zeros((1,3),np.uint8) #定义矩阵
a=dst[300,180] #将像素点BGR直接赋值给矩阵
b=np.zeros((1,3),np.uint8) #定义矩阵
b=image[300,180] #将像素点BGR直接赋值给矩阵
c=np.zeros((1,3),np.uint8) #定义矩阵
d=np.zeros((1,3),np.uint8) #定义矩阵
d=image[300,180] #将像素点BGR直接赋值给矩阵
e=np.zeros((1,3),np.uint8) #定义矩阵
#二进制按位与计算e
for i in range(3): #计数
print('a','[0,',i,']=',a[i],'的二进制转化值=', bin(a[i]), ',b=','[0,',i,']=', b[i],'的二进制转化值=',bin(b[i])) #输出二进制转化值
c[0,i]=np.bitwise_and(a[i],b[i]) #赋值按位与计算值
print('c',[0,i],'=',c[0,i]) #输出按位与计算值
print('c','[0,',i,']=',[0,i],'的二进制转化值=', bin(c[0,i]), ',d=','[0,',i,']=', d[i],'的二进制转化值=',bin(d[i])) #输出二进制转化值
e[0,i]=np.bitwise_and(c[0,i],d[i]) #赋值按位与计算值
print('e',[0,i],'=',e[0,i]) #输出按位与计算值
#输出矩阵结果
print('a=',a) #输出矩阵
print('b=',b) #输出矩阵
print('c=',c) #输出矩阵
print('d=',d) #输出矩阵
print('e=',e) #输出矩阵
之后将按位与计算图像和原图像作对比:
python
#合并图像
himg=np.hstack((src,img))
himg2=np.hstack((src,img2))
然后显示和保存图像:
python
# 显示和保存定义的图像
cv.imshow('dst', dst) # 显示图像
cv.imshow('img', img) # 显示图像
cv.imwrite('img.png', img) # 保存图像
cv.imshow('img2', img2) # 显示图像
cv.imwrite('img2.png', img2) # 保存图像
cv.imshow('image', image) # 显示图像
cv.imwrite('image.png', image) # 保存图像
cv.imshow('mask', mask) # 显示图像
cv.imwrite('mask.png', mask) # 保存图像
cv.imshow('himg', himg) # 显示图像
cv.imwrite('himg.png', himg) # 保存图像
cv.imshow('himg2', himg2) # 显示图像
cv.imwrite('himg2.png', himg2) # 保存图像
cv.waitKey() # 图像不关闭
cv.destroyAllWindows() # 释放所有窗口
代码运行后,获得的图像为:
++图6 第二张带掩模的图像image.png++
++图7 掩模矩阵对应的图像image.png++
++图8 按位与运算后的图像-不带掩模矩阵++
++++
++图9 按位与运算后的图像-带掩模矩阵++
显然,代掩模矩阵后,最后获得的按位与计算图像展示了三张图共有的部分。为增进这种对比效果,把两张按位与计算的图像合并在一起后:
++图10 按位与计算后的图像-不带掩模矩阵vs带掩模矩阵++
然后对特定点像素点的BGR值读取:
++图11 特定像素点读取效果++
图11的特定像素点读取结果依然表明,使用cv2.bitwise_and()函数执行图像按位与计算时,当面向两张图像时,各个像素点的BGR值都是按照十进制转二进制、二进制按位与计算,然后再转回十进制的顺序进行。当面向三张图像时,先对前两张图像执行按位与计算,此时会获得一张中间图像,然后中间图像和第三个图像再次执行按位与计算。
++图12 按位操作工作流程++
此时的完整代码为:
python
import cv2 as cv # 引入CV模块
import numpy as np #引入numpy模块
# 读取图片-直接转化灰度图
src = cv.imread('srcx.png') #读取图像
dst=src #输出图像
gray_src=cv.cvtColor(src,cv.COLOR_BGR2GRAY) #转化为灰度图
dstg=gray_src #输出图像
print('初始图像像素大小为',src.shape)
print('初始图像灰度图像素大小为',gray_src.shape)
# 定义第二个图像
image = np.zeros(src.shape, np.uint8) # 定义一个竖直和水平像素与初始图像等大的全0矩阵
print('初始图像像素大小为',src.shape)
image[50:350, :, :] = 255 # 行掩模
image[:,120:200,: ] = 200 # 列掩模
image[:, :, 0] = 55 # 第三个通道值
#定义掩模矩阵
mask = np.zeros((gray_src.shape), np.uint8) # 定义一个竖直和水平像素与初始图像等大的全0矩阵
mask[280:350, :] = 255 # 水平区域
mask[:,150:350] = 200 # 竖直区域
#按位与运算
img=cv.bitwise_and(src,image) #与运算
img2=cv.bitwise_and(src,image,mask=mask) #与运算
#显示BGR值
print("dst像素数为[300,180]位置处的BGR=", dst[300,180]) # 获取像素数为[100,100]位置处的BGR
print("image像素数为[300,180]位置处的BGR=", image[300,180]) # 获取像素数为[100,100]位置处的BGR
print("img像素数为[300,180]位置处的BGR=", img[300,180]) # 获取像素数为[100,100]位置处的BGR
print("img2像素数为[300,180]位置处的BGR=", img2[300,180]) # 获取像素数为[100,100]位置处的BGR
a=np.zeros((1,3),np.uint8) #定义矩阵
a=dst[300,180] #将像素点BGR直接赋值给矩阵
b=np.zeros((1,3),np.uint8) #定义矩阵
b=image[300,180] #将像素点BGR直接赋值给矩阵
c=np.zeros((1,3),np.uint8) #定义矩阵
d=np.zeros((1,3),np.uint8) #定义矩阵
d=image[300,180] #将像素点BGR直接赋值给矩阵
e=np.zeros((1,3),np.uint8) #定义矩阵
#二进制按位与计算e
for i in range(3): #计数
print('a','[0,',i,']=',a[i],'的二进制转化值=', bin(a[i]), ',b=','[0,',i,']=', b[i],'的二进制转化值=',bin(b[i])) #输出二进制转化值
c[0,i]=np.bitwise_and(a[i],b[i]) #赋值按位与计算值
print('c',[0,i],'=',c[0,i]) #输出按位与计算值
print('c','[0,',i,']=',[0,i],'的二进制转化值=', bin(c[0,i]), ',d=','[0,',i,']=', d[i],'的二进制转化值=',bin(d[i])) #输出二进制转化值
e[0,i]=np.bitwise_and(c[0,i],d[i]) #赋值按位与计算值
print('e',[0,i],'=',e[0,i]) #输出按位与计算值
#输出矩阵结果
print('a=',a) #输出矩阵
print('b=',b) #输出矩阵
print('c=',c) #输出矩阵
print('d=',d) #输出矩阵
print('e=',e) #输出矩阵
#合并图像
himg=np.hstack((src,img))
himg2=np.hstack((src,img2))
himg3=np.hstack((img,img2))
# 显示和保存定义的图像
cv.imshow('dst', dst) # 显示图像
cv.imshow('img', img) # 显示图像
cv.imwrite('img.png', img) # 保存图像
cv.imshow('img2', img2) # 显示图像
cv.imwrite('img2.png', img2) # 保存图像
cv.imshow('image', image) # 显示图像
cv.imwrite('image.png', image) # 保存图像
cv.imshow('mask', mask) # 显示图像
cv.imwrite('mask.png', mask) # 保存图像
cv.imshow('himg', himg) # 显示图像
cv.imwrite('himg.png', himg) # 保存图像
cv.imshow('himg2', himg2) # 显示图像
cv.imwrite('himg2.png', himg2) # 保存图像
cv.imshow('himg3', himg3) # 显示图像
cv.imwrite('himg3.png', himg3) # 保存图像
cv.waitKey() # 图像不关闭
cv.destroyAllWindows() # 释放所有窗口
【3】总结
掌握了python+opencv实现使用cv2.bitwise_and()函数实现图像带掩模矩阵按位与计算的技巧。