Whether or not this is possible depends on your container and codec being used. Assuming the codec allows retrieving the total number of frames, you can do something like this:
import imageio.v3 as iio
import numpy as np
my_video = "imageio:cockatoo.mp4"
props = iio.improps(my_video, plugin="pyav")
# Make sure the codec knows the number of frames
assert props.shape[0] != -1
for idx in np.linspace(0, props.shape[0]-1, 5, dtype=int):
# imageIO < 2.21.0
image = iio.imread(my_video, index=idx)
# imageIO > 2.21.0
# image = iio.imread(my_video, index=idx, plugin="pyav")
iio.imwrite(f"delete_me/frame_{idx:03d}.png", image)
A few notes:
- you want to use pyav for the call to
iio.improps
, because it doesn't decode frames, so it is fast.
- some codecs or containers (especially when streaming video) either don't report or can't report the number of frames stored within. In this case
props.shape[0]
will be -1
and we can't use this method.
- normally I'd recommend using pyav for the
imread
call as well, but there is a bug in the plugin that causes an EoF exception when trying to index=
to the last frame. This will be fixed by #855, though I can't say if it will make it into this weekly release or the next.
- if the codec used doesn't guarantee constant framerate, you won't get any speed advantages over
iio.imiter
because we can't safely predict how far into the video to seek. If you know that your video has a constant framerate, however, you can use the constant_framerate
kwarg of the pyav plugin to speed things up. (IMPORTANT: if the video has variable framerate and you set this anyway the seek will not be accurate.)
- As usual, you can use
iio.imopen
if you want to do all of these operations without reopening the video each time.