番外 2. OpenCV 中摄像头捕获与视频处理与常见问题解决方案
本系列专栏写作方式
本系列专栏写作将采用首创的问答式写作形式,快速让你学习到 OpenCV 的初级、中级、高级知识。
2. OpenCV 中摄像头捕获与视频处理
OpenCV 除了应用在图像处理领域外,还会应用到视频处理领域,接下来我们就将学习到,如何通过 Python OpenCV 对摄像头捕获或者视频文件进行处理。
视频文件将从三个方向入手,分别是读取文件,显示视频,保存视频。
本文将为你核心解决以下 2 个函数:<kbd>cv2.VideoCapture</kbd> 与 <kbd>cv2.VideoWrite</kbd>,基于这 2 个函数,会衍生出其它相关函数,具体参照下文。
在 OpenCV 中操作摄像头相关注意事项和解决方案
摄像头相较于视频,差异在一个是实时图像,一个是既定内容。如果想要捕获到视频,用到的是<kbd>cv2.VideoCapture</kbd> 函数,该函数的第一个参数是设备的索引号,如果你使用的是笔记本电脑,默认一般是 0,表示的内置摄像头,如果链接了外置,可以修改该数字即可。
最简单的测试代码如下:
该代码在运行时,如果你电脑未安装摄像头或者驱动异常,都会导致报错,例如下述 BUG
该问题虽然报错出现在 <kbd>cv2.cvtColor</kbd>函数,但是原因是 frame
为空,即<kbd>cap.read()</kbd>读取失败导致的。
这里在实际编码过程中,需要增加一个判断,<kbd>cap.read()</kbd> 函数会返回一个状态布尔值,如果读取到数据,返回真,否则返回假,测试如下代码(下述代码的停止,需要按键盘上的<kbd>CTRL+C</kbd> ):
测试完毕之后,我们修改本文一开始的代码,让其更加健壮。
这里存在一个常见,但是及容易被忽视的问题,就是很多时候,我们并不知道电脑上有没有摄像头,或者摄像头的设备号,该如何进行操作。
你可以按照下述代码进行检测:
以上代码运行的原理是,按照顺序依次打开设备 0~5
,当发现摄像头被成功打开,返回跳出。
上述代码还提及了一个新的函数 <kbd>cap.isOpened</kbd>,该函数用来检测摄像头是否初始化(能被打开),初始化成功返回 True。
在 OpenCV 中操作视频文件相关注意事项和解决方案
其实操作视频文件与操作摄像头操作基本一致,唯一修改的就是<kbd>cv2.VideoCapture</kbd> 函数设备号即可。
这里将设备号修改为视频文件路径。
接下来,我们先看一段代码,认识基本用法。
其中最需要注意的一个地方,不是 <kbd>cv2.VideoCapture('test.mp4')</kbd> 函数读取文件,而是 <kbd>cv2.waitKey(25)</kbd>,这个地方需要设置好对应的视频,如果数值特别小,例如 1
,视频就会快速播放,设置太高播放又会变慢,一般建议设置为 25
。
当然,上述代码注释的部分,如果取消,就会变成一个灰度视频。
甚至可以直接将视频进行翻转,用到函数为:<kbd>cv2.flip(frame, 0)</kbd>,
上述代码运行如下:
接下来我们用视频来学习一下一些操作属性的方法。
<kbd>cv2.VideoCapture.get(propId)</kbd> 可以访问视频的某些功能,其中 <kbd>propId</kbd> 是一个从 0 到 18 的数字,每个数字表示视频的属性。
取值清单如下(该清单只作为查询参考使用):
0 - <kbd>cv2.CAP_PROP_POS_MSEC</kbd>: 视频文件的当前位置(ms);
1 - <kbd>cv2.CAP_PROP_POS_FRAMES</kbd>:从 0 开始索引帧,帧位置;
2 - <kbd>cv2.CAP_PROP_POS_AVI_RATIO</kbd>:视频文件的相对位置(0 表示开始,1 表示结束);
3 - <kbd>cv2.CAP_PROP_FRAME_WIDTH</kbd>:视频流的帧宽度;
4 - <kbd>cv2.CAP_PROP_FRAME_HEIGHT</kbd>: 视频流的帧高度;
5 - <kbd>cv2.CAP_PROP_FPS</kbd>:帧率;
6 - <kbd>cv2.CAP_PROP_FOURCC</kbd> : 编解码器四字符代码;
7 - <kbd>cv2.CAP_PROP_FRAME_COUNT</kbd> :视频文件的帧数;
8 - <kbd>cv2.CAP_PROP_FORMAT</kbd>:retrieve()返回的 Mat 对象的格式;
9 - <kbd>cv2.CAP_PROP_MODE</kbd> :后端专用的值,指示当前捕获模式;
10 - <kbd>cv2.CAP_PROP_BRIGHTNESS</kbd> :图像的亮度,仅适用于支持的相机;
11 - <kbd>cv2.CAP_PROP_CONTRAST</kbd> :图像对比度,仅适用于相机;
12 - <kbd>cv2.CAP_PROP_SATURATION</kbd>:图像饱和度,仅适用于相机;
13 - <kbd>cv2.CAP_PROP_HUE</kbd>:图像色调,仅适用于相机;
14 - <kbd>cv2.CAP_PROP_GAIN</kbd>:图像增益,仅适用于支持的相机;
15 - <kbd>cv2.CAP_PROP_EXPOSURE</kbd>:曝光,仅适用于支持的相机;
16 - <kbd>cv2.CAP_PROP_CONVERT_RGB</kbd>:布尔标志,指示是否应将图像转换为 RGB;
17 - <kbd>cv2.CAP_PROP_WHITE_BALANCE</kbd>:目前不支持;
18 - <kbd>cv2.CAP_PROP_RECTIFICATION</kbd>:立体摄像机的整流标志。
有了上述清单,可以获取视频较多的属性值了,例如获取宽度与高度。
有 <kbd>get</kbd> 方法,对应的就存在 <kbd>set</kbd> 函数,函数原型如下:
但这个地方要注意下,上面 <kbd>set</kbd> 函数只对采集摄像头有用,如果读取的是视频文件,上述内容就不在起作用了。
如果你还是希望实现修改视频文件的窗口大小,那可以使用下述方案。
如果想希望查看视频播放的当前位置、帧率、帧数,可以直接使用下述代码。
当然,使用属性值也可以。
在 OpenCV 中捕获视频并保存
图片的保存使用函数 <kbd>cv2.imwrite</kbd>即可实现,但视频保存,需要与<kbd>cv2.VideoCapture</kbd>对应着,创建一个 <kbd>VideoWriter</kbd>对象,而且还需要确定文件的名称,视频 <kbd>FourCC</kbd> 编码,频率,帧大小,<kbd>isColor</kbd>标签,该标签如果为 True 则保存彩色图,否则是灰度图。
首先对 <kbd>FourCC</kbd> 进行一下说明,该编码是一个 4 字节码,表示的是视频编码格式。
例如对于 <kbd>MJPG</kbd>,它有两种写法。
注意这是 <kbd>OpenCV 3</kbd> 写法,网上现在大多数博客都是 <kbd>OpenCV 2</kbd> 写法。
常见编码说明:
<kbd>MJPG</kbd>编码器编码的视频非常大;
<kbd>X264</kbd> 编码器编码的视频很小;
<kbd>XVID</kbd>编码器优先选择,质量较高且体积较小。
<kbd>cv2.VideoWriter</kbd>函数原型如下:
相关参数:
<kbd>filename</kbd>:视频保存文件名称;
<kbd>fourcc</kbd>:视频编解码器的 4 字节代码;
<kbd>fps</kbd>:帧率;
<kbd>frameSize</kbd>:帧大小;
<kbd>isColor</kbd>:如果为 True,则视频为彩色,否则为灰度视频,默认为 True。
测试代码如下,代码之后跟相关问题的说明。
在调用函数 cv2.VideoWriter("test1.avi", fourcc, fps, (width, height))
的时候,注意需要 (width, height)
必须是整数,需要强制转换一下。
其中 20 是 fps ,如果想保存成灰度视频,按照下述代码修改即可。
如果在编码时出现如下错误,注意是 frameSize
参数设置的问题
对应的代码位置按照如下修改即可
下一个常见的问题是,如果不是读取视频文件,直接采集的摄像头数据,使用 <kbd>fps = cap.get(5)</kbd> 是无法获取到具体的 fps 值的,此时只能进行手动设定。
该值的设定需要依据自己电脑的配置,一般设置为 10~20 即可。
版权声明: 本文为 InfoQ 作者【梦想橡皮擦】的原创文章。
原文链接:【http://xie.infoq.cn/article/ce4e913b72122aa1b9a42d35a】。文章转载请联系作者。
评论