Why is `capture.set(cv2.CAP_PROP_POS_FRAMES, i)` so slow?

I am trying to sample every 5th frame from a source. I can either iterate through the frames and pick every 5th frame and discard the rest like:

def sample_video_loop(capture, sampling_gap=5, batch_size=5):
    frames = []
    for i in range(batch_size):
        for j in range(sampling_gap):
            ret, f0 = capture.read()
        frames += [f0]
    return frames

Or I can use the VideoCapture set() method to set the property cv2.CAP_PROP_POS_FRAMES to like:

def sample_video_set_pos(capture, sampling_gap=5, batch_size=5):
    frames = []
    pos = 0
    for i in range(batch_size):
        ret, f0 = capture.read()
        pos += sampling_gap
        capture.set(cv2.CAP_PROP_POS_FRAMES, pos)
        frames += [f0]
    return frames

Without checking the implementation ideally the latter method should be faster. But when i timed it, it is 3-4 times slower.

%%timeit
frames = sample_video_loop(dataset, 5, 5)

>>> 98.4 ms ± 5.49 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%%timeit
frames = sample_video_set_pos(dataset, 5, 5)

>>> 305 ms ± 16.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Is this a bug or am i missing something? If not then what is the best practice to sample frames?

Thanks in advance.

no bug here, “random access” in video IS slow.
whenever you send it to frame x, it has to decode from the previous to the next key frame, to deliver a single image.

i’d say, you found out already :wink:

1 Like

That’s a bit disappointing but makes sense. Thanks.