*完整代码请滑到文章末尾。
一、问题描述
针对大量视频文件,每个视频抽取30~40帧。
二、解决方案
针对上述问题,可以获取视频的长度,根据视频长度判断一秒分割成多少帧。
1.获取视频长度
一开始找到了通过moviepy
库1,具体代码如下:
from moviepy.editor import VideoFileClip
def get_video_times(video_path):
video_clip = VideoFileClip(video_path)
durantion = video_clip.duration
return durantion
但某篇博客/回答指出,cv
获取视频长度更快捷。具体代码如下:
def get_video_duration(filename):
cap = cv2.VideoCapture(filename)
if cap.isOpened():
rate = cap.get(5)
frame_num =cap.get(7)
duration = frame_num/rate
return duration
return -1
考虑到需要处理大量视频,应采取运行速度更快的方法。故对两种方法的运行时间进行比较。具体代码如下:
start =time.clock()
video=get_video_duration('D:\shujuji\IMG_1002 (1).MP4')#取某个视频测试一下
end = time.clock()
print(end-start)
结果表明,调用cv
运行速度确实更快,是前者的十几倍。此处不放结果截图了,有兴趣可以自己试试。
2.判断分割帧数
一开始考虑固定不同区间视频时长的帧数,后觉得有点麻烦,采用如下方法:
length=get_video_duration(all_files[i])
zhen=int(35/length)
最终抽取的视频帧将为35左右。
三、完整代码
import cv2
import os
'''
批量视频抽帧
'''
def get_video_duration(filename):
cap = cv2.VideoCapture(filename)
if cap.isOpened():
rate = cap.get(5)
frame_num =cap.get(7)
duration = frame_num/rate
return duration
return -1
#读取数据集合
video_path = r'D:\shujuji'
#获得文件名
start_dir_num = 30000000#从6位数开始编号
all_files = os.listdir(video_path)#获得所有的视频列表
#准备txt文件
f = open('D:\\video\my_dataset.txt','w')
for i in range(len(all_files)):
video_type = all_files[i].split('.')[1]
if video_type not in ['avi','MP4','flv','mov','mp4']:
continue
save_path = os.path.join(r'D:\video',str(start_dir_num))
# 判断文件夹是否存在
folder = os.path.exists(save_path)
if not folder:
os.mkdir(save_path)
print("创建文件夹: ",str(start_dir_num))
# subprocess.Popen('ffmpeg -i {} -r 6 -f image2 {}\%05d.jpg'.format(all_files[i],save_path),stdout=subprocess.PIPE)
length=get_video_duration(all_files[i])
zhen=int(35/length)
cmd = 'ffmpeg -i {} -r {} -f image2 {}\%05d.jpg'.format(all_files[i],zhen,save_path)
os.system(cmd)
#将视频信息写入csv文件中 格式: 编号 帧数 类型
frame_num = os.listdir(save_path)
rowname = str(start_dir_num)+" "+str(len(frame_num))+" \n"
f.write(rowname)
start_dir_num+=1
f.close()