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

ops/2025/2/2 12:18:12/

【1】引言

前序已经对使用cv2.bitwise_and()函数实现图像按位与运算进行了反复探究:

pythonopencv|读取图像(四十三)使用cv2.bitwise_and()函数实现图像按位与运算-CSDN博客

pythonopencv|读取图像(四十四)原理探究: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]位置处的BGRa=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]位置处的BGRa=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]位置处的BGRa=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]位置处的BGRa=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()函数实现图像带掩模矩阵按位与计算的技巧。


http://www.ppmy.cn/ops/155030.html

相关文章

C语言自定义数据类型详解(一)——结构体类型(上)

什么是自定义数据类型呢?顾名思义,就是我们用户自己定义和设置的类型。 在C语言中,我们的自定义数据类型一共有三种,它们分别是:结构体(struct),枚举(enum),联合(union)。接下来,我…

第四章 WAL 4.1 WAL文件

4.1 WAL文件 WAL文件用于存储WAL日志。本小节主要介绍WAL文件。 1、WAL文件大小 PG使用64位的无符号整型作为日志文件的寻址空间。如下所示: typedef uint64 XLogRecPtr;//日志寻址类型 static void PreallocXlogFiles(XLogRecPtr endptr)//预分配日志文件uint64 offset;…

机器学习之决策树(DecisionTree——C4.5)

在机器学习之决策树(DecisionTree——ID3)中我们提到,ID3无法处理是连续值或有缺失值的属性。而C4.5算法可以解决ID3算的上述局限性。 1、连续值属性的处理 对于数据集 D D D和连续值属性 A A A,假设连续值属性 A A A有 M M M个不…

【处理和预防校园霸凌】。营造安全

处理和预防校园霸凌对于营造安全、和谐的校园环境至关重要,以下从处理和预防两个方面提供一些建议: ### 处理校园霸凌 1. **及时干预制止**:教师一旦发现校园霸凌行为,要第一时间上前制止,确保受霸凌学生的人身安全&a…

算法基础——存储

引入 基础理论的进步,是推动技术实现重大突破,促使相关领域的技术达成跨越式发展的核心。 在发展日新月异的大数据领域,基础理论的核心无疑是算法。不管是技术设计,还是工程实践,都必须仰仗相关算法的支持&#xff0…

数据结构 队列

目录 前言 一,队列的基本知识 二,用数组实现队列 三,用链表实现队列 总结 前言 接下来我们将学习队列的知识,这会让我们了解队列的基本概念和基本的功能 一,队列的基本知识 (Queue) 我们先来研究队列的ADT&#xff0c…

前端【11】HTML+CSS+jQUery实战项目--实现一个简单的todolist

前端【8】HTMLCSSjavascript实战项目----实现一个简单的待办事项列表 (To-Do List)-CSDN博客 学过jQUery可以极大简化js代码的编写,基于之前实现的todolist小demo,了解如何使用 jQuery 来实现常见的动态交互功能。 修改后的js代码 关键点解析 动态添加…

通过 Docker 部署 pSQL 服务器的教程

在这篇文章中,我们将深入探讨如何利用 Docker 在 Azure 上快速部署 PostgreSQL(pSQL)服务器。这个过程不仅简单高效,还能为你的开发环境提供强大的支持。 如何使用 Edu 邮箱申请 Azure 订阅并开通免费的 VPS 首先,你…