【问题标题】:Slow image(frame) grabbing from video with OpenCV's VideoCapture and Python使用 OpenCV 的 VideoCapture 和 Python 从视频中抓取慢速图像(帧)
【发布时间】:2019-12-03 10:02:28
【问题描述】:

我想要的是从长视频(约 50 分钟和 30fps)中获取随机索引帧,以预处理图像以训练神经网络。 使用 opencv 加载存储的 png 图像大约需要 10 毫秒的时间。这确实很快,但是在考虑加载它们进行训练之前,您总是必须通过从中提取图像来预处理视频。 所以我的想法是只在我的 multiprocessing-keras-dataloader 中使用视频作为输入。 我已经能够在 cv.VideoCapture() 中设置帧索引并获取帧。问题是设置索引的速度很慢。抓取一帧大约需要 2-3 毫秒,这比加载存储的图像要快得多。问题是设置帧索引花费的时间太长,我不知道如何加速这个过程。

分割长视频不会带来任何性能。所需时间始终相同。

frame_set_timings = []
frame_read_timings = []
frames = []
batch_size = 10
video = '/mnt/sda/test_video.mp4'

cap = cv2.VideoCapture(video)
total_frames = int(cap.get(7))  # total number of frames

for i in range(batch_size):
    random_frame = random.randrange(start=0, stop=total_frames)  # get random frame number
    start_frame_set = time.time()
    cap.set(1, random_frame)  # Set which frame to grab from the video
    start_frame_read = time.time()
    ret, frame = cap.read()  # Read (grab) the image
    end_frame_read = time.time()

    frame_set_timings.append(float("{0:.4f}".format(start_frame_read - start_frame_set)))
    frame_read_timings.append(float("{0:.4f}".format(end_frame_read - start_frame_read)))
    frames.append(frame)

cap.release()

mean_frame_set = float("{0:.4f}".format(sum(frame_set_timings) / len(frame_set_timings)))
mean_frame_read = float("{0:.4f}".format(sum(frame_read_timings) / len(frame_read_timings)))
print('Frame set timings: {list}\nwith a mean time of: {mean}'.format(list=frame_set_timings,
                                                                      mean=mean_frame_set))
print('Frame read timings: {list}\nwith a mean time of: {mean}'.format(list=frame_read_timings,
                                                                       mean=mean_frame_read))

设置所需帧索引的平均持续时间约为 56 毫秒。帧抓取大约是 3 毫秒,这对我的目的来说真的很快。 我希望帧索引更快。也许我应该使用另一个编解码器,或者将视频转换为另一种格式(如 avi)会更快吗?

【问题讨论】:

  • 现在我使用 avi 视频进行了测试,它将帧索引从 56 毫秒加速到 28 毫秒。读取时间现在是 4ms 而不是 2-3ms
  • 我从未尝试过,也没有任何理由相信它一定会更快,但您可能会发现只寻找 forwards 会更快 在您的视频中。因此,您可以在循环之外生成您想要的一批帧号,并将它们按升序排序,看看是否有帮助......奇怪的事情发生了!
  • 在压缩视频中查找通常涉及从最近的keyframe 线性遍历每一帧。您可以使用其他存储原始数据的编解码器(即库可以跳过 n_frames*bytes_per_frame 字节并读取下一个图像,例如 ProRes)。但正如马克建议的那样,你能订购你的随机帧索引吗?这对于您的项目似乎是可行的。然后你可以线性地浏览视频,没有回溯,这应该会加快速度。
  • 你有什么更新吗?我面临同样的问题,使用 opencv 从 mp4 视频中抓取帧非常慢。而如果我们直接在命令行中使用ffmpeg或从.mov文件中抓取帧,它会快得多。

标签: python opencv deep-learning video-processing


【解决方案1】:

好的,我找到了一个昂贵的解决方法...

我正在使用 FFMPEG 使用 rawvideo 编解码器和以下命令将 mp4 视频转换为原始视频:

ffmpeg -i input.mp4 -an -vf scale=768:512 -c:v rawvideo output.3gp

但现在我的视频大小从 18MB 增加到 750MB。这有点奇怪,目前我不知道如何减小输出的大小。

但是: 6 个随机帧的加载时间也从 ~500ms 减少到 ~20ms。这太棒了,而且是我没想到的好结果。

问题:我有 271 个 mp4 视频,总大小为 200GB。如果我计算所有视频的 42 的 faktor,我的输出将有大约 8400GB 的数据。

任何想法如何在不购买 12GB 硬盘的情况下减小此大小?

【讨论】:

  • 也许你可以用更频繁的关键帧重新编码你的视频,这样不会浪费空间,但可以加快搜索速度。
  • @MarkSetchell 是的,这可能是一个选择。但我真的不熟悉高性能编解码器和文件格式。我将尝试使用此处描述的一些编解码器和格式:en.wikipedia.org/wiki/Video_file_format
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-07-04
  • 1970-01-01
  • 2021-01-06
  • 1970-01-01
  • 1970-01-01
  • 2016-02-12
相关资源
最近更新 更多