opencv视频读写

简介

opencv中关于视频的读操作是通过VideoCapture类来完成的;关于视频的写操作是通过VideoWriter类来实现的。

VideoCapture

VideoCapture既支持从视频文件读取,也支持直接从摄像机(比如电脑自带摄像头)中读取。

要想获取视频需要先创建一个 VideoCapture 对象,VideoCapture类提供了构造函数:cv2.VideoCapture()

1
2
cap = cv2.VideoCapture(0)  # 读取摄像头
cap = cv2.VideoCapture('video.mp4') # 读取视频文件

摄像头ID号默认值为-1,表示随机选取一个摄像头。

如果你运行该程序的设备有多个摄像头,则用0表示设备内置的第一个摄像头,1表示设备的第二个摄像头,依次类推。如果一般台式机只有一个摄像头,用0或者-1都可以。

常用方法

检查是否初始化成功

1
cap.isOpened()

说明:判断视频对象是否成功读取,成功读取视频对象返回True

当我们初始化摄像头失败后,我们还可以使用函数cv2.VideoCapture.open()打开摄像头:

1
2
3
4
cap = cv2.VideoCapture(0)

if cap.isOpened() is False:
result = cap.open(0)

其中,open参数也是摄像头的ID号,与前面构造函数一样。同时,使用open()函数打开摄像头后,也返回成功True或失败False

捕获帧

1
retval, frame = cap.read()

说明:

  • 按帧读取视频,返回值retval是布尔型,正确读取则返回True
  • 读取失败或读取视频结尾则会返回False
  • frame为每一帧的图像,这里图像是三维矩阵,即frame.shape = (640,480,3),读取的图像为BGR格式。

等待键盘输入

waitKey()方法本身表示等待键盘输入

1
key = cv2.waitKey(1)

说明:

  • 参数1,表示延时1ms切换到下一帧。
  • 参数为0,表示显示当前帧,相当于视频暂停。
  • 参数过大如cv2.waitKey(1000),会因为延时过久而卡顿感觉到卡顿。

示例:

1
2
3
4
5
6
7
8
9
10
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if ret:
cv2.imshow('Video', frame)
key = cv2.waitKey(1)
if key == 27:
break
cap.release()
cv2.destroyAllWindows()
  • key得到的是键盘输入的 ASCII 码,esc 键对应的 ASCII 码是 27,即当按 esc 键时 if 条件句成立。

释放资源

使用完摄像头资源之后,需要释放该资源,即关闭摄像头:

1
cap.release()

关闭所有图像窗口

1
cv2.destroyAllWindows()

属性设置

有时,我们需要获取cv2.VideoCapture摄像头的一些属性,比如其分辨率,像素。

OpenCV提供了cv2.VideoCapture.get()函数:

1
cameraInfo = cap.get(propId)

参数propId对应着就是cv2.VideoCapture类对象的属性。

1
2
3
4
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))  # 获取视频的宽度
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 获取视频的高度
fps = cap.get(cv2.CAP_PROP_FPS) # 获取视频的帧率
fourcc = int(cap.get(cv2.CAP_PROP_FOURCC)) # 视频的编码

grab() 与 retrieve()

一般情况下,我们都只使用一个摄像头,上面这些步骤与函数完全能够应付。但是,如果需要同步一组或一个多头摄像头,就需要使用VideoCapture.grab()VideoCapture.retrieve()函数。可以把函数VideoCapture.read()理解为这两个函数的组合。

函数grab()用于指向下一帧,函数retrieve()用来解码并返回一帧。所以,对于一组摄像头我们可以这样操作:

1
2
3
4
5
6
7
8
9
cap0 = cv2.VideoCapture(0)
cap1 = cv2.VideoCapture(0)

isCamera0 = cap0.grab()
isCamera1 = cap1.grab()

if isCamera0 and isCamera1:
frame0 = cap0.retrieve()
frame1 = cap1.retrieve()

示例

读取摄像头并保存为视频

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def videocapture():
cap=cv2.VideoCapture(0) # 生成读取摄像头对象
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # 获取视频的宽度
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 获取视频的高度
fps = cap.get(cv2.CAP_PROP_FPS) # 获取视频的帧率
fourcc = int(cap.get(cv2.CAP_PROP_FOURCC)) # 视频的编码
# 定义视频对象输出
writer = cv2.VideoWriter("video_result.mp4", fourcc, fps, (width, height))
while cap.isOpened():
ret, frame = cap.read() # 读取摄像头画面
cv2.imshow('video', frame) # 显示画面
key = cv2.waitKey(24)
writer.write(frame) # 视频保存
# 按 Q 退出
if key == ord('q'):
break
cap.release() # 释放摄像头
cv2.destroyAllWindows() # 释放所有显示图像窗口

通过帧数间隔抽取图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def to_img(mp4_path):
cap = cv2.VideoCapture(mp4_path)
c = 1
frame_rate = 100 # 帧数截取间隔(每隔100帧截取一帧)

while True:
ret, frame = cap.read()
if ret:
if c % frame_rate == 0:
print("开始截取视频第 " + str(c) + " 帧")

# 图片保存到本地
save_image_path = os.path.join(save_dir, f'{c}.jpg')
# cv2.imwrite(save_image_path, frame) # 不能包含中文
cv2.imencode('.jpg', frame)[1].tofile(save_image_path)
c += 1
else:
break
cap.release()

通过时间间隔抽取图片

假如你想每隔10秒截取一帧,那么就相当于你要每隔( FPS * 10 )帧截取一帧图像

首先你需要知道你的视频的帧率(FPS)是多少,通过opencv获取:

1
2
3
cap = cv2.VideoCapture("./query_video/test_video_0.mp4")

fps = cap.get(cv2.CAP_PROP_FPS)

结合:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def to_img(mp4_path):
cap = cv2.VideoCapture(mp4_path)
fps = cap.get(cv2.CAP_PROP_FPS)
c = 1
time_rate = 10 # 帧数截取间隔(每隔10秒截取一帧)

while True:
ret, frame = cap.read()
if ret:
frame_rate = int(int(fps) * time_rate / 2.5) # 如果视频2.5倍速加速过
if c % frame_rate == 0:
print("开始截取视频第 " + str(c) + " 帧")
# 图像保存到本地
save_image_path = os.path.join(save_dir, f'{c}.jpg')
# cv2.imwrite(save_image_path, frame) # 不能包含中文
cv2.imencode('.jpg', frame)[1].tofile(save_image_path)
c += 1
cv2.waitKey(0)
else:
print("截取完毕")
break
cap.release()

参考:

cv2.VideoCapture读取视频或摄像头,并进行保存帧图像或视频-CSDN博客

opencv学习—VideoCapture 类基础知识-CSDN博客


opencv视频读写
https://blog-21n.pages.dev/2023/08/09/opencv视频读写/
作者
Neo
发布于
2023年8月9日
许可协议