提示:本专栏所用版本仅供参考,其他版本也可
库 | 版本 |
---|---|
python | Python 3.9.3 |
opencv | 4.5.5 |
matplotlib | 3.4.3 |
numpy | 1.19.5 |
学习基础 | python及其简单的矩阵计算 |
首先,运行如下代码,我们发现桌面上创建了一个名为"img"的窗口并显示了当前文件夹下名为111的图片。(注意,运行前情复制一张图片到写有python代码的文件夹下,并重命名为111)
import cv2#导入cv库
img = cv2.imread(".\\111.bmp")#读取图片111
"""
./代表表示文件夹:
"./111.bmp"表示当前文件夹下的111图片,格式为bmp
"""
cv2.imshow("img",img)#显示图片111到窗口
print(img)#打印图像数据
cv2.waitKey(0)#等待键盘任意按键按下
cv2.destroyWindow("img")#关闭img窗口
函数介绍:
函数原型 | 返回值 | 参数 |
---|---|---|
cv2.imread(filename[,flags]) | 读取的图像 | filename:完整文件名 flags:读取类型[如灰度] |
cv2.imshow(winname,mat) | None | winname:窗口名称 mat:要显示的图像 |
cv2.waitKey([delay]) | 按键的ASCII码 | 等待键盘触发的时间(ms) |
cv2.destroyWindow(winname) | None | 要销毁窗口的名称 |
cv2.imwrite(filename,img[,params]) | True/False | filename:路径名 img:保存的图像 params保存的类型 |
运行(一)的代码后,除了启动一个窗口,还在终端打印了如下数据
可以看到,一个彩色图像在计算机中以三维数组(x,y,3)的形式存储(准确的说,这是RGB彩色图像存储方式,在openCV中,还有其他的图像形式,第二章中将详细讲解),为了感受三维图像,我绘制了如下三维坐标图:
在openCV中,对图像数据的处理分为行,列和通道,对应三维矩阵的形式。行列及其通道决定了像素大小,通道分为R,G,B三通道,表示了不同的三原色,R代表红色,G表示绿色,B表示蓝色。
有了这些数据,我们便可以对图像进行肆无忌惮的处理,修改矩阵中的数据就相当于读图像进行修改。
在(二)中,我们有了图像在三维矩阵中存储形式个概念,接下来,我们将对一幅图像的数据进行修改。 在此之前,我们已经通过函数cv2.imread()拿到了图像111的三维数组。
函数 | 作用 |
---|---|
x,y,n = img.shape | 获取彩色图像的行,列,通道 |
value = img.size | 获取图像的像素大小(size=x* y*N) |
import cv2
img = cv2.imread("./111.jpg")#读取图片111
B = img[:,:,0]# 0(B通道)
G = img[:,:,1]# 1(R通道)
R = img[:,:,2]
cv2.imshow("B",B)#显示图片111到窗口
cv2.imshow("G",G)#显示图片111到窗口
cv2.imshow("R",R)#显示图片111到窗口
cv2.imshow("img",img)#显示原图
cv2.waitKey()
cv2.destroyAllWindows()#销毁所有窗口
可以看到我们通过获取三维数组的每一个通道表示的二维数组分离了B G R三个通道,且三个通道对不同的颜色表现出了不同的敏感度。
关于通道的分离,我们还可以使用opencv提供的split函数
B,G,R = cv2.split( img ) #分离B,G,R三通道
根据(二),我们已经知道了一张图像是以矩阵的形式存储数据。那么理论上,我们也可以手动生成一个数组,并让它显示出来。
矩阵计算相关函数:
名称 | 作用 |
---|---|
numpy | 一个提供了大量的矩阵运算的模块 |
np.zeros() | 生成一张全是 0 的矩阵表 |
np.ones() | 生成一张全时 1 的矩阵表 |
np.random.randint() | 生成一张全是随机数的矩阵表 |
np.hstack() | 将多个二维数组水平拼接在一起 |
import numpy as np#导入np库
#np.uint8表示一个无符号字节,大小(0~255)
data1 = np.zeros((200,200),np.uint8)#生成一张200*200全为0的矩阵
data2 = np.ones((200,200),np.uint8)#生成一张200*200全为1的矩阵
data2 = data2*255#将data2矩阵的每个数据都乘上255
data3 = np.random.randint(0,255,(200,200),np.uint8)#生成一张200*200的随机矩阵
data4 = np.hstack((data1,data2,data3))#j将三个二维数组水平拼接在一起
#img = np.random.randint(0,255,(200,200,3),np.uint8)#生成一张200*200*3的随机矩阵
cv2.imshow("combition",data4)
cv2.waitKey()
cv2.destroyAllWindows()#销毁所有窗口
数学逻辑:a+b<=255 (sum = a+b)
数学逻辑:a+b>255 (sum = (a+b)%255)
img = cv2.imread("./111.jpg")#读取图片111
# 1
B = img.copy()#复制img的数据
B[:,:,0] = 255#让图像的0通道全部为255
# 2
R = img.copy()
x,y,n = R.shape#获取R的行列和通道数
mask = np.zeros((x,y,n),np.uint8)#生成一个大小等于R的矩阵
mask[200:400,200:500,0] = 100#修改B 通道某个区域为255
R = mask+R #两个矩阵相加
#R = R-mask
#R = R*2
cv2.imshow("combition",R)
cv2.waitKey()
cv2.destroyAllWindows()#销毁所有窗口
cv提供的函数 | 实质 | 作用 |
---|---|---|
cv2.bitwise_and(s1,s2[,mask]) | & | 按位与操作 |
cv2.bitwise_or(s1,s2[,mask]) | | | 按位或操作 |
cv2.bitwise_not(s1[,mask]) | ~ | 按位取反操作 |
cv2.bitwise_xot(s1,s2[,mask]) | ^ | 按位异或操作 |
如图是一个(3*3),unit8类型的矩阵的二进制表,在计算中,按位逻辑操作可以可以操作每一个比特位的值。这些操作包含:&、|、~、^
—— | 0 | 1 | 2 |
---|---|---|---|
0 | 00100101 | 11111111 | 01010100 |
1 | 11111111 | 11011100 | 11110000 |
2 | 11101111 | 00000000 | 11111110 |
import cv2
import numpy as np
img = cv2.imread("./111.jpg")#读取图片111
# 1
B,G,R = cv2.split(img)#通道分离
C = B[200:500,200:500]
imgmask = np.ones((C.shape),np.uint8)#生成一个大小等于B的二维矩阵
imgmask[:,:] = 0x15;#每个像素点 = 0001 0101
#进行按位逻辑运算
A = cv2.bitwise_and(C,imgmask)
O = cv2.bitwise_or(C,imgmask)
N = cv2.bitwise_not(C)
X = cv2.bitwise_xor(C,imgmask)
AONX1 = np.hstack((C,A,O))#水平拼接
AONX2 = np.hstack((C,N,X))
showimg = np.vstack((AONX1,AONX2))#垂直拼接
cv2.imshow("showimg",showimg)
cv2.waitKey()
cv2.destroyAllWindows()#销毁所有窗口
甚至,我们还可以逐位(1111 1111)单独提取组成八张新矩阵,既位平面分解
## 4、图像访问numpy库向用户提供了一种矩阵的快速访问接口
import cv2
import numpy as np
img = cv2.imread('./111.jpg')
number = img.item((200,200,1))#访问200行,200列,1通道的数据
img.itemset((200,200,1),50)#修改200行,200列,1通道的数据
number1 = img.item((200,200,1))#访问200行,200列,1通道的数据
print(number," ",number1)#打印修改前后的数据
import cv2
video = cv2.VideoCapture(0)#0表示打开笔记本自带的摄像头
open = video.isOpened()#判断摄像头是否被打开,发开返回True
while(open):
"""由于摄像头不是静态的照片
所以需要以循环的方式一直读取
"""
ret,frame = video.read()#读取摄像头当前帧的数据,每帧为一张图片
if frame is None:#判断是否有数据被读取
break
cv2.imshow("video",frame)#显示读取到的数据
if cv2.waitKey(30) & 0xff == 27:#判断是否按下了ESC键
break
cv2.destroyAllWindows()#销毁所有窗口
运行以上函数,我们成功打开了笔记本电脑的摄像头。对于读取到的frame数据而言,依然是一张BGT彩色图像的数据形式,我们依然可以使用前面写过的算法操作进行计算它的数据,唯一不同的是frame数据会随着时间的变化而自行变化。
【点击学习】:openCV专栏(二):基础计算实战+色彩空间转换
以上就是今天所要分享的内容了
学习路漫漫,我们仍需负重前行……
为此博主新创建了一个群,期待你们的加入:
QQ群:928357277
欢迎加入我们的大家庭:928357277