用Python提取視頻中的圖片

小編自己碼的通用型函數(shù),支持各種常用視頻格式,可滿足常用需求,親測效果和速度都不錯。

想獲取本文數(shù)據和完整代碼的下載鏈接,請關注微信公眾號"R語言和Python學堂",并回復發(fā)文日期"20181103"。

最近在幫著處理實驗上的一些視頻,我們知道視頻是由一幀一幀圖片疊加而制成的。其中第一步就是要把視頻中的圖片提取出來,怎么做呢?

有人會說,網上應該有很多相關小軟件可以做這個事情。仔細一想,大多數(shù)軟件應該不能滿足以后的需求,比如:批量處理視頻,提取視頻某段時間內的圖片,每隔一段時間提取一張圖片。。。

Google了一下,發(fā)現(xiàn)Python在處理視頻方面表現(xiàn)非常優(yōu)秀,多數(shù)都是基于OpenCV庫的。為了解決我的需求,因此決定自己寫個基于Python+OpenCV的通用函數(shù),來解決以后在提取圖片過程中的各種需求。

這個函數(shù)就是本文要介紹的video2frames()函數(shù),功能就是從視頻中提取圖片,名稱“video2frames”是我自己取的,還比較形象?,F(xiàn)將它分享給大家,感興趣的小伙伴們可以參考一下,完整代碼附在文末。

1. 主要功能

這個函數(shù)有以下主要功能:

  • 提取特定時間點圖片,比如:提取視頻第3秒, 第5秒,第9秒圖片

  • 設定提取的起始時刻,比如:從視頻的第10秒開始提取

  • 設定提取的終止時刻,比如:100秒后的視頻不提取圖片

  • 設定每隔多少秒提取一張圖片,比如:每隔2秒從視頻中提取一張圖片

2. 函數(shù)參數(shù)

video2frames()函數(shù)的原型為:

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)

各參數(shù)的意義:

  • pathIn:視頻的路徑,比如:F:\python_tutorials\test.mp4

  • pathOut:設定提取的圖片保存在哪個文件夾下,比如:F:\python_tutorials\frames\。如果該文件夾不存在,函數(shù)將自動創(chuàng)建它

  • only_output_video_info:如果為True,只輸出視頻信息(長度、幀數(shù)和幀率),不提取圖片

  • extract_time_points:提取的時間點,單位為秒,為元組數(shù)據,比如,(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:設置圖片質量,范圍為0100,默認為100(質量最佳)

  • isColor:如果為False,輸出的將是黑白圖片

目前只支持輸出jpg格式圖片

3. 例子

下面來測試一下這個函數(shù)的功能:

  • 設置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參數(shù),提取特定時間點的圖片
>>> 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參數(shù),改變輸出圖片的質量
>>> 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參數(shù)為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()函數(shù)的功能測試到此結束。

4. 完整代碼

函數(shù)為通用型的,因此代碼較長,可能還存在可以優(yōu)化的地方,僅供參考。

完整代碼如下:

# -*- 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\。如果該文件夾不存在,函數(shù)將自動創(chuàng)建它
    only_output_video_info:如果為True,只輸出視頻信息(長度、幀數(shù)和幀率),不提取圖片
    extract_time_points:提取的時間點,單位為秒,為元組數(shù)據,比如,(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))  ##視頻的幀數(shù)
    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:
        ##判斷起始時間、終止時間參數(shù)是否符合要求
        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)

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本公眾號。


感謝您的閱讀!想了解更多有關Python技巧,請關注我的微信公眾號“R語言和Python學堂”,我將定期更新相關文章。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容