小編自己碼的通用型函數(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.jpg
、frame_000002.jpg
谣妻、frame_000003.jpg
......jpg_quality
:設(shè)置圖片質(zhì)量萄喳,范圍為0
到100
,默認(rèn)為100
(質(zhì)量最佳)isColor
:如果為False
蹋半,輸出的將是黑白圖片
目前只支持輸出
jpg
格式圖片
3. 例子
下面來測試一下這個函數(shù)的功能:
- 設(shè)置
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
文件夾下
- 設(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)文章肄满。