def frame_extraction(video_path, short_side):
"""Extract frames given video_path.
Args:
video_path (str): The video_path.
"""
# Load the video, extract frames into ./tmp/video_name
target_dir = osp.join('./tmp', osp.basename(osp.splitext(video_path)[0]))
os.makedirs(target_dir, exist_ok=True)
# Should be able to handle videos up to several hours
frame_tmpl = osp.join(target_dir, 'img_{:06d}.jpg')
vid = cv2.VideoCapture(video_path)
frames = []
frame_paths = []
flag, frame = vid.read()
cnt = 0
new_h, new_w = None, None
while flag:
if new_h is None:
h, w, _ = frame.shape
new_w, new_h = mmcv.rescale_size((w, h), (short_side, np.Inf))
frame = mmcv.imresize(frame, (new_w, new_h))
frames.append(frame)
frame_path = frame_tmpl.format(cnt + 1)
frame_paths.append(frame_path)
cv2.imwrite(frame_path, frame)
cnt += 1
flag, frame = vid.read()
return frame_paths, frames
frame_tmpl = osp.join(target_dir, 'img_{:06d}.jpg')
vid = cv2.VideoCapture(video_path)
frames = []
frame_paths = []
flag, frame = vid.read()
cnt = 0
new_h, new_w = None, None
这段代码的目的是从视频中提取帧,并将每个帧保存为图像文件。
-
frame_tmpl = osp.join(target_dir, 'img_{:06d}.jpg')
:定义了保存帧图像的文件名模板。{:06d}
表示将帧序号格式化为6位的数字,例如000001
、000002
等。 -
vid = cv2.VideoCapture(video_path)
:使用 OpenCV 的VideoCapture
类打开视频文件,video_path
是视频文件的路径。 -
frames
和frame_paths
:分别是用于存储帧图像和帧图像文件路径的列表。 -
flag, frame = vid.read()
:使用read()
方法从视频中读取下一帧图像。flag
是一个布尔值,表示读取是否成功,frame
是读取到的图像。 -
cnt
:计数器,用于记录已读取的帧数。 -
new_h, new_w = None, None
:用于存储图像的新高度和宽度,这里初始化为None
。
while flag:
if new_h is None:
h, w, _ = frame.shape
new_w, new_h = mmcv.rescale_size((w, h), (short_side, np.Inf))
frame = mmcv.imresize(frame, (new_w, new_h))
frames.append(frame)
frame_path = frame_tmpl.format(cnt + 1)
frame_paths.append(frame_path)
cv2.imwrite(frame_path, frame)
cnt += 1
flag, frame = vid.read()
return frame_paths, frames
这段代码是一个循环,用于读取视频的每一帧,并对每一帧进行处理和保存。
-
while flag:
:循环条件,只要读取到有效的帧图像,即flag
为True
,就进入循环。 -
if new_h is None:
:这是一个条件判断语句,用于检查是否需要调整帧图像的大小。如果new_h
是None
,表示还没有计算出新的高度和宽度。 -
h, w, _ = frame.shape
:获取当前帧图像的高度和宽度。frame.shape
返回一个元组,包含图像的高度、宽度和通道数(在这里用不到)。 -
new_w, new_h = mmcv.rescale_size((w, h), (short_side, np.Inf))
:使用mmcv.rescale_size()
函数计算新的调整后的宽度和高度。该函数接受两个参数,第一个参数是原始图像的宽度和高度,第二个参数是目标尺寸的限制(这里使用short_side
作为限制,另一边的尺寸不限制)。计算得到的新的宽度和高度将赋值给new_w
和new_h
。 -
frame = mmcv.imresize(frame, (new_w, new_h))
:使用mmcv.imresize()
函数调整帧图像的大小。该函数接受两个参数,第一个参数是原始图像,第二个参数是目标尺寸的宽度和高度。将调整后的帧图像赋值给frame
。 -
frames.append(frame)
:将处理后的帧图像添加到frames
列表中。 -
frame_path = frame_tmpl.format(cnt + 1)
:使用帧序号格式化帧图像的文件路径。frame_tmpl
是保存帧图像的文件名模板,使用format()
方法将帧序号格式化为文件路径。 -
frame_paths.append(frame_path)
:将帧图像文件路径添加到frame_paths
列表中。 -
cv2.imwrite(frame_path, frame)
:使用cv2.imwrite()
函数将帧图像保存为图像文件。接受两个参数,第一个参数是保存的文件路径,第二个参数是要保存的图像。 -
cnt += 1
:计数器自增,用于记录已处理的帧数。 -
flag, frame = vid.read()
:读取视频的下一帧图像,将读取结果赋值给flag
和frame
。
最终,该循环会读取视频的每一帧图像,对每一帧进行处理和保存,并将帧图像文件路径和帧图像本身分别存储在 frame_paths
和 frames
列表中。循环结束后,函数会返回 frame_paths
和 frames
作为结果。
参考: