Python opencv提取视频中的图片
作者:R语言和Python学堂
链接:https://www.jianshu.com/p/e3c04d4fb5f3
这个函数就是本文要介绍的video2frames()
函数,功能就是从视频中提取图片,名称“video2frames”是我自己取的,还比较形象。现将它分享给大家,感兴趣的小伙伴们可以参考一下,完整代码附在文末。
1. 主要功能
这个函数有以下主要功能:
-
提取特定时间点图片,比如:提取视频第3秒, 第5秒,第9秒图片
-
设定提取的起始时刻,比如:从视频的第10秒开始提取
-
设定提取的终止时刻,比如:100秒后的视频不提取图片
-
设定每隔多少秒提取一张图片,比如:每隔2秒从视频中提取一张图片
2. 函数参数
video2frames()
函数的原型为:
video2frames(pathIn='', pathOut='', only_output_video_info = False, extract_time_points = None, initial_extract_time = 0, end_extract_time = None, extract_time_interval = -1, output_prefix = 'frame', jpg_quality = 100, isColor = True)
各参数的意义:
-
pathIn
:视频的路径,比如:F:\python_tutorials\test.mp4
-
pathOut
:设定提取的图片保存在哪个文件夹下,比如:F:\python_tutorials\frames\
。如果该文件夹不存在,函数将自动创建它 -
only_output_video_info
:如果为True
,只输出视频信息(长度、帧数和帧率),不提取图片 -
extract_time_points
:提取的时间点,单位为秒,为元组数据,比如,(2, 3, 5)
表示只提取视频第2秒, 第3秒,第5秒图片 -
initial_extract_time
:提取的起始时刻,单位为秒,默认为0
(即从视频最开始提取) -
end_extract_time
:提取的终止时刻,单位为秒,默认为None
(即视频终点) -
extract_time_interval
:提取的时间间隔,单位为秒,默认为-1
(即输出时间范围内的所有帧) -
output_prefix
:图片的前缀名,默认为frame
,那么图片的名称将为frame_000001.jpg
、frame_000002.jpg
、frame_000003.jpg
...... -
jpg_quality
:设置图片质量,范围为0
到100
,默认为100
(质量最佳) -
isColor
:如果为False
,输出的将是黑白图片
目前只支持输出
jpg
格式图片
3. 例子
下面来测试一下这个函数的功能:
- 设置
only_output_video_info
为True
,将只输出视频信息,不提取图片
>>> pathIn = 'test.mp4' >>> video2frames(pathIn, only_output_video_info=True) only output the video information (without extract frames):::::: Duration of the video: 5.28 seconds Number of frames: 132 Frames per second (FPS): 25.0
可以看到,视频
test.mp4
的长度为5.28秒,共132帧,帧率为25.0
- 提取所有图片,并保存到指定文件夹下
-
>>> pathIn = 'test.mp4' >>> pathOut = './frames1/' >>> video2frames(pathIn, pathOut) Converting a video into frames...... Write a new frame: True, 1/132 Write a new frame: True, 2/132 .............................. Write a new frame: True, 131/132 Write a new frame: True, 132/132
可以看到,视频的132帧图片全部提取到
frames1
文件夹下
- 设置
extract_time_points
参数,提取特定时间点的图片
>>> pathIn = 'test.mp4' >>> pathOut = './frames2' >>> video2frames(pathIn, pathOut, extract_time_points=(1, 2, 5)) Write a new frame: True, 1th Write a new frame: True, 2th Write a new frame: True, 3th
可以看到,只提取了第1秒,第2秒和第5秒图片
- 每隔一段时间提取图片,并设置初始时刻和终止时刻
-
>>> pathIn = 'test.mp4' >>> pathOut = './frames3' >>> video2frames(pathIn, pathOut, initial_extract_time=1, end_extract_time=3, extract_time_interval = 0.5) Converting a video into frames...... Write a new frame: True, 1th Write a new frame: True, 2th Write a new frame: True, 3th Write a new frame: True, 4th Write a new frame: True, 5th
可以看到,1到3秒内的视频每隔0.5秒提取图片,共5张图片(分别为1s, 1.5s, 2s, 2.5s, 3s时刻的图片)
- 设置
jpg_quality
参数,改变输出图片的质量 -
>>> pathOut = './frames4' >>> pathIn = 'test.mp4' >>> video2frames(pathIn, pathOut, extract_time_points=(0.3, 2), jpg_quality=50) Write a new frame: True, 1th Write a new frame: True, 2th
- 设置
isColor
参数为False
,提取的照片将是黑白色
>>> pathOut = './frames5' >>> pathIn = 'test.mp4' >>> video2frames(pathIn, pathOut, extract_time_points=(0.3, 2), isColor=False) Write a new frame: True, 1th Write a new frame: True, 2th
video2frames()
函数的功能测试到此结束。
4. 完整代码
函数为通用型的,因此代码较长,可能还存在可以优化的地方,仅供参考。
完整代码如下:
# -*- coding: utf-8 -*- import os import cv2 ##加载OpenCV模块 def video2frames(pathIn='', pathOut='', only_output_video_info = False, extract_time_points = None, initial_extract_time = 0, end_extract_time = None, extract_time_interval = -1, output_prefix = 'frame', jpg_quality = 100, isColor = True): ''' pathIn:视频的路径,比如:F:\python_tutorials\test.mp4 pathOut:设定提取的图片保存在哪个文件夹下,比如:F:\python_tutorials\frames1\。如果该文件夹不存在,函数将自动创建它 only_output_video_info:如果为True,只输出视频信息(长度、帧数和帧率),不提取图片 extract_time_points:提取的时间点,单位为秒,为元组数据,比如,(2, 3, 5)表示只提取视频第2秒, 第3秒,第5秒图片 initial_extract_time:提取的起始时刻,单位为秒,默认为0(即从视频最开始提取) end_extract_time:提取的终止时刻,单位为秒,默认为None(即视频终点) extract_time_interval:提取的时间间隔,单位为秒,默认为-1(即输出时间范围内的所有帧) output_prefix:图片的前缀名,默认为frame,图片的名称将为frame_000001.jpg、frame_000002.jpg、frame_000003.jpg...... jpg_quality:设置图片质量,范围为0到100,默认为100(质量最佳) isColor:如果为False,输出的将是黑白图片 ''' cap = cv2.VideoCapture(pathIn) ##打开视频文件 n_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) ##视频的帧数 fps = cap.get(cv2.CAP_PROP_FPS) ##视频的帧率 dur = n_frames/fps ##视频的时间 ##如果only_output_video_info=True, 只输出视频信息,不提取图片 if only_output_video_info: print('only output the video information (without extract frames)::::::') print("Duration of the video: {} seconds".format(dur)) print("Number of frames: {}".format(n_frames)) print("Frames per second (FPS): {}".format(fps)) ##提取特定时间点图片 elif extract_time_points is not None: if max(extract_time_points) > dur: ##判断时间点是否符合要求 raise NameError('the max time point is larger than the video duration....') try: os.mkdir(pathOut) except OSError: pass success = True count = 0 while success and count < len(extract_time_points): cap.set(cv2.CAP_PROP_POS_MSEC, (1000*extract_time_points[count])) success,image = cap.read() if success: if not isColor: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) ##转化为黑白图片 print('Write a new frame: {}, {}th'.format(success, count+1)) cv2.imwrite(os.path.join(pathOut, "{}_{:06d}.jpg".format(output_prefix, count+1)), image, [int(cv2.IMWRITE_JPEG_QUALITY), jpg_quality]) # save frame as JPEG file count = count + 1 else: ##判断起始时间、终止时间参数是否符合要求 if initial_extract_time > dur: raise NameError('initial extract time is larger than the video duration....') if end_extract_time is not None: if end_extract_time > dur: raise NameError('end extract time is larger than the video duration....') if initial_extract_time > end_extract_time: raise NameError('end extract time is less than the initial extract time....') ##时间范围内的每帧图片都输出 if extract_time_interval == -1: if initial_extract_time > 0: cap.set(cv2.CAP_PROP_POS_MSEC, (1000*initial_extract_time)) try: os.mkdir(pathOut) except OSError: pass print('Converting a video into frames......') if end_extract_time is not None: N = (end_extract_time - initial_extract_time)*fps + 1 success = True count = 0 while success and count < N: success,image = cap.read() if success: if not isColor: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) print('Write a new frame: {}, {}/{}'.format(success, count+1, n_frames)) cv2.imwrite(os.path.join(pathOut, "{}_{:06d}.jpg".format(output_prefix, count+1)), image, [int(cv2.IMWRITE_JPEG_QUALITY), jpg_quality]) # save frame as JPEG file count = count + 1 else: success = True count = 0 while success: success,image = cap.read() if success: if not isColor: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) print('Write a new frame: {}, {}/{}'.format(success, count+1, n_frames)) cv2.imwrite(os.path.join(pathOut, "{}_{:06d}.jpg".format(output_prefix, count+1)), image, [int(cv2.IMWRITE_JPEG_QUALITY), jpg_quality]) # save frame as JPEG file count = count + 1 ##判断提取时间间隔设置是否符合要求 elif extract_time_interval > 0 and extract_time_interval < 1/fps: raise NameError('extract_time_interval is less than the frame time interval....') elif extract_time_interval > (n_frames/fps): raise NameError('extract_time_interval is larger than the duration of the video....') ##时间范围内每隔一段时间输出一张图片 else: try: os.mkdir(pathOut) except OSError: pass print('Converting a video into frames......') if end_extract_time is not None: N = (end_extract_time - initial_extract_time)/extract_time_interval + 1 success = True count = 0 while success and count < N: cap.set(cv2.CAP_PROP_POS_MSEC, (1000*initial_extract_time+count*1000*extract_time_interval)) success,image = cap.read() if success: if not isColor: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) print('Write a new frame: {}, {}th'.format(success, count+1)) cv2.imwrite(os.path.join(pathOut, "{}_{:06d}.jpg".format(output_prefix, count+1)), image, [int(cv2.IMWRITE_JPEG_QUALITY), jpg_quality]) # save frame as JPEG file count = count + 1 else: success = True count = 0 while success: cap.set(cv2.CAP_PROP_POS_MSEC, (1000*initial_extract_time+count*1000*extract_time_interval)) success,image = cap.read() if success: if not isColor: image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) print('Write a new frame: {}, {}th'.format(success, count+1)) cv2.imwrite(os.path.join(pathOut, "{}_{:06d}.jpg".format(output_prefix, count+1)), image, [int(cv2.IMWRITE_JPEG_QUALITY), jpg_quality]) # save frame as JPEG file count = count + 1 ##### 测试 pathIn = 'test.mp4' video2frames(pathIn, only_output_video_info = True) pathOut = './frames1/' video2frames(pathIn, pathOut) pathOut = './frames2' video2frames(pathIn, pathOut, extract_time_points=(1, 2, 5)) pathOut = './frames3' video2frames(pathIn, pathOut, initial_extract_time=1, end_extract_time=3, extract_time_interval = 0.5) pathOut = './frames4/' video2frames(pathIn, pathOut, extract_time_points=(0.3, 2), isColor = False) pathOut = './frames5/' video2frames(pathIn, pathOut, extract_time_points=(0.3, 2), jpg_quality=50)