# 视频入门 ## 目标 在本次会议中: * 学习加载视频、显示视频和保存视频。 * 学习用相机捕捉并显示。 * 你要学习这些函数:**[cv.VideoCapture()](https://docs.opencv.org/4.0.0/d8/dfe/classcv_1_1VideoCapture.html "Class for video capturing from video files, image sequences or cameras. ")**,**[cv.VideoWriter()](https://docs.opencv.org/4.0.0/dd/d9e/classcv_1_1VideoWriter.html "Video writer class. ")** ## 从相机捕捉视频 通常,我们用相机捕捉直播。OpenCV 为此提供了一个非常简单的接口。我们用相机捕捉一个视频(我用的电脑内置摄像头),将它转换成灰度视频并显示。仅仅是一个简单的开始。 去获取一个视频,你需要创建一个**VideoCapture**对象。它的参数可以是设备索引或者一个视频文件名。设备索引仅仅是摄像机编号。通常会连接一台摄像机(as in my case)。所以我只传了 0(或者-1)。你可以通过传 1 来选择第二个摄像机,以此类推。之后,你能逐帧捕获。但是最后,不要忘记释放这个 Capture 对象。 ```python import numpy as np import cv2 as cv cap = cv.VideoCapture(0) while(True): # 一帧一帧捕捉 ret, frame = cap.read() # 我们对帧的操作在这里 gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) # 显示返回的每帧 cv.imshow('frame',gray) if cv.waitKey(1) & 0xFF == ord('q'): break # 当所有事完成,释放 VideoCapture 对象 cap.release() cv.destroyAllWindows() ``` **[cap.read()](https://docs.opencv.org/4.0.0/d2/d75/namespacecv.html#a9afba2f5b9bf298c62da8cf66184e41f)** 返回一个 bool 值(`True`/`False`)。如果加载成功,它会返回`True`。因此,你可以通过这个返回值判断视频是否结束。 有时,cap 可能没有初始化 capture。在这种情况下,此代码显示错误。你可以通过该方法 **cap.isOpened()** 检查它是否初始化。如果它是 True,那么是好的,否则用 **[cap.open()](https://docs.opencv.org/4.0.0/d6/dee/group__hdf5.html#ga243d7e303690af3c5c3686ca5785205e "Open or create hdf5 file. ")** 打开在使用。 你也可以通过使用 **cap.get(propId)** 函数获取一些视频的特征,这里的 propld 是一个 0-18 的数字,每个数字代表视频的一个特征 (如果这个视频有),或者使用 [cv::VideoCapture::get()](https://docs.opencv.org/4.0.0/d8/dfe/classcv_1_1VideoCapture.html#aa6480e6972ef4c00d74814ec841a2939 "Returns the specified VideoCapture property. ") 获取全部细节。它们中有些值可以使用 **cap.set(propId, value)** 修改。Value 就是你想要的新值 例如:我可以用 **cap.get([cv.CAP_PROP_FRAME_WIDTH](https://docs.opencv.org/4.0.0/d4/d15/group__videoio__flags__base.html#ggaeb8dd9c89c10a5c63c139bf7c4f5704dab26d2ba37086662261148e9fe93eecad "Width of the frames in the video stream. "))** 获得宽, **cap.get([cv.CAP_PROP_FRAME_HEIGHT](https://docs.opencv.org/4.0.0/d4/d15/group__videoio__flags__base.html#ggaeb8dd9c89c10a5c63c139bf7c4f5704dad8b57083fd9bd58e0f94e68a54b42b7e "Height of the frames in the video stream. "))** 获得高。它返回的是 640x480,但是我想把它修改为 320x240。仅使用 **ret = cap.set([cv.CAP_PROP_FRAME_WIDTH](https://docs.opencv.org/4.0.0/d4/d15/group__videoio__flags__base.html#ggaeb8dd9c89c10a5c63c139bf7c4f5704dab26d2ba37086662261148e9fe93eecad "Width of the frames in the video stream. "),320)** 和 **ret = cap.set([cv.CAP_PROP_FRAME_HEIGHT](https://docs.opencv.org/4.0.0/d4/d15/group__videoio__flags__base.html#ggaeb8dd9c89c10a5c63c139bf7c4f5704dad8b57083fd9bd58e0f94e68a54b42b7e "Height of the frames in the video stream. "),240)** **Note** * 如果给你报错了,确保用任意其他的相机程序 (如 Linux 下的 Cheese 程序) 可以正常工作 ## 播放视频文件 它和从相机捕获一样,只需要用视频文件名更改相机索引。同时显示 frame,为 **[cv.waitKey()](https://docs.opencv.org/4.0.0/d7/dfc/group__highgui.html#ga5628525ad33f52eab17feebcfba38bd7 "Waits for a pressed key. ")** 使用合适的时间。如果它太小,视频将非常快,如果太大,视频将很慢 (嗯,这就是如何显示慢动作)。正常情况下,25 毫秒就可以了。 ```python import numpy as np import cv2 as cv cap = cv.VideoCapture('vtest.avi') while(cap.isOpened()): ret, frame = cap.read() gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) cv.imshow('frame',gray) if cv.waitKey(1) & 0xFF == ord('q'): break cap.release() cv.destroyAllWindows() ``` **Note** * 确保 ffmpeg 和 gstreamer 安装合适的版本。有时,使用 Video Capture 是比较头痛的,主要是因为错误的安装 ffmpeg 或 gstreamer。 ## 保存视频 我们捕获视频,逐帧处理然后保存下来。对于图像来说,是非常的简单,就用 **[cv.imwrite()](https://docs.opencv.org/4.0.0/d4/da8/group__imgcodecs.html#gabbc7ef1aa2edfaa87772f1202d67e0ce "Saves an image to a specified file. ")**。这里需要做更多的工作。 这次我们创建一个 **VideoWriter** 对象。我们应该指定输出文件的名字 (例如:output.avi)。然后我们应该指定 **FourCC** 码 (下一段有介绍)。然后应该传递每秒帧数和帧大小。最后一个是 **isColor** flag。如果是 True,编码器期望彩色帧,否则它适用于灰度帧。 **[FourCC](http://en.wikipedia.org/wiki/FourCC)** 是用于指定视频解码器的 4 字节代码。这里 **[fourcc.org](http://www.fourcc.org/codecs.php)** 是可用编码的列表。它取决于平台,下面编码就很好。 * In Fedora: DIVX, XVID, MJPG, X264, WMV1, WMV2. (XVID 是最合适的. MJPG 结果比较大. X264 结果比较小) * In Windows: DIVX (还需要测试和添加跟多内容) * In OSX: MJPG (.mp4), DIVX (.avi), X264 (.mkv). 对于 MJPG, FourCC 的代码作为 **cv.VideoWriter_fourcc('M','J','P','G')** 或 **cv.VideoWriter_fourcc(*'MJPG')** 传递。 下面的代码从相机捕获,在垂直方向翻转每一帧然后保存它。 ```python import numpy as np import cv2 as cv cap = cv.VideoCapture(0) # 声明编码器和创建 VideoWrite 对象 fourcc = cv.VideoWriter_fourcc(*'XVID') out = cv.VideoWriter('output.avi',fourcc, 20.0, (640,480)) while(cap.isOpened()): ret, frame = cap.read() if ret==True: frame = cv.flip(frame,0) # 写入已经翻转好的帧 out.write(frame) cv.imshow('frame',frame) if cv.waitKey(1) & 0xFF == ord('q'): break else: break # 释放已经完成的工作 cap.release() out.release() cv.destroyAllWindows() ``` ## 其他资源 ## 练习