本文来自作者 离梦远 在 GitChat 上分享 「PyQt 5 开发之旅之 OpenCV 的 GUI 特性」
编辑 | 哈比
本篇适合 OpenCV(Python 版)初学者入门使用。如果您对 OpenCV 比较了解,可以略过。
学习本文当然还要有一定的 Python 基础功底,至于 Python 2 还是 Python 3 无关紧要。
本文重点讲解 OpenCV 的 GUI 特性,还有部分 PyQt5 相关的内容,如果想动手敲代码的话一定要搭建好开发环境,关于开发环境我在另一场 Chat 有详细的介绍,本文不再讲解。
讲解过程中会做一些显示效果来说明,为了方便会先使用 OpenCV 自带的显示功能进行显示,后面总结的时候会结合 PyQt5 和 Matplotlib 显示。
开发环境搭建请参考 https://goo.gl/RnNSGy。
函数 cv2.imread(),有两个参数,参数 1 是要读入的图像文件(包含路径),参数 2 告诉函数应该如何读取图像(可不填)。
注意:图像的路径错误时,OpenCV 不会提醒。
下面列出读出方式:
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)和通道(Channel)的图像读取之间的转换关系。
显示图像就比较简单了,首先可以使用 OpenCV 自带的窗口显示,函数就是 cv2.imshow()。
第一个参数是窗口的名字,第二个参数是要显示的图像了,也就是 cv2.imread() 函数的返回值。
当然为了让显示窗口保持住程序不能运行结束需要使用 cv2.waitKey(),最后结束还要使用 cv2.destroyAllWindows() 销毁。
还有种方法就是使用 Matplotlib 来显示,这个要结合 PyQt5 在自己想要的地方进行显示的,显示过程和前面一个过程差不多。
但是要注意一点的是 Matplotlib 显示的彩色图像和 OpenCV 显示时候的 RGB 顺序不一样,所以在显示前要转换一下,这个在后面的例子中会详解。
保存图像使用函数 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)
效果如下图所示:
获取视频的函数为 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
在我们捕获视频,并对每一帧都进行加工之后我们想要保存这个视频,对于图片来说很简单使用 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()
OpenCV 中的绘图函数是在图像上绘制直线(line)、圆(circle)、矩形(rectangle)、椭圆(ellipse)、文字(putText)等,这些函数除需要自己特有的参数外,还有共同的参数如下:
img:绘制图像的那副图像;
color:绘制图形的颜色,以 BGR 为例,需要传入一个元祖,例如 (255,0,0),代表蓝色。对于灰度图只需要传入灰度值;
thickness:线条的粗细。如果给一个闭合图形设置为-1,那么这个图形就会被填充。默认值就是-1;
linetype:线条的类型,有连接、抗锯齿等。默认情况是 8 表,示连接。cv2.LINE_AA 表示抗锯齿。这样子看起来非常平滑。
画线需要知道线的起点和终点,例如画一个起点 (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)
画一个矩形需要告诉函数左上角和右下角的顶点坐标。例如,画一个右上角为 (50,100),左下角 (150,200),颜色为绿色,线宽为 3 的矩形,代码如下:
cv2.rectangle(img, (50,100), (150,200), (0,255,0), 3)
画圆需要告诉函数圆形的中心坐标和半径大小(单位是像素)。例如,画一个圆心为 (180,180),半径为 80,红色填充的圆形,代码如下:
cv2.circle(img, (180,180), 80, (0,0,255), -1)
画椭圆比较复杂,传入的参数也多,有椭圆的中心点坐标,长轴和短轴的长度,椭圆沿逆时针方向旋转的角度。
椭圆沿顺时针方向的起始角度和结束角度,如果是 0 到 360,就是整个椭圆,例如画一个中心点为 (300,300),长轴为 50,短轴为 25,旋转角度是 50°。
起始角度 0 到结束角度 270,代码如下:
cv2.ellipse(img, (300,300), (50,25), 50, 0, 270, (255,0,0), -1)
画多边形需要指定每个顶点的坐标。用这些坐标构建成一个大小等于行数的数组(行数就是点的数目),这些数组的数据类型是 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() 速度快。
扫描下方二维码
阅读完整原文
并与作者交流