小編自己碼的通用型函數(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.mp4pathOut:設定提取的圖片保存在哪個文件夾下,比如: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:設置圖片質量,范圍為0到100,默認為100(質量最佳)isColor:如果為False,輸出的將是黑白圖片
目前只支持輸出
jpg格式圖片
3. 例子
下面來測試一下這個函數(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文件夾下
- 設置
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學堂”,我將定期更新相關文章。
