简介
在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都可以。
常用方法
检查是否初始化成功
说明:判断视频对象是否成功读取,成功读取视频对象返回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,表示延时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 条件句成立。
释放资源
使用完摄像头资源之后,需要释放该资源,即关闭摄像头:
关闭所有图像窗口
属性设置
有时,我们需要获取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) 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
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.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
while True: ret, frame = cap.read() if ret: frame_rate = int(int(fps) * time_rate / 2.5) if c % frame_rate == 0: print("开始截取视频第 " + str(c) + " 帧") save_image_path = os.path.join(save_dir, f'{c}.jpg') 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博客