`videoutils` lets you get rid of writing boilerplate code for reading video and adds some convenience on top of that.

Install

pip install videoutils

How to use

from videoutils.io import read_video, as_tensor, bgr2rgb, resize
fname = 'files/interstellar-waves-edit.mp4'
x = read_video(fname)
len(x)
x[0].shape
1578
(480, 720, 3)

By default, read_video returns a list of np.arrays of shape (height, width, channels).
However, you can define precisely which frames you'd like to grab in a number of ways. This is done by using either the {start_idx, end_idx, frame_stride} or target_frames arguments.

Grab the first n frames

n = 50
x  = read_video(fname, end_idx=n)
x2 = read_video(fname, target_frames=(0,n))

len(x)
len(x) == len(x2)
50
True

Grab every nth frame

n=5
x = read_video(fname, frame_stride=n, end_idx=50)
len(x)
10
x = read_video(fname, frame_stride=50) # total frames = 1578
len(x)
32

Grab frames at specific indices

x = read_video(fname, target_frames=[10, 50, 76, 420])
len(x)
4
x  = read_video(fname, start_idx=10, end_idx=15)
x2 = read_video(fname, target_frames=(10, 15))

len(x)
len(x) == len(x2)
5
True

Return as torch.Tensor

You can pass any function that transforms a np.array of shape (height, width, channels) to the apply argument. videoutils provides as_tensor for convenience -- if you use this function, read_video will automatically call torch.stack and return the collection of frames as a 4D tensor, else it will return a list of 3D arrays/tensors.

import torch
from functools import partial

x  = read_video(fname, end_idx=10, apply=as_tensor)
x2 = read_video(fname, end_idx=10, apply=partial(as_tensor, normalise=True))
x2 = torch.stack(x2) # since we aren't using `as_tensor`, but a partial (thus different) function

x.shape
x.shape == x2.shape
x.mean(), x2.mean()
torch.Size([10, 480, 720, 3])
True
(tensor(36.8276), tensor(0.1443))

Resize Video

read_video has an optional argument resize_func which is meant to be a function that resizes a np.array of shape (height, width, channels).
You can use the predefined resize function or pass in a custom function here.

help(resize)
Help on function resize in module videoutils.utils:

resize(image, height=None, width=None, keep_aspect_ratio=True, scale_factor=1.0)
    Resize by `scale_factor` if preserving aspect ratio else
    resize by custom `height` and `width`

x = read_video(fname, target_frames=[0,1,2], apply=as_tensor,
               resize_func=partial(resize, scale_factor=2.))
x.shape
torch.Size([3, 960, 1440, 3])
x = read_video(fname, target_frames=[0,1,2], apply=as_tensor,
               resize_func=partial(resize, width=200, height=100, keep_aspect_ratio=False))
x.shape
torch.Size([3, 100, 200, 3])