大多数的OpenCV应用程序需要将图像作为输入参数,同时也会将图像作为返回的结果。一个交互式的OpenCV应用程序很可能就是将摄像头或者视频文件又或者图像文件又或是原始字节(raw byte)等作为输入参数,通过窗口显示输出结果。
1、 图像文件的读取、显示以及保存
1.1 读取图像
函数:cv2.imread(),有两个参数,参数1是要读入的图像文件(包含路径,注意:图像的路径错误时,opencv不会提醒的);参数2表示告诉函数应该如何读取图像(可不填)。下面列出读出方式:
cv2.IMREAD_COLOR(1):读入一副彩色图像,图像的透明度会被忽略,这是默认参数;会将图像转换成三通道、8比特的图像。
cv2.IMREAD_GRAYSCALE(0):以灰度模式读入图像,会将图像转换成单通道、8比特的图像。
cv2.IMREAD_UNCHANGED(-1):读入一副图像并且包括图像的alpha通道;也就是使用原图像文件的通道数和比特数。
cv2.IMREAD_ANYCOLOR(4):转换成8比特的图像,通道数有图像文件决定,注意4通道图像会被转换成三通道图像;
cv2.IMREAD_ANYDEPTH(2):转换成单通道,比特数由图像文件决定。
下面用一个表格说明不同bit和通道(ch)的图像读取之间的转换关系:
1.2 显示图像
显示图像就比较简单了,首先可以使用OpenCV自带的窗口显示,函数就是cv2.imshow()。第一个参数就是窗口的名字,第二个参数就是要显示的图像了,也就是cv2.imread()函数的返回值。当然为了让显示窗口保持住程序不能运行结束需要使用cv2.waitKey()保持,最后结束还要使用cv2.destroyAllWindows()销毁。
还有种方法就是使用Matplotlib来显示,这个要结合PyQt5来进行在自己想要的地方进行显示的,显示过程和前面一个过程差不多,但是要注意一点的是Matplotlib显示的彩色图像和OpenCV显示时候的RGB顺便不一样,所以在显示前要转换一下,这个再后面的例子中会详解。
1.3 保存图像
保存图像使用函数:cv2.imwrite()
参数1:要保存的文件名和后缀名以及保存的路径
参数2:要保存的图像。
该函数会根据文件名的后缀自动保存相应的格式,不需要特殊指明;
import cv2
img = cv2.imread('image/test2.jpg')
cv2.imshow('demo', img)
while True:
if cv2.waitKey(20)&0xff == 27:
break
cv2.destroyAllWindows()
cv2.imwrite('sss.png', img)
**小结:**imread()函数和imwrite()函数能支持各种静态图像文件格式,不同系统的文件格式不一样,但是都支持BMP格式,通常还支持PNG、JPEG和TIFF格式。
2、 视频文件的获取和保存
OpenCV提供了VideoCapture类和VideoWrite类来支持各种格式的视频文件,支持的格式类型也会因系统的不同而不同,但都会支持AVI格式。在到达视频文件末尾之前,VideoCapture类可以通过read()函数来获取新的帧,每帧都是一幅基于BGR格式的图像。
2.1 获取视频帧
获取视频的函数:cv2.VideoCapture();
参数:可以是设备的索引号,也可以是视频文件;索引号对应的就是PC上的摄像头设备;获取到视频后,可以一帧一帧的获取(read())图像,但是最后,别忘记停止捕获视频(使用release()函数)。read()返回一个布尔值(True/False)。如果帧读取的是正确的,就是True。有时候cap(cv2.VideoCapture()的返回值)可能会不能成功的初始化摄像头的设备,这种情况下不正正常运行,可以使用cap.isOpened(),来检测是否成功初始化,如果返回是True就ok,否则就是用函数cap.open()。
还可以使用函数cap.get(propId)来获得视频的一些参数信息。这里propId可以是0到18之间的任何整数,每个数代表视频的一个属性。其中的一些值可以使用 cap.set(propId,value) 来修改, value 就是你想要设置成的新值。例如cap.get(3)和cap.get(4)来查看每一帧的宽和高。
那么如何显示视频呢?其实就是一帧一帧的显示读取到的每一帧图片,显示的快了就是视频的形式了。可以使用cv2.waitKey()设置适当的持续时间。如果设置的太低视频就会播放的快,太高就会播放的慢(使用这个方法控制视频的播放速度),通常情况下25毫秒就可以了。下面列出所有属性的值:
cv2.CAP_PROP_POS_MSEC(0):current position of the video file in milliseconds
cv2.CAP_PROP_POS_FRAMES(1):0-based index of the frame to be decoded/captured next
cv2.CAP_PROP_POS_AVI_RATIO(2):Relative position of the video file:0-start of the film,1-end of the film.
cv2.CAP_PROP_FRAME_WIDTH(3):width of the frames in the video stream.
cv2.CAP_PROP_FRAME_HEIGHT(4):hright of the frames in the video stream.
cv2.CAP_PROP_FPS(5):frame rate.
cv2.CAP_PROP_FOURCC(6):4-character code of codec.
cv2.CAP_PROP_FRAME_COUNT(7):number of frames in the video file.
cv2.CAP_PROP_FORMAT(8):format of the Mat objects returned by retrieve().
cv2.CAP_PROP_MODE(9): Backend-specific value indicating thecurrent capture mode.
cv2.CAP_PROP_BRIGHTNESS(10): Brightness of the image (only for cameras).
cv2.CAP_PROP_CONTRAST(11): Contrast of the image (only for cameras).
cv2.CAP_PROP_SATURATION(12): Saturation of the image (only for cameras).
cv2.CAP_PROP_HUE(13): Hue of the image (only for cameras).
cv2.CAP_PROP_GAIN(14): Gain of the image (only for cameras).
cv2.CAP_PROP_EXPOSURE(15): Exposure (only for cameras).
cv2.CAP_PROP_CONVERT_RGB(16): Boolean flags indicatingwhether images should be converted to RGB.
cv2.CAP_PROP_WHITE_BALANCE(17): Currently unsupported
cv2.CAP_PROP_RECTIFICATION(18): Rectification flag for stereo cameras (note: only supported by DC1394 v 2.x backend currently
2.2 保存视频
在我们捕获视频,并对每一帧都进行加工之后我们想要保存这个视频,对于图片来说很简单使用cv2.imwrite()。但是对于视频来说就要多做点工作。首先要创建一个VideoWriter的对象,我们应该确定一个输出文件的名字。接下来指定FourCC编码。播放频率和帧的大小也需要确定。最后一个是isColor标签,如果是True,每帧就是彩色图,否则就是灰度图。
下面用一个实际操作的例子说明一下:
import cv2
import numpy as np
# 选取摄像头,0为笔记本内置的摄像头,1,2···为外接的摄像头
cap = cv2.VideoCapture(0)
#定义摄像头的分辨率
cap.set(4,720)
#第一个参数是路径和文件名,文件命名的时候不要有特殊的符号
#第二个参数是视频格式,“MPEG”是一种标准格式,百度fourcc可见各种格式
#第二个参数(fourcc)如果设置为-1,允许实时选择视频格式
fourcc = cv2.VideoWriter_fourcc(*"MPEG")
# 第三个参数则是镜头快慢的,20为正常,小于二十为慢镜头
out = cv2.VideoWriter('./output.avi',fourcc,20,(640,480))
while True:
ret,frame = cap.read() # 获取图像
if ret == True:
frame = cv2.flip(frame, 1)# 在帧上进行操作
cv2.imshow("frame", frame) # 显示帧
out.write(frame) # 保存视频
if cv2.waitKey(1) == ord('s'): #按下‘s’保存图片
print('save photo')
cv2.imwrite("./new.png",frame)
if cv2.waitKey(1) == ord('q'):#按下‘q’退出
print('quit')
break
else:
break
# 释放摄像头资源
cap.release()
out.release()
cv2.destroyAllWindows()
要注意:必须要为VideoWriter类的构造函数指定视频文件名,这个文件名对应的文件若存在则会被覆盖。也必须指定视频编解码器。编解码器的可用性根据系统不同而不同,下面是一些常用选项:
1. cv2.VideWriter_fourcc(‘I’,’4’,’2’,’0’):该选项是一个未压缩的YUV颜色编码,是4:2:0色度子采样。这种编码有很好的兼容性,但会产生较大文件,文件扩展名为.avi。
2. cv2.VideWriter_fourcc(‘P’,‘I’,‘M’,‘1’):该选项是MPEG-1编码类型,文件扩展名也是.avi。
3. cv2.VideWriter_fourcc(‘X’,’V’,’I’,’D’):该选项是MPEG-4编码类型,如果希望得到的视频的大小为平均值,推荐使用此选项,文件扩展名也是.avi。
4. cv2.VideWriter_fourcc(‘T’,’H’,’E’,’O’):该选项是Ogg Vorbis,文件扩展名应为.ogv。
5. cv2.VideWriter_fourcc(‘F’,’L’,’V’,’I’):该选项是Flash视频,文件扩展名为.flv。
另外帧速率和帧代销也必须设置,如果是从另一个视频文件复制视频帧,这些属性可以使用VideoCapture类的get()函数得到。(值的注意是如果VideoCapture类是从摄像头中获取的视频帧,get方法是不能反悔帧速率的准确值的。)
3、 OpenCV中的绘图函数
OpenCV中的绘图函数是在图像上绘制直线(line),圆(circle),矩形(rectangle),椭圆(ellipse),文字(putText)等,这些函数除需要自己特有的参数外,还有共同的参数如下:img:绘制图像的那副图像;color:绘制图形的颜色,以BGR为例,需要传入一个元祖,例如(255,0,0):代表蓝色。对于灰度图只需要传入灰度值;thickness:线条的粗细。如果给一个闭合图形设置为-1,那么这个图形就会被填充。默认值就是-1;linetype:线条的类型,有连接,抗锯齿等。默认情况是8表示连接。cv2.LINE_AA表示抗锯齿。这样子看起来非常平滑。
3.1 画线
画线需要知道线的起点和终点,例如画一个起点(0,0)和终点(100,100),线宽为5(像素),颜色为蓝色的线;例如:
import numpy as np
import cv2
img = np.zeros((400,400,3), np.uint8)# 创建一副图像
cv2.line(img, (0,0), (100,100), (255,0,0), 5)
3.2 画矩形
画一个矩形需要告诉函数左上角和右下角的顶点坐标。例如:画一个右上角为(50,100),左下角(150,200),颜色为绿色,线宽为3的矩形:
cv2.rectangle(img, (50,100), (150,200), (0,255,0), 3)
3.3 画圆
画圆需要告诉函数圆形的中心坐标和半径大小(单位是像素);例如:画一个圆心为(180,180),半径为80,红色的,填充的圆形:
cv2.circle(img, (180,180), 80, (0,0,255), -1)
3.4 画椭圆
画椭圆比较复杂,传入的参数也多,有椭圆的中心点坐标,长轴和短轴的长度,椭圆沿逆时针方向旋转的角度。椭圆沿顺时针方向的起始角度和结束角度,如果是0到360,就是整个椭圆,例如:画一个中心点为(300,300),长轴为50,短轴为25,旋转角度是50°。起始角度0到结束角度270:
cv2.ellipse(img, (300,300), (50,25), 50, 0, 270, (255,0,0), -1)
3.5 画多边形
画多边形需要指定每个顶点的坐标。用这些坐标构建成一个大小等于行数的数组(行数就是点的数目),这些数组的数据类型是int32;例如:
pts = np.array([[15,5],[200,30],[70,200],[50,100]], np.int32)
pts = pts.reshape(-1,1,2)
cv2.polyline(img, [pts], True, (0,255,255))
提示:如果第三个参数是False,就不是闭合的多边形,cv2.polylines()可以被用来画很多条线,只需要把画的线放在一个列表中,将其传给函数即可,每天先都可独立绘制,这会比cv2.line()速度快。
3.6 在图片上添加文字
绘制文字需要的参数如下:
1. 要绘制的文字
2. 绘制的位置
3. 字体的类型(需要系统支持的字体)
4. 字体的大小
5. 字体的一般属性如颜色,粗细,线条类型等
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img, "AMY", (100,200), font, 4, (255,255,255), 2)
cv2.namedWindow("example")
cv2.imshow("example", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
注意:OpenCV里画的图形是直接改变图像的值,所以不能恢复(可以在画之前备份即可)。效果如图:
4、 鼠标事件的处理
本节用到的函数是cv2.setMouseCallback();
可以通过如下方式获取所有的鼠标事件:打开Python的IDLE工具:
输入:(这些事件有左键、右键、双击、移动等)
import cv2
events = [i for i in dir(cv2) if 'EVENT' in i]
print(events)
这些事件什么意思,看名字大概就能猜到,再不懂可以百度一下就知道了,这里不一一解释了。
例如在一幅图上双击画一个圆:
import numpy as np
import cv2
img = np.zeros((512,512,3), np.uint8)
def draw_circle(event, x, y, flags, param):
print(event)
if event == cv2.EVENT_LBUTTONDBLCLK:#双击
cv2.circle(img, (x,y), 100, (255,0,0), 3)
cv2.namedWindow("example")
cv2.setMouseCallback("example", draw_circle)
while(1):
cv2.imshow("example", img)
if cv2.waitKey(20)&0xff == 27:
break
cv2.destroyAllWindows()
效果如图:双击即可画圆(当然你也可以自己定义鼠标事件要做的事情,只要在回调函数书写自己要做的即可)
**注意:**OpenCV不提供任何处理窗口事件的方法,例如,当点击窗口的关闭按钮时,并不能关闭应用程序。这也是为什么后面会使用PyQt结合OpenCV进行开发的原意之一。
5、 调色板
调色板这个还是比较还是比较简单的,就是用三个滑动条设置BGR的值来控制窗口的颜色。所以我们先用OpenCV自带的窗口部件创建一个简单的调色板。随后我们会用PyQt5做一个交互更好的调色板。
首先使用的是函数cv2.getTrackbarPos();这个函数的一个参数是滑动条的名字,第二个参数是滑动条被放置窗口的名字,第三个参数是滑动条的默认位置。第四个参数是滑动条的最大值,第五个参数是回调函数,每次滑动都会调用回调函数的。回调函数通常会含有一个默认参数,就是滑动条的位置。
import numpy as np
import cv2
def nothing(x):# 这里什么也不做
pass
# Create a black image
img = np.zeros((512,512,3), np.uint8)
cv2.namedWindow('image')
cv2.createTrackbar('R', 'image', 0, 255, nothing)
cv2.createTrackbar('G', 'image', 0, 255, nothing)
cv2.createTrackbar('B', 'image', 0, 255, nothing)
switch = "0:OFF\n1:ON"
cv2.createTrackbar(switch, 'image', 0, 1, nothing)
while(1):
cv2.imshow('image', img)
k = cv2.waitKey(1)&0xff
if k == 27:
break
r = cv2.getTrackbarPos('R', 'image')
g = cv2.getTrackbarPos('G', 'image')
b = cv2.getTrackbarPos('B', 'image')
s = cv2.getTrackbarPos(switch, 'image')
if s == 0:
img[:] = 0
else:
img[:] = [b,g,r]
cv2.destroyAllWindows()
效果如图:(可以看出这样的交互性太差,所有才要结合PyQt5做OpenCV的开发)
小结:就到这里了,到这里如果你已经掌握了以上内容,那么你就能进行视频以及图像文件的读取,保存,以及鼠标事件和在图像上做各种文字和图形了,下节将介绍如何修改像素以及图像的各种属性以及图像上的算术运算等操作,谢谢!
如您发现错误之处,可以指出来加以改正!谢谢