PyQt 5 开发之旅之 OpenCV的GUI 特性

本文来自作者离梦远在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 cv2img = cv2.imread('image/test2.jpg')cv2.imshow('demo', img)while True:if cv2.waitKey(20)&0xff == 27: breakcv2.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 millisecondscv2.CAP_PROP_POS_FRAMES(1):0-based index of the frame to be decoded/captured nextcv2.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 unsupportedcv2.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 cv2import 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 中的绘图函数

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 npimport cv2img = 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() 速度快。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180321B06ROC00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券