用Python提取視頻中的圖片

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

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

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

有人會說肄扎,網(wǎng)上應(yīng)該有很多相關(guān)小軟件可以做這個事情。仔細(xì)一想赁酝,大多數(shù)軟件應(yīng)該不能滿足以后的需求犯祠,比如:批量處理視頻,提取視頻某段時間內(nèi)的圖片酌呆,每隔一段時間提取一張圖片衡载。。隙袁。

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

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

1. 主要功能

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

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

  • 設(shè)定提取的起始時刻万搔,比如:從視頻的第10秒開始提取

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

  • 設(shè)定每隔多少秒提取一張圖片官帘,比如:每隔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:設(shè)定提取的圖片保存在哪個文件夾下,比如:F:\python_tutorials\frames\刽虹。如果該文件夾不存在酗捌,函數(shù)將自動創(chuàng)建它

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

  • extract_time_points:提取的時間點,單位為秒阀圾,為元組數(shù)據(jù)哪廓,比如,(2, 3, 5)表示只提取視頻第2秒初烘, 第3秒涡真,第5秒圖片

  • initial_extract_time:提取的起始時刻,單位為秒肾筐,默認(rèn)為0(即從視頻最開始提榷吡稀)

  • end_extract_time:提取的終止時刻,單位為秒局齿,默認(rèn)為None(即視頻終點)

  • extract_time_interval:提取的時間間隔剧劝,單位為秒,默認(rèn)為-1(即輸出時間范圍內(nèi)的所有幀)

  • output_prefix:圖片的前綴名抓歼,默認(rèn)為frame讥此,那么圖片的名稱將為frame_000001.jpgframe_000002.jpg谣妻、frame_000003.jpg......

  • jpg_quality:設(shè)置圖片質(zhì)量萄喳,范圍為0100,默認(rèn)為100(質(zhì)量最佳)

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

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

3. 例子

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

  • 設(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文件夾下

  • 設(shè)置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秒圖片

  • 每隔一段時間提取圖片甜紫,并設(shè)置初始時刻和終止時刻
>>> 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秒內(nèi)的視頻每隔0.5秒提取圖片骂远,共5張圖片(分別為1s, 1.5s, 2s, 2.5s, 3s時刻的圖片)

  • 設(shè)置jpg_quality參數(shù)囚霸,改變輸出圖片的質(zhì)量
>>> 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
  • 設(shè)置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ù)的功能測試到此結(jié)束激才。

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:設(shè)定提取的圖片保存在哪個文件夾下钞脂,比如:F:\python_tutorials\frames1\。如果該文件夾不存在捕儒,函數(shù)將自動創(chuàng)建它
    only_output_video_info:如果為True冰啃,只輸出視頻信息(長度、幀數(shù)和幀率)刘莹,不提取圖片
    extract_time_points:提取的時間點阎毅,單位為秒,為元組數(shù)據(jù)点弯,比如扇调,(2, 3, 5)表示只提取視頻第2秒, 第3秒抢肛,第5秒圖片
    initial_extract_time:提取的起始時刻狼钮,單位為秒,默認(rèn)為0(即從視頻最開始提燃裥酢)
    end_extract_time:提取的終止時刻熬芜,單位為秒,默認(rèn)為None(即視頻終點)
    extract_time_interval:提取的時間間隔福稳,單位為秒涎拉,默認(rèn)為-1(即輸出時間范圍內(nèi)的所有幀)
    output_prefix:圖片的前綴名,默認(rèn)為frame的圆,圖片的名稱將為frame_000001.jpg鼓拧、frame_000002.jpg、frame_000003.jpg......
    jpg_quality:設(shè)置圖片質(zhì)量越妈,范圍為0到100季俩,默認(rèn)為100(質(zhì)量最佳)
    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)  ##轉(zhuǎn)化為黑白圖片
                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....')
        
        ##時間范圍內(nèi)的每幀圖片都輸出
        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

        ##判斷提取時間間隔設(shè)置是否符合要求    
        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....')
        
        ##時間范圍內(nèi)每隔一段時間輸出一張圖片
        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)

以上就是本文的全部內(nèi)容藐鹤,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持本公眾號赂韵。


感謝您的閱讀娱节!想了解更多有關(guān)Python技巧,請關(guān)注我的微信公眾號“R語言和Python學(xué)堂”祭示,我將定期更新相關(guān)文章肄满。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市质涛,隨后出現(xiàn)的幾起案子稠歉,更是在濱河造成了極大的恐慌,老刑警劉巖汇陆,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件怒炸,死亡現(xiàn)場離奇詭異,居然都是意外死亡毡代,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進(jìn)店門教寂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捏鱼,“玉大人,你說我怎么就攤上這事酪耕〉及穑” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵迂烁,是天一觀的道長看尼。 經(jīng)常有香客問我,道長婚被,這世上最難降的妖魔是什么狡忙? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮址芯,結(jié)果婚禮上灾茁,老公的妹妹穿的比我還像新娘。我一直安慰自己谷炸,他們只是感情好北专,可當(dāng)我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著旬陡,像睡著了一般拓颓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上描孟,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天驶睦,我揣著相機(jī)與錄音砰左,去河邊找鬼。 笑死场航,一個胖子當(dāng)著我的面吹牛缠导,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播溉痢,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼僻造,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了孩饼?” 一聲冷哼從身側(cè)響起髓削,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎镀娶,沒想到半個月后立膛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡汽畴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年旧巾,在試婚紗的時候發(fā)現(xiàn)自己被綠了耸序。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忍些。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖坎怪,靈堂內(nèi)的尸體忽然破棺而出罢坝,到底是詐尸還是另有隱情,我是刑警寧澤搅窿,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布嘁酿,位于F島的核電站,受9級特大地震影響男应,放射性物質(zhì)發(fā)生泄漏闹司。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一沐飘、第九天 我趴在偏房一處隱蔽的房頂上張望游桩。 院中可真熱鬧,春花似錦耐朴、人聲如沸借卧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铐刘。三九已至,卻和暖如春影晓,著一層夾襖步出監(jiān)牢的瞬間镰吵,已是汗流浹背檩禾。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留疤祭,地道東北人锌订。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像画株,于是被迫代替她去往敵國和親辆飘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內(nèi)容