圖片序列轉換成視頻
最近一直在找一個工具,能夠將一堆圖片轉化成視頻。網上找了一些小軟件,還有 win10 的照片
自帶的視頻制作功能,都不是很滿意。
又不想下載那些專業的視頻剪輯軟件大材小用。
然后找到了ffmpeg
這個非常出名非常常用的多媒體編解碼庫,看了下文檔試着用了下,它確實可以完成上述功能,但是命令行對輸入圖片的命名有規定(文件名必須開頭相同、且包含連續編號),並且windows
下的編譯版不支持Pattern type 'glob'
。
先嘗試了用python
寫了批量重命名然后調用ffmpeg
的命令,然后發現還需要相同的分辨率才行。。。
最后決定參照網上的其他使用OpenCV
(OpenCV在視頻處理功能底層也是用的ffmpeg
)的博客自己寫一個。
這里先把完整代碼和使用說明貼出來:
import os, sys
import cv2
import numpy as np
import argparse
imgs_path = 'C:\\'
target_size = (1280, 720)
target_fps = 1.0
# 輸出文件名
target_video = 'out.mp4'
# 是否保存 resize 的中間圖像
saveResizeFlag = False
img_types = ('.bmp', '.dib', '.png', '.jpg', '.jpeg', '.pbm', '.pgm', '.ppm', '.tif', '.tiff')
# 不存在則創建目錄
def mkdir(path):
if not os.path.exists(path):
os.mkdir(path)
# 將圖片等比例縮放,不足則填充黑邊
def resizeAndPadding(img):
size = img.shape
h, w = size[0], size[1]
target_h, target_w = target_size[1], target_size[0]
# 確定縮放的尺寸
scale_h, scale_w= float(h / target_h), float(w / target_w)
scale = max(scale_h, scale_w)
new_w, new_h = int(w / scale), int(h / scale)
# 縮放后其中一條邊和目標尺寸一致
resize_img = cv2.resize(img, (new_w, new_h))
# 圖像上、下、左、右邊界分別需要擴充的像素數目
top = int((target_h - new_h) / 2)
bottom = target_h - new_h - top
left = int((target_w - new_w) / 2)
right = target_w - new_w - left
# 填充至 target_w * target_h
pad_img = cv2.copyMakeBorder(resize_img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=[0,0,0])
return pad_img
def imgs2video():
output_path = imgs_path + 'out\\'
mkdir(output_path)
target = output_path + target_video
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
vw = cv2.VideoWriter(target, fourcc, target_fps, target_size)
images = os.listdir(imgs_path)
count = 0
for image in images:
if not (image.lower().endswith(img_types)):
continue
try:
print(image)
# cv2.waitKey(100)
# frame = cv2.imread(imgs_path + image)
# imread 不能讀中文路徑,unicode也不行
frame = cv2.imdecode(np.fromfile(imgs_path + image, dtype=np.uint8), cv2.IMREAD_COLOR) #, cv2.IMREAD_UNCHANGED
pad_frame = resizeAndPadding(frame)
# print(pad_frame.shape)
if saveResizeFlag:
# 保存縮放填充后的圖片
resize_path = imgs_path + 'resize\\'
mkdir(resize_path)
resize_name = resize_path + 'resize_' + image
# cv2.imwrite(resize_name, pad_frame)
# imwrite 不能讀中文路徑,unicode也不行
cv2.imencode(os.path.splitext(image)[-1], pad_frame)[1].tofile(resize_name)
# 寫入視頻
vw.write(pad_frame)
count += 1
except Exception as exc:
print(image, exc)
vw.release()
print('\r\nConvert Success! Total ' + str(count) + ' images be combined into the video at: ' + target + '\r\n')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Function: convert images to video")
parser.add_argument('--input', '-i', required = True)
parser.add_argument('--output', '-o', default='out.mp4')
parser.add_argument('--fps', '-f', type=float, default = 1.0)
parser.add_argument('--resolution', '-r', type=int, nargs = 2, default = [1280, 720])
parser.add_argument('--save', '-s', action='store_true')
args = parser.parse_args()
if args.input:
if not os.path.isdir(args.input):
print("input is not a directory")
sys.exit(0)
imgs_path = args.input
if not imgs_path.endswith(('\\', '/')):
imgs_path += os.path.sep
print('input path: ' + imgs_path)
if args.output:
target_video = args.output
print('output file: ' + target_video)
if args.fps:
if not args.fps > 0:
print('fps should be greater than zero')
sys.exit(0)
target_fps = args.fps
print('output file fps: ' + str(target_fps))
if args.resolution:
if not args.resolution[0] > 0 and args.resolution[1] > 0:
print('resolution should be greater than zero')
sys.exit(0)
target_size = (args.resolution[0], args.resolution[1])
print('output file resolution: ' + str(target_size))
if args.save:
saveResizeFlag = True
imgs2video()
使用方法:
- 依賴
numpy
和cv2
:(當然首先得有 Python 環境)
pip install numpy
pip install opencv-python
- 下載本代碼到本地;
- 在命令行運行本代碼,並指定參數:
python imgs2video.py -i D:\images\
python imgs2video.py -i D:\images\ -o test.mp4 -f 0.5 -r 1920 1080 -s
- 參數介紹:
--input, -i: 輸入圖片的路徑,必須參數;
--output, -o: 輸出視頻的名字,默認 out.mp4;
--fps, -f: 指定的幀率,類型浮點數,默認 1.0;
--resolution, -r: 指定視頻的分辨率,類型兩個整數,默認 1280 720;
--save, -s: 是否保存圖片轉化分辨率之后的中間結果,默認不保存。
說明
代碼看起來有點長,其實核心功能在函數imgs2video
中:創建一個cv2.VideoWriter
用於寫視頻文件,cv2.imdecode
讀圖片,然后縮放,然后寫入視頻。可選項:cv2.imencode
將縮放后的圖片保存下來。之所以不用cv2.imread
和cv2.imwrite
是因為這倆沒辦法處理中文路徑 😦
函數resizeAndPadding
用於將圖片等比例縮放至指定分辨率,並往周圍填充黑邊(想用其他顏色在代碼里改一改value=[0,0,0]
這里的 RGB 值就行了)。這個函數本身也可以實現某些需求了。
main
里面主要是處理命令行的一些參數,指定輸入文件、輸出文件、分辨率、幀率等
輸出文件類型目前用的mp4
,可以指定其他類型試試。我自己試過avi
但是在幀率低的時候表現不太正常。指定其他類型可能需要把fourcc = cv2.VideoWriter_fourcc(*"mp4v")
這里的"mp4v"
改成其他的,具體怎么改可以搜一下,這里就不一一列舉了。(這里有一個奇妙 BUG,寫"MP4V"
反正會報出錯誤,雖然能正常生成視頻。在StackOverFlow
上看見有人說改成"mp4v"
就正常了,試了下還真的是。。。。)
其他功能的說明在上文使用方法
里都有寫。
后記
折騰了一天寫了個用處不大的小工具。如果此代碼對你有幫助可以在該github倉庫點個Star
。