有没有一种方法可以从视频中剪切帧以减小其大小和持续时间?

时间:2020-03-06 22:28:16

标签: python opencv video

我需要处理大量视频,但是处理速度很慢,因为处理涉及以0.6FPS的速度运行整个视频,并且绝大多数帧之间的变化很小。

是否可以通过某种方式每隔两秒钟对视频进行一次采样,然后将其保存为另一个将帧率和时长减少一倍的视频?我不担心这样做会丢失信息,我很乐意将10分钟的视频缩减到几百帧。我确实需要将其作为视频文件,而不是图像集。

1 个答案:

答案 0 :(得分:0)

您可以使用cv2.VideoCapturecv2.VideoWriter或使用FFmpeg来解决它。

以下解决方案使用ffmpeg-python
我同时发布了OpenCV解决方案和FFmpeg解决方案。

使用OpenCV解决:

  • 打开输入视频文件以使用cv2.VideoCapture阅读。
  • 打开输出视频文件以使用cv2.VideoWriter进行写操作。
  • 读取所有帧,但仅每10帧写入一次输出文件。

使用FFmpeg解决:

以下示例为“自包含”-生成用于测试的合成输入视频文件,并对生成的输入视频执行跳帧。

以下是代码(底部使用ffmpeg-python的示例):

import ffmpeg  # Note: import ffmpeg is not a must, when using OpenCV solution.
import cv2
import sys

out_filename = 'out.mp4'

# Build synthetic video and read binary data into memory (for testing):
#########################################################################
in_filename = 'in.mp4'
width, height = 320, 240
fps = 1  # 1Hz (just for testing)

# Build synthetic video, for testing:
# ffmpeg -y -f lavfi -i testsrc=size=320x240:rate=1 -c:v libx264 -crf 18 -t 50 in.mp4
(
    ffmpeg
    .input('testsrc=size={}x{}:rate={}'.format(width, height, fps), f='lavfi')
    .output(in_filename, vcodec='libx264', crf=18, t=50)
    .overwrite_output()
    .run()
)
#########################################################################

# Open video file for reading
in_vid = cv2.VideoCapture(in_filename)

#Exit if video not opened.
if not in_vid.isOpened():
    print('Cannot open input video file')
    sys.exit()

# Read first image (for getting resolution).
ok, frame = in_vid.read()
if not ok:
    print('Cannot read video file')
    sys.exit()

width, height = frame.shape[1], frame.shape[0]

# Get frame rate of input video.
fps = in_vid.get(cv2.CAP_PROP_FPS)

# Create video writer
# 264 doesn't come by default with the default installation of OpenCV, but I preferred using H.264 (supposed to be better than XVID).
# https://stackoverflow.com/questions/41972503/could-not-open-codec-libopenh264-unspecified-error
# (I had to download openh264-1.8.0-win64.dll)
out_vid = cv2.VideoWriter(out_filename, cv2.VideoWriter_fourcc(*'H264'), fps, (width, height))


frame_counter = 0

while True:
    # Write every 10th frame to output video file.
    if ((frame_counter % 10) == 0):
        out_vid.write(frame)

    # Read a new frame
    ok, frame = in_vid.read()
    if not ok:
        break

    frame_counter += 1

out_vid.release()





# Selecting one every n frames from a video using FFmpeg:
# https://superuser.com/questions/1274661/selecting-one-every-n-frames-from-a-video-using-ffmpeg 
# ffmpeg -y -r 10 -i in.mp4 -vf "select=not(mod(n\,10))" -vsync vfr -vcodec libx264 -crf 18  1_every_10.mp4

out_filename = '1_every_10.mp4'

# Important: set input frame rate to fps*10
(
    ffmpeg
    .input(in_filename, r=str(fps*10))
    .output(out_filename, vf='select=not(mod(n\,10))', vsync='vfr', vcodec='libx264', crf='18')
    .overwrite_output()
    .run()
)
  • 注意:由于解码和重新编码,该解决方案失去了某些视频质量。

如果您正在寻找根据指标计算跳过帧的解决方案,也可以尝试FFmpeg decimate filter