最近在项目中遇到了这样一个需求,要求读取视频,根据视频帧数剪辑出多个时长相对固定的视频片段(如第100、575、920帧的前后50帧)。该需求通过cv2实现,前后大约修改过三次:
1、第一种方法是通过多次重复读取视频,每次截取相应的帧数片段,这种方法最为简单但显然效率极其低下,在较长视频处理的场景下是不可接受的;
2、第二种方法是读取视频,将需要截取的视频图像保存到列表中,再通过videowriter将图像写入,这种方法处理短时长视频可以接受,在处理较长且分辨率大的视频时有内存溢出风险;
3、第三种方法为创建多个videowriter,本文主要介绍该方法,代码如下
`
import cv2
import datetime
def video_cut(frame_list,video_path,save_path):
'''
:param frame_list: 需要剪辑视频的帧数定位列表,如需要剪辑100,500,800的前60帧后40帧,输入[100,500,800]
:param video_path: 待剪辑视频路径
:param save_path: 视频片段保存路径
'''
cap = cv2.VideoCapture(video_path)
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
#FPS = 20 # int(round(cap.get(cv2.CAP_PROP_FPS)))
frame_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
frame_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
output_list = []
frame_id = 0
for i in range(len(frame_list)):
img_pre_fix = '_%s' % datetime.datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
output_list.append(cv2.VideoWriter(
save_path + '/' + 'video' + '_' + str(frame_list[i]) + img_pre_fix + '.mp4',fourcc, 20,(frame_width, frame_height)))
print('video cut generate')
while True:
ret,frame = cap.read()
if not ret:
break
frame_id += 1
#print(frame_id)
for num,id in enumerate(frame_list):
if id-60 <=frame_id<=id+40: # 设置为定位frame的前60帧后40帧
output_list[num].write(frame)
cap.release()
if __name__ == '__main__':
frame_list = [100,420,650] # 定位帧数frame id
video_path = r'E:\test.mp4' # 视频路径
save_path = r'F:\save_path' # 存储路径
video_cut(frame_list=frame_list,video_path=video_path,save_path=save_path)
本文主要是作者对自己学习工作过程中的一个记录,也希望为正遇到类似问题的朋友提供一个参考。