zoukankan      html  css  js  c++  java
  • 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 est.mp4

    • pathOut:设定提取的图片保存在哪个文件夹下,比如:F:python_tutorialsframes。如果该文件夹不存在,函数将自动创建它

    • 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.jpgframe_000002.jpgframe_000003.jpg......

    • jpg_quality:设置图片质量,范围为0100,默认为100(质量最佳)

    • isColor:如果为False,输出的将是黑白图片

    目前只支持输出jpg格式图片

    3. 例子

    下面来测试一下这个函数的功能:

    • 设置only_output_video_infoTrue,将只输出视频信息,不提取图片
    >>> 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	est.mp4
        pathOut:设定提取的图片保存在哪个文件夹下,比如:F:python_tutorialsframes1。如果该文件夹不存在,函数将自动创建它
        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)
  • 相关阅读:
    centos7下编译安装python3.7,且与python2.7.5共存
    Linux下的ctrl常用组合键
    命令 docker rm | docker rmi | docker prune 的差异
    docker操作命令大全和后台参数
    解决Linux下ssh登录后出现 报错 Write failed: Broken pipe 的方法
    在centos7 中docker info报错docker bridge-nf-call-iptables is disabled 的解决方法
    Linux下实现不活动用户登录超时后自动登出
    centos下非yum方式安装docker环境
    Git Error:There is no tracking information for the current branch.
    Vim操作:打开文件
  • 原文地址:https://www.cnblogs.com/-wenli/p/11943523.html
Copyright © 2011-2022 走看看