python学opencv|读取图像(四十九)原理探究:使用cv2.bitwise()系列函数实现图像按位运算
【0】基础定义
按位与运算:两个等长度二进制数上下对齐,全1取1,其余取0。
按位或运算:两个等长度二进制数上下对齐,有1取1,其余取0。
按位异或运算: 两个等长度二进制数上下对齐,相同取0,其余取1。
按位取反运算:一个二进制数,0变1,1变0。
【2】引言
在前序学习进程中,调用cv2.bitwise()系列函数实现了图像的按位与计算,相关文章链接包括且不限于:
python学opencv|读取图像(四十三)使用cv2.bitwise_and()函数实现图像按位与运算-CSDN博客
python学opencv|读取图像(四十五)增加掩模:使用cv2.bitwise_and()函数实现图像按位与运算-CSDN博客
python学opencv|读取图像(四十六)使用cv2.bitwise_or()函数实现图像按位或运算-CSDN博客
python学opencv|读取图像(四十七)使用cv2.bitwise_not()函数实现图像按位取反运算-CSDN博客
python学opencv|读取图像(四十八)使用cv2.bitwise_xor()函数实现图像按位异或运算-CSDN博客
图像的按位与计算,是通过对各个像素点上的BGR值进行操作:先把十进制数转化为二进制数,再进行按位计算,然后再转回十进制数输出。
由于前序文章的重点是对比按位计算前后图像的色彩变化,除按位与计算外,没有详细深究二进制按位计算过程。因此本文以之前按位与计算为基础,对此展开专题探索。
按位与计算的原理探索文章链接为:
python学opencv|读取图像(四十三)使用cv2.bitwise_and()函数实现图像按位与运算-CSDN博客
【3】项目可行性分析
以输入的外部图像为基础,调用cv2.bitwise()系列函数让图像进行按位计算后,读取相关点的BGR值,使用np.bitwise()系列函数对cv2.bitwise()系列函数按位计算进行原理呈现。
【4】代码测试
首先引入相关模块和图像:
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('第二个图像像素大小为',image.shape)
image[50:350, :, :] = 180 # 行掩模
image[:,120:200,: ] = 255 # 列掩模
image[:, :, 2] = 120 # 第二个通道值
然后要引入一个8位单通道的二维矩阵定义掩模:
#定义掩模矩阵
mask = np.zeros((gray_src.shape), np.uint8) # 定义一个竖直和水平像素与初始图像等大的全0矩阵
mask[280:350, :] = 155 # 水平区域
mask[:,150:350] = 100 # 竖直区域
之后就调用cv2.bitwise()系列函数执行按位计算:
#执行位运算
#按位与运算
img_and=cv.bitwise_and(src,image) #按位与运算
img_and_mask=cv.bitwise_and(src,image,mask=mask) #按位与运算
#按位或运算
img_or=cv.bitwise_or(src,image) #按位或运算
img_or_mask=cv.bitwise_or(src,image,mask=mask) #按位或运算
#按位异或运算
img_xor=cv.bitwise_xor(src,image) #按位异或运算
img_xor_mask=cv.bitwise_xor(src,image,mask=mask) #按位异或计算
#按位取反运算
img_not=cv.bitwise_not(src) #按位取反运算
img_not_mask=cv.bitwise_not(src,mask=mask) #按位异或计算
按位计算执行以后,图像的BGR值发生变化,这时候使用np.bitwise()系列函数图像的BGR值进行按位计算,以对cv2.bitwise()系列函数按位计算进行原理呈现:
#显示BGR值
print("初始图像dst像素数为[300,180]位置处的BGR=", dst[300,180],'=a') # 获取像素数为[100,100]位置处的BGR
print("第二个图像image像素数为[300,180]位置处的BGR=", image[300,180],'=b') # 获取像素数为[100,100]位置处的BGR
print("img_and像素数为[300,180]位置处的BGR=", img_and[300,180],'=c') # 获取像素数为[100,100]位置处的BGR
print("img_and_mask像素数为[300,180]位置处的BGR=", img_and_mask[300,180]) # 获取像素数为[100,100]位置处的BGR
print("img_or像素数为[300,180]位置处的BGR=", img_or[300,180],'=d') # 获取像素数为[100,100]位置处的BGR
print("img_or_mask像素数为[300,180]位置处的BGR=", img_or_mask[300,180]) # 获取像素数为[100,100]位置处的BGR
print("img_xor像素数为[300,180]位置处的BGR=", img_xor[300,180],'=e') # 获取像素数为[100,100]位置处的BGR
print("img_xor_mask像素数为[300,180]位置处的BGR=", img_xor_mask[300,180]) # 获取像素数为[100,100]位置处的BGR
print("img_not像素数为[300,180]位置处的BGR=", img_not[300,180],'=f') # 获取像素数为[100,100]位置处的BGR
print("img_not_mask像素数为[300,180]位置处的BGR=", img_not_mask[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) #定义矩阵-np.bitwise_and
d=np.zeros((1,3),np.uint8) #定义矩阵-np.bitwise_or
e=np.zeros((1,3),np.uint8) #定义矩阵-np.bitwise_xor
f=np.zeros((1,3),np.uint8) #定义矩阵-np.bitwise_not
# 二进制按位与计算
for i in range(3): # 计数
print('a', '[0,', i, ']=', a[i], '的二进制转化值=',bin(a[i])) # 输出二进制转化值
print('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], '的二进制转化值=', bin(c[0,i])) # 输出二进制转化值
d[0, i] = np.bitwise_or(a[i], b[i]) # 赋值按位或计算值
print('d', '[0,', i, ']=', d[0,i], '的二进制转化值=', bin(d[0,i])) # 输出二进制转化值
e[0, i] = np.bitwise_xor(a[i], b[i]) # 赋值按位或计算值
print('e', '[0,', i, ']=', e[0, i], '的二进制转化值=', bin(e[0, i])) # 输出二进制转化值
f[0, i] = np.bitwise_not(a[i]) # 赋值按位或计算值
print('f', '[0,', i, ']=', e[0, i], '的二进制转化值=', bin(f[0, i])) # 输出二进制转化值
print('c', [0, i], '是a[0,', i, ']和b[0', i, ']按位与的值=np.bitwise_and(a[0,',i, '],b[0,',i,'])=', c[0, i]) # 输出按位与计算值
print('d', [0, i], '是a[0,', i, ']和b[0', i, ']按位或的值=np.bitwise_or(a[0,',i, '],b[0,',i,'])=', d[0, i]) # 输出按位或计算值
print('e', [0, i], '是a[0,', i, ']和b[0', i, ']按位异或的值=np.bitwise_xor(a[0,',i, '],b[0,',i,'])=', e[0, i]) # 输出按位异或计算值
print('f', [0, i], '是a[0,', i, ' ]按位取反的值=np.bitwise_not(a[0,',i, '])=', f[0, i]) # 输出按位取反计算值
# 输出矩阵结果
print('a=', a) # 输出矩阵
print('b=', b) # 输出矩阵
print('c=', c) # 输出矩阵
print('d=', d) # 输出矩阵
print('e=', e) # 输出矩阵
print('f=', f) # 输出矩阵
由于主要关注数值变化,因此未直接显示相关图像,其余代码可作为辅助学习使用:
#合并图像
himg_and_andmask = np.hstack((img_and,img_and_mask))
himg_or_ormask = np.hstack((img_or,img_or_mask))
himg_xor_xormask = np.hstack((img_xor,img_xor_mask))
himg_not_notmask = np.hstack((img_not,img_not_mask))
# 显示和保存定义的图像
#cv.imshow('dst', dst) # 显示图像
#cv.imshow('image', image) # 显示图像
#cv.imshow('mask', mask) # 显示图像
#cv.imshow('himg_and_andmask', himg_and_andmask) # 显示图像
#cv.imshow('himg_or_ormask', himg_or_ormask) # 显示图像
#cv.imshow('himg_xor_xormask', himg_xor_xormask) # 显示图像
#cv.imshow('himg_not_notmask', himg_not_notmask) # 显示图像
cv.waitKey() # 图像不关闭
cv.destroyAllWindows() # 释放所有窗口
代码运行使用的相关图像有:
图1 初始图像srcx.png
图2 第二张图像image.png
图3 掩模mask.png
代码运行后,获得的相关文字输出为:
图4 图像基本属性
图5 特定像素点BGR值读取
读取到特定像素点[300,180]处的BGR之后,首先需要关注:
初始图像在此处的BGR值为:[132 80 121]
第二张图像在此处的BGR值为:[255 255 120]
其余位置的数据,其实是通过cv2.bitwise()系列函数按位计算之后获得的。为追溯这个计算过程,继续获得了输出文字:
图6 特定像素点BGR值-按位计算第一个点
需要注意的是 ,e[0,0]和f[0,0]在0b后面只有7位数字,这是因为0b01111011在0b之后的0确实没有用处,只有占位的作用,所以python就直接省略了。
图7 特定像素点BGR值-按位计算第二个点
a[0,1]和c[0,1]在0b后面只有7位数字,也是因为在0b之后的0确实没有用处,只有占位的作用,所以python就直接省略了。
图8 特定像素点BGR值-按位计算第二个点
e[0,2]是异或计算的结果,两个二进制数上下对齐,相同取0,其余取1,只有最右侧的位置不同,其余均相同,所以最后的结果是1。
f[0,2]是按位取反的结果,虽然a[0,2]只有7位,但首位的0取反之后就是1,所以f[0,2]有8位数字。
此时的完整代码为:
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('第二个图像像素大小为',image.shape)
image[50:350, :, :] = 180 # 行掩模
image[:,120:200,: ] = 255 # 列掩模
image[:, :, 2] = 120 # 第二个通道值
#定义掩模矩阵
mask = np.zeros((gray_src.shape), np.uint8) # 定义一个竖直和水平像素与初始图像等大的全0矩阵
mask[280:350, :] = 155 # 水平区域
mask[:,150:350] = 100 # 竖直区域
#执行位运算
#按位与运算
img_and=cv.bitwise_and(src,image) #按位与运算
img_and_mask=cv.bitwise_and(src,image,mask=mask) #按位与运算
#按位或运算
img_or=cv.bitwise_or(src,image) #按位或运算
img_or_mask=cv.bitwise_or(src,image,mask=mask) #按位或运算
#按位异或运算
img_xor=cv.bitwise_xor(src,image) #按位异或运算
img_xor_mask=cv.bitwise_xor(src,image,mask=mask) #按位异或计算
#按位取反运算
img_not=cv.bitwise_not(src) #按位取反运算
img_not_mask=cv.bitwise_not(src,mask=mask) #按位异或计算
#显示BGR值
print("初始图像dst像素数为[300,180]位置处的BGR=", dst[300,180],'=a') # 获取像素数为[100,100]位置处的BGR
print("第二个图像image像素数为[300,180]位置处的BGR=", image[300,180],'=b') # 获取像素数为[100,100]位置处的BGR
print("img_and像素数为[300,180]位置处的BGR=", img_and[300,180],'=c') # 获取像素数为[100,100]位置处的BGR
print("img_and_mask像素数为[300,180]位置处的BGR=", img_and_mask[300,180]) # 获取像素数为[100,100]位置处的BGR
print("img_or像素数为[300,180]位置处的BGR=", img_or[300,180],'=d') # 获取像素数为[100,100]位置处的BGR
print("img_or_mask像素数为[300,180]位置处的BGR=", img_or_mask[300,180]) # 获取像素数为[100,100]位置处的BGR
print("img_xor像素数为[300,180]位置处的BGR=", img_xor[300,180],'=e') # 获取像素数为[100,100]位置处的BGR
print("img_xor_mask像素数为[300,180]位置处的BGR=", img_xor_mask[300,180]) # 获取像素数为[100,100]位置处的BGR
print("img_not像素数为[300,180]位置处的BGR=", img_not[300,180],'=f') # 获取像素数为[100,100]位置处的BGR
print("img_not_mask像素数为[300,180]位置处的BGR=", img_not_mask[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) #定义矩阵-np.bitwise_and
d=np.zeros((1,3),np.uint8) #定义矩阵-np.bitwise_or
e=np.zeros((1,3),np.uint8) #定义矩阵-np.bitwise_xor
f=np.zeros((1,3),np.uint8) #定义矩阵-np.bitwise_not
# 二进制按位与计算
for i in range(3): # 计数
print('a', '[0,', i, ']=', a[i], '的二进制转化值=',bin(a[i])) # 输出二进制转化值
print('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], '的二进制转化值=', bin(c[0,i])) # 输出二进制转化值
d[0, i] = np.bitwise_or(a[i], b[i]) # 赋值按位或计算值
print('d', '[0,', i, ']=', d[0,i], '的二进制转化值=', bin(d[0,i])) # 输出二进制转化值
e[0, i] = np.bitwise_xor(a[i], b[i]) # 赋值按位或计算值
print('e', '[0,', i, ']=', e[0, i], '的二进制转化值=', bin(e[0, i])) # 输出二进制转化值
f[0, i] = np.bitwise_not(a[i]) # 赋值按位或计算值
print('f', '[0,', i, ']=', e[0, i], '的二进制转化值=', bin(f[0, i])) # 输出二进制转化值
print('c', [0, i], '是a[0,', i, ']和b[0', i, ']按位与的值=np.bitwise_and(a[0,',i, '],b[0,',i,'])=', c[0, i]) # 输出按位与计算值
print('d', [0, i], '是a[0,', i, ']和b[0', i, ']按位或的值=np.bitwise_or(a[0,',i, '],b[0,',i,'])=', d[0, i]) # 输出按位或计算值
print('e', [0, i], '是a[0,', i, ']和b[0', i, ']按位异或的值=np.bitwise_xor(a[0,',i, '],b[0,',i,'])=', e[0, i]) # 输出按位异或计算值
print('f', [0, i], '是a[0,', i, ' ]按位取反的值=np.bitwise_not(a[0,',i, '])=', f[0, i]) # 输出按位取反计算值
# 输出矩阵结果
print('a=', a) # 输出矩阵
print('b=', b) # 输出矩阵
print('c=', c) # 输出矩阵
print('d=', d) # 输出矩阵
print('e=', e) # 输出矩阵
print('f=', f) # 输出矩阵
#合并图像
himg_and_andmask = np.hstack((img_and,img_and_mask))
himg_or_ormask = np.hstack((img_or,img_or_mask))
himg_xor_xormask = np.hstack((img_xor,img_xor_mask))
himg_not_notmask = np.hstack((img_not,img_not_mask))
# 显示和保存定义的图像
#cv.imshow('dst', dst) # 显示图像
#cv.imshow('image', image) # 显示图像
#cv.imshow('mask', mask) # 显示图像
#cv.imshow('himg_and_andmask', himg_and_andmask) # 显示图像
#cv.imshow('himg_or_ormask', himg_or_ormask) # 显示图像
#cv.imshow('himg_xor_xormask', himg_xor_xormask) # 显示图像
#cv.imshow('himg_not_notmask', himg_not_notmask) # 显示图像
cv.waitKey() # 图像不关闭
cv.destroyAllWindows() # 释放所有窗口
综上所述:
a.图像的按位与计算,是通过对各个像素点上的BGR值进行操作:先把十进制数转化为二进制数,再进行按位计算,然后再转回十进制数输出。
b.使用np.bitwise()系列函数对cv2.bitwise()系列函数按位计算进行原理呈现中继续发现,python在输出二进制的过程中,会省略0b之后紧跟的0。
【5】总结
专题探索了cv2.bitwise()系列函数按位计算时的BGR值二进制转化和按位计算过程。