python学opencv|读取图像(四十五)增加掩模:使用cv2.bitwise_and()函数实现图像按位与运算

【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】有掩模矩阵

有掩模矩阵需要先定义一个掩模矩阵,如果我们回溯官网,会发现官网对掩模矩阵的定义有一个要求:必须是单通道矩阵。

官网链接和相关说明如下:

OpenCV: Operations on arrays

++图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()函数实现图像带掩模矩阵按位与计算的技巧。

相关推荐
山居秋暝LS35 分钟前
目标跟踪之sort算法(3)
python·算法·目标跟踪·sort
{⌐■_■}2 小时前
【Validator】自定义字段、结构体补充及自定义验证,go案例讲解ReportError和errors.As在其中的使用
开发语言·golang·xcode
python算法(魔法师版)4 小时前
C++游戏开发深度解析
开发语言·c++·c
siy23335 小时前
[c语言日寄]assert函数功能详解
c语言·开发语言·笔记·学习·算法
Tester_孙大壮7 小时前
第26章 测试驱动开发(TDD)模式详解与 Python 实践
驱动开发·python·tdd
youcans_7 小时前
2025年数学建模美赛:A题分析(1)Testing Time: The Constant Wear On Stairs
python·数学建模·模型·频率·可靠性
皮皮虾我们跑8 小时前
Java中的泛型
java·开发语言
Channing Lewis8 小时前
如何使用 Flask-Caching 提高性能?
后端·python·flask
fly spider8 小时前
每日 Java 面试题分享【第 14 天】
java·开发语言
大哥喝阔落8 小时前
GRAPHARG——学习
python·学习·flask