2 图像入门--视频
2.1 从相机中读取视频
要捕获视频,你需要创建一个 VideoCapture 对象。它的参数可以是设备索引或视频文件的名称。设备索引就是指定哪个摄像头的数字。正常情况下,一个摄像头会被连接。所以我简单地传0(或-1)。你可以通过传递1来选择第二个相机,以此类推。在此之后,你可以逐帧捕获。但是在最后,不要忘记释放俘虏。
代码如下:
import cv2 as cv
capture = cv.VideoCapture(0)
if not capture.isOpened():
print('cannot open camera')
exit()
while True:
# 逐帧捕捉
ret, frame = capture.read()
# 如果正确读取帧,ret为True
if not ret:
print("Can't receive frame (stream end). Exiting...")
break
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
# 显示结果帧
cv.imshow('frame', gray)
# 这里设的是每3ms读取一帧,按下ESC键退出
if cv.waitKey(3) & 0xFF == 27:
break
# 完成所有操作后,释放捕获器
capture.release()
cv.destroyAllWindows()
capture.read() 返回布尔值( True / False )。如果正确读取了帧,它将为True 。因此,你可以通过检查此返回值来检查视频的结尾。
有时,capture可能尚未初始化捕获。在这种情况下,此代码显示错误。你可以通过capture.isOpened()方法检查它是否已初始化。如果是True,那么确定。否则,使用capture.open()打开它。
你还可以使用capture.get(propId) 方法访问该视频的某些功能,其中propId是0到18之间的一个数字。每个数字表示视频的属性(如果适用于该视频),并且可以显示完整的详细信息在这里看到:cv::VideoCapture::get()。其中一些值可以使用capture.set(propId,value) 进行修改。value是你想要的新值。
这里附上propId中0~18这些数字代表的值:
参数 | propld | 功能 |
---|---|---|
cv2.CAP_PROP_POS_MSEC | 0 | 视频文件的当前位置(以毫秒为单位)或视频捕获时间戳 |
cv2.CAP_PROP_POS_FRAMES | 1 | 基于0的索引将被解码/捕获下一帧 |
cv2.CAP_PROP_POS_AVI_RATIO | 2 | 视频文件的相对位置:0 - 视频的开始,1 - 视频的结束 |
cv2.CAP_PROP_FRAME_WIDTH | 3 | 帧的宽度 |
cv2.CAP_PROP_FRAME_HEIGHT | 4 | 帧的高度 |
cv2.CAP_PROP_FPS | 5 | 帧速 |
cv2.CAP_PROP_FOURCC | 6 | 4个字符表示的视频编码器格式 |
cv2.CAP_PROP_FRAME_COUNT | 7 | 帧数 |
cv2.CAP_PROP_FORMAT | 8 | byretrieve()返回的Mat对象的格式 |
cv2.CAP_PROP_MODE | 9 | 指示当前捕获模式的后端特定值 |
cv2.CAP_PROP_BRIGHTNESS | 10 | 图像的亮度(仅适用于相机) |
cv2.CAP_PROP_CONTRAST | 11 | 图像对比度(仅适用于相机) |
cv2.CAP_PROP_SATURATION | 12 | 图像的饱和度(仅适用于相机) |
cv2.CAP_PROP_HUE | 13 | 图像的色相(仅适用于相机) |
cv2.CAP_PROP_GAIN | 14 | 图像的增益(仅适用于相机) |
cv2.CAP_PROP_EXPOSURE | 15 | 曝光(仅适用于相机) |
cv2.CAP_PROP_CONVERT_RGB | 16 | 表示图像是否应转换为RGB的布尔标志 |
cv2.CAP_PROP_WHITE_BALANCE | 17 | |
cv2.CAP_PROP_RECTIFICATION | 18 | 立体摄像机的整流标志 |
代码如下:
frame_width = capture.get(cv.CAP_PROP_FRAME_WIDTH)
frame_height = capture.get(cv.CAP_PROP_FRAME_HEIGHT)
print(frame_width, frame_height)
cv.CAP_PROP_FRAME_WIDTH和cv.CAP_PROP_FRAME_HEIGHT分别可以获取视频的宽度和高度。
如果想要修改宽高,就需要使用capture.set,直接在后面添加自己想要的数值就行了,像这样:
capture.set(cv.CAP_PROP_FRAME_WIDTH, 480)
capture.set(cv.CAP_PROP_FRAME_HEIGHT, 270)
注意:①capture.set只是用来设置摄像头采集图像的宽高的,自己放入的视频并不能通过set函数进行修改,我还一直用它来设置自己的视频,结果半天反应没有,原来这个只能用修改摄像头的;
②如果发现不能修改,可能你放在打开摄像头之前了,需要将它放在打开摄像头之后;
③再有一个就是如果出现错误,请确保使用任何其他相机应用程序(例如Linux中的Cheese)都可以正常使用相机。
2.2 从文件播放视频
它与从相机捕获相同,只是用视频文件名更改摄像机索引。另外,在显示框架时,请使用适当的时间cv.waitKey() 。如果太小,则视频将非常快,而如果太大,则视频将变得很慢(嗯,这就是显示慢动作的方式)。正常情况下25毫秒就可以了,这里涉及到帧率的相关知识,大家可以自行百度去查看。
代码如下:
import cv2 as cv
capture = cv.VideoCapture('03.mp4')
while capture.isOpened():
ret, frame = capture.read()
# 如果正确读取帧,ret为True
if not ret:
print("不能接收到帧,正在退出中。。。")
break
gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) # 将每一帧转换为灰度图像
cv.imshow('frame', gray)
if cv.waitKey(15) & 0xFF == ord('q'):
break
capture.release()
cv.destroyAllWindows()
注意:确保安装了正确的 ffmpeg 或 gstreamer 版本。有时,使用视频捕获(Video Capture)是一件令人头疼的事情,主要原因是错误地安装了 ffmpeg / gstreamer。
2.3 保存视频
我们都知道保存图像用cv.imwrite()就可以了,那么视频应该怎么保存呢?
保存视频我们使用的是cv.VideoWriter对象,主要参数有四个:
- 第一个参数是输出文件名(eg:out.avi)。
- 第二个参数是fourcc代码段,直接用cv.VideoWriter_fourcc()对象调用,是用于指定视频编解码器的4字节代码,可以在fourcc.org这里找到详细的代码段。
- 第三个参数是传递帧率的数量,单位fps。
- 第四个参数是传递帧率的大小。
fourcc代码段详细参数以及使用方法这里就不说了,这里涉及到视频编解码知识,大家可以查找相关资料。
直接上代码:
import cv2 as cv
capture = cv.VideoCapture('03.mp4')
print(capture.get(cv.CAP_PROP_FRAME_WIDTH)) # 960
print(capture.get(cv.CAP_PROP_FRAME_HEIGHT)) # 540
# 定义编解码器并创建VideoWriter对象
fourcc = cv.VideoWriter_fourcc(*'XVID')
save_video = cv.VideoWriter('out.avi', fourcc, 500.0, (960, 540))
while capture.isOpened():
ret, frame = capture.read()
if not ret:
print("不对,我看不见视频啊。。。重新换一个试试?")
break
frame = cv.flip(frame, 0)
# 写翻转的框架
save_video.write(frame)
cv.imshow('frame', frame)
if cv.waitKey(1) & 0xff == 27:
break
# 完成保存之后释放所有内容
capture.release()
save_video.release()
cv.destroyAllWindows()
注意:相信在这里,大家保存视频会有很多问题,打不开,报各种错误,这里列举了一下:
1. 在 VideoWriter 中指定的尺寸要和 write() 中写进去的一样,不然视频会存储失败的。
2. 仔细看自己的代码while循环里面是否写错了,一般都是这里写错了。
3. 根据自己电脑系统,选择合适的fourcc代码段。
3. 若觉得都没有问题,还是无法打开,将编译环境退出一次或者重启,视频就彻底生成成功并且可以播放了