轉:python下opencv和ffmpeg結合的視頻處理
(2020-06-06 17:24:52)分类: 信息技术研究 |
## ffmpeg 切割视频 | |
使用ffmpeg直接切割视频的命令 | |
``` | |
ffmpeg -i test.mp4 -ss 00:00:00 -t 00:00:30 -c:v copy -c:a copy output.mp4 | |
``` | |
或者 | |
``` | |
ffmpeg -i test.mp4 -ss 00:00:00 -to 00:00:30 -c:v copy -c:a copy output.mp4 | |
``` | |
其中 | |
``` | |
-i 指定输入文件 | |
-ss 指定开始时间 | |
-to 指定结束时间 | |
-t 指定需要截取的时长 | |
``` | |
上述命令将从视频开头截取一段30s的视频。但是,如果截取的开始时间和结束时间不是关键帧,那么得到的视频开头画面通常会卡住,而声音是正常的。这时候可以对视频流进行重编码,命令如下: | |
``` | |
ffmpeg -ss 00:00:00 -to 00:00:30 -i test.mp4 -c:v h264 -c:a copy output.mp4 | |
``` | |
上述方法基本上可以满足大部分人的需求,时间精确到了秒。对于强迫症来说可能还不够准确,需要精确到帧。 | |
## OpenCV精准切割视频 | |
首先,使用ffmpeg粗略的切割视频 | |
``` | |
ffmpeg -ss START -to END -i INPUT -c:v copy -c:a copy cut.mp4 | |
``` | |
这里START建议设置在目标开始时间前几秒,END设置在目标结束时间后几秒,以保证待截取的所有视频帧都包含在输出文件内。 | |
接下来使用Python+OpenCV库实现以帧为单位的精准切割视频。首先将cut.mp4逐帧保存为图片,这里可以使用OpenCV或者ffmpeg生成(在当前目录下新建一个`frames`文件夹,否则无法保存): | |
``` | |
ffmpeg -i cut.mp4 frames/frames_d.jpg | |
``` | |
或者使用OpenCV | |
```python2 | |
from __future__ import absolute_import | |
from __future__ import division | |
from __future__ import print_function | |
import cv2 | |
cap = cv2.VideoCapture('cut.mp4') | |
success, image = cap.read() | |
count = 0 | |
success = True | |
while success: | |
# save frame as JPEG file | |
cv2.imwrite("frames/frame%d.jpg" % count, image) | |
success, image = cap.read() | |
print('Read a new frame: ', count) | |
count += 1 | |
``` | |
在frames文件夹下,我们可以看到视频帧都转换成了图像文件。接下来,找出需要截取的视频开始帧和结束帧对应的文件,并记下编号(下一步用到)。 | |
```python2 | |
from __future__ import absolute_import | |
from __future__ import division | |
from __future__ import print_function | |
import cv2 | |
cap = cv2.VideoCapture('cut.mp4') | |
outpath = 'cut_1.mp4' | |
start_frame = 372 # 开始帧 | |
end_frame = 1230 # 结束帧 | |
# 获取视频分辨率 | |
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))) | |
# 输出文件编码,Linux下可选X264 | |
fourcc = cv2.VideoWriter_fourcc(*'mp4v') | |
# 视频帧率 | |
fps = cap.get(cv2.CAP_PROP_FPS) | |
success, image = cap.read() | |
count = 0 | |
success = True | |
# 从视频开头获取每一帧,直到到达开始帧 | |
while success: | |
success, image = cap.read() | |
count += 1 | |
if (count==start_frame): | |
success = False | |
# 开始帧的时间(单位ms),相当于ffmpeg的ss参数 | |
ss = int(cap.get(cv2.CAP_PROP_POS_MSEC)) | |
# 输出 | |
out = cv2.VideoWriter(outpath, fourcc, fps, size) | |
# 读取开始帧到结束帧的每一帧并写入新视频 | |
while (count | |
success, image = cap.read() | |
out.write(image) | |
count+=1 | |
# 结束帧的时间,相对于ffmpeg的to参数 | |
to = int(cap.get(cv2.CAP_PROP_POS_MSEC)) | |
print(ss, to) | |
cap.release() | |
out.release() | |
``` | |
以上程序将生产一个精确到帧的视频文件,但是没有声音,而ffmpeg在分割音频的时候是很精确的。接下来将用ffmpeg来切割音频,并和上述视频合并。 | |
## ffmpeg切割音频并合并视频 | |
``` | |
ffmpeg -i cut_1.mp4 -i cut.mp4 -ss TIME_OFF -to TIME_STOP -c copy output.mkv | |
``` | |
这里`TIME_OFF`和`TIME_STOP`与前一节的`ss`和`to`相对应,但是ffmpeg里面时间单位是s,因此应先除以`1000`。 |
前一篇:PYGAME
后一篇:視頻:ass字幕參數實例