OPENCV基础操作教程
温馨提示:本栏目使用的版本仅供参考,其他版本也可
库 | 版本 |
---|---|
python | Python 3.9.3 |
opencv | 4.5.5 |
matplotlib | 3.4.3 |
numpy | 1.19.5 |
学习基础 | python及其简单的矩阵计算 |
(1) 读取图像
首先,运行如下代码,我们发现桌面上创建了一个名为”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保存的类型 |
(2) 图像的存储形式
运行(1)的代码后,除了启动一个窗口外,终端上还打印了如下数据
可以看到,一个彩色图像在计算机中以三维数组(x,y,3)的形式存储(准确的说,这是RGB模式的彩色图像存储方式,在openCV中,还有其他的图像形式),为了感受三维图像,我绘制了如下三维坐标图:
在openCV中,对图像数据的处理分为行,列和通道,对应三维矩阵的形式。行列及其通道决定了像素大小,通道分为R,G,B三通道,表示了不同的三原色,R代表红色,G表示绿色,B表示蓝色。
有了这些数据,我们就可以肆无忌惮的对图像进行处理,而修改矩阵中的数据,就相当于读取图像并对其进行修改。
(3) 图像数据的处理
在(二)中,我们有了图像在三维矩阵中存储形式个概念,接下来,我们将对一幅图像的数据进行修改。 在此之前,我们已经通过函数cv2.imread()拿到了图像111的三维数组。
函数 | 作用 |
---|---|
x,y,n = img.shape | 获取彩色图像的行,列,通道 |
value = img.size | 获取图像的像素大小(x* y*N) |
1、依次显示B,G,R三个通道的图像
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 ),效果同上
2、制作一张随机图像
根据(2),我们已经知道图像以矩阵的形式存储数据。那么理论上,我们也可以手动生成一个数组并显示出来。
名称 | 作用 |
---|---|
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()#销毁所有窗口
3、像素处理:加减乘除
在三维矩阵中,每一个数据都可以看作是图像的一个像素点,我们可以通过各种算法(如+ – * /)对这些数据进行处理和计算。
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()#销毁所有窗口
运行后,图像上出现了一部分黄色的区域,打印三维数组,我们可以看到当(像素点(255)+100 >255)之后,数据变为99(a+b和256取余数),而不是355。因为RGB彩色图像的像素点范围为(uint8 一个无符号字节)0~255.
3、像素处理(按位逻辑操作)
cv提供的函数 | 实质 | 作用 |
---|---|---|
cv2.bitwise_and(s1,s2[,mask]) | & | 按位与操作 |
cv2.bitwise_or(s1,s2[,mask]) | | | 按位或操作 |
cv2.bitwise_not(s1[,mask]) | ~ | 按位取反操作 |
cv2.bitwise_xot(s1,s2[,mask]) | ^ | 按位异或操作 |
按位逻辑操作实际上是对一个无符号一字节的二进制形式的操作,我们知道,一个RGB彩色图像的单一通道是以二维数组的形式存在,而二维数组中的每一个像素点都是由(0~255)之间的数字组成,那么转换成二进制的表达方式就应该是这样的(3*3)。
—— | 0 | 1 | 2 |
---|---|---|---|
0 | 0010001 | 11111111 | 0101010 |
1 | 11111111 | 1101110 | 11110000 |
2 | 11111111 | 0000000 | 11111111 |
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、图像访问openCV库向用户提供了一种图像的快速访问接口
import cv2
import numpy as np
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)#打印修改前后的数据
(4) 相机的基本操作
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数据会随着时间的变化而自行变化。
(5) 结论
以上就是今天分享的代码
学习的路还很长,我们还要继续前行……
为此,博主新建了一个群,期待你的加入:
QQ群:928357277
欢迎加入我们的大家庭:928357277
文章出处登录后可见!