step0:概述
- 动机:手头有数个20秒左右的短视频(守望先锋最佳镜头),期望能组合成一个长视频
- 技术路线:opencv+python(opencv在Python中的封装库是cv2,依赖于numpy)
step1:打开并显示视频
要组合视频,首先需要打开视频并获取每一帧的图像,在opencv中可以使用VideoCapture
这个类来打开视频,打开的视频也存在于这个类中,使用.read()
方法也可以获得每一帧的图像,该方法的用法类似于生成器,每调用一次都会返回下一帧的图像。其中.waitKey()
方法是延迟并获取键盘输入,传入参数是延迟时间数,单位是1/60s且必须是整数,因为原视频是60帧,所以间隔为1时是常速播放
import cv2
capture = cv2.VideoCapture(
"../leviathan's highlight_17-08-16_00-52-33.mp4")
if capture.isOpened():
while True:
ret, prev = capture.read()
if ret is True:
cv2.imshow("", prev)
else:
break
cv2.waitKey(1)
玩过守望先锋的小伙伴应该知道,那个最佳镜头的最后会一段浮现守望先锋logo的部分,我们需要切掉这一部分,方法是只截取前17.5秒的视频,因为不知道是否有24帧的视频,所以要先获得帧率再截取前17.5*fps的视频,现在的代码是
import cv2
capture = cv2.VideoCapture(
"../leviathan's highlight_17-08-16_00-52-33.mp4")
print(capture.get(cv2.CAP_PROP_FRAME_WIDTH))
print(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = capture.get(cv2.CAP_PROP_FPS)
if capture.isOpened():
i = 0
while i < fps * 17.5:
i += 1
ret, prev = capture.read()
if ret is True:
cv2.imshow("", prev)
else:
break
cv2.waitKey(1)
顺便还看了下幕布的尺寸为1920*1080
参考python tools:计算视频的 FPS,以及总帧数
step2打开并显示一堆视频
因为视频一共有20个左右,所以可以使用os
模块中的listdir()
获取所有文件,并筛选带.mp4
后缀的视频文件。这样获取的list是完全按顺序排列的,我们还可以使用random.shuffle()
方法打乱整个视频列表
mp4list = [x for x in os.listdir("../") if x[-4:] == ".mp4"]
random.shuffle(mp4list)
于是遍历整个列表看所有视频了
import cv2
import os
import random
mp4list = [x for x in os.listdir("../") if x[-4:] == ".mp4"]
random.shuffle(mp4list)
print(mp4list)
for mp4file in mp4list:
capture = cv2.VideoCapture("../%s" % mp4file)
fps = capture.get(cv2.CAP_PROP_FPS)
print(fps)
if fps != 60:
jump = 20
else:
jump = 1
if capture.isOpened():
i = 0
while i < fps * 1:
i += 1
ret, prev = capture.read()
if ret is True:
cv2.imshow("", prev)
else:
break
cv2.waitKey(jump)
cv2.destroyAllWindows()
step3:保存为一个大视频
保存视频首先需要创建一个视频容器,可以使用cv2.VideoWriter
,输入参数为路径,压缩方式,帧率,幕布大小,随后使用该对象的write()
方法即可写入一帧,写入完成后,使用release()
方法释放容器并保存,若在次之前程序中断,那视频文件会是损坏状态,于是程序是这样的
import cv2
import os
import random
VideoWriter = cv2.VideoWriter(
"./overwatch.avi",
cv2.VideoWriter_fourcc('X', 'V', 'I', 'D'), 60,
(1920, 1080))
mp4list = [x for x in os.listdir("../") if x[-4:] == ".mp4"]
random.shuffle(mp4list)
print(mp4list)
for mp4file in mp4list:
print(mp4file)
capture = cv2.VideoCapture("../%s" % mp4file)
fps = capture.get(cv2.CAP_PROP_FPS)
if capture.isOpened():
i = 0
while i < fps * 17.5:
i += 1
ret, prev = capture.read()
if ret is True:
if fps == 60:
VideoWriter.write(prev)
else:
VideoWriter.write(prev)
VideoWriter.write(prev)
else:
break
VideoWriter.release()
cv2.destroyAllWindows()
其中为了补偿30帧左右的视频,非60帧图片一帧写入两次