其实现在很多视觉任务都涉及到视频的读取以及分析,类似于各种制造厂、道路监控等等等,所有有必要学习并记录下视频帧的读取方式,方便回忆。
其实总的来说,读取一个视频截取其中的帧分为两步:(1)根据video路径,创建抓取视频帧的句柄(我习惯这么叫)(2)使用句柄以及视频帧下标(第几帧)获取。当前我这么说也很抽象,下面我们一步步来:
1. 根据video路径,创建抓取视频帧的句柄
import cv2
# 全局变量 video路径
video_path = '/xx/xx/xx/test.avi'
# (1) 获取抓取视频帧句柄
video_cap = cv2.VideoCapture(video_path)
# (2)该对象提供了默认函数isOpened()用来判断句柄是否获取成功
# 如果vedio路径不对,VideoCapture()返回None??返回啥存疑,具体代码没看到
if not self.video_cap.isOpened():
self.video_cap = None
else:
print('success')
2. 截取视频帧并保存
# 在我们截取视频帧之前,我们需要知道当前视频有多少帧
# cv2提供了默认的关键字 CAP_PROP_FRAME_COUNT 可以获得视频总的帧数
frame_len = int(video_cap.get(cv2.CAP_PROP_FRAME_COUNT))
# 获取视频帧速率 FPS
frame_fps = int(video_cap.get(cv2.CV_CAP_PROP_FPS))
# 获取视频帧宽度和高度
frame_width = int(video_cap.get(cv2.CV_CAP_PROP_FRAME_WIDTH))
frame_height = int(video_cap.get(cv2.CV_CAP_PROP_FRAME_HEIGHT))
# 有了这些信息,正式开始截取视频帧
# (3) 没有任何需求的情况下,循环获取每一帧。
while True:
# 句柄内置函数read(),返回两个参数,ret:是否截取成功 True or False,frame:截取的帧
ret, frame = video_cap.read()
if frame is None:
break
# 写入
cv2.imwrite(save_path, frame)
# 最后释放句柄
video.release()
3. 特殊需求
如果需要截取特定的帧?或者截取一系列特征的帧(帧下标用list存储),我们需要怎么办?其实也很简单。
# (4) 截取特定的帧 截取第idx个帧
# 句柄内置函数set() , 设置要获取的帧的索引号
# 注:CV_CAP_PROP_POS_FRAMES:下一个要解码/截取的帧的基于0的索引号
# set() 函数还是挺有说法的,如果你们有时间可以去看看,set有两个参数,有不同的组合方式。
video_cap.set(cv2.CAP_PROP_POS_FRAMES, idx)
# 句柄内置函数read()返回一个布尔值:是否截取成功;需要截取的视频帧。
bool, frame = video_cap.read()
# (5) 根据间隔interval,对整个视频截取frames
# 根据interval和视频总帧数,我们可以得到需要获得每一帧索引号的list
frames_list = [x0, x1, x2,..., xn]
# 重点来了,在这里你可以循环遍历 也可以 使用迭代器访问
# 这就要用到 def __next__(self)
class GetFrame:
def __init__(self):
self.idx = 1
def __next__(self):
if self.idx合法:
video_cap.set(cv2.CAP_PROP_POS_FRAMES, frames_list[idx])
bool, frame = video_cap.read()
self.idx += 1
return frame
gf = GetFrame()
for frame in gf:
print(frame)
# !发现了把,重写__next__()后,辅助for循环迭代遍历。
剩下的就没有什么了,这里面主要的几个函数,如果各位有兴趣可以去看看。