From video to frames

Use imageio library to get frames out of a video. I used a sample.mp4 video as the example. Install imageio with pip install imageio-ffmpeg to use the video-format support of the library.

import os
import imageio
import matplotlib.pyplot as plt

os.environ["VIDEO_PATH"] = "data/2021-10-20-from-video-to-image/sample.mp4"
os.environ["IMAGE_PATH"] = "data/2021-10-20-from-video-to-image/sample_frame.jpeg"

I set 1 frame per second and the image size to be (1080, 1920). If the size parameter is not specified the reader will infer from the video file.

reader = imageio.get_reader(
    os.environ["VIDEO_PATH"], 
    fps=1, 
    size=(1080, 1920)
)
The frame size for reading (1080, 1920) is different from the source frame size (1920, 1080).

Get the frames out of the video:

frames = []
for i, im in enumerate(reader):
    frames.append(im)
    print('Mean of frame %i is %1.1f' % (i, im.mean()))
Mean of frame 0 is 128.8
Mean of frame 1 is 128.7
Mean of frame 2 is 128.4
Mean of frame 3 is 120.3
Mean of frame 4 is 122.5
Mean of frame 5 is 128.6
Mean of frame 6 is 132.4
Mean of frame 7 is 134.1
Mean of frame 8 is 137.4
Mean of frame 9 is 137.0
Mean of frame 10 is 135.7
Mean of frame 11 is 131.2
Mean of frame 12 is 131.9

Frame data type

The frames are of type imageio.core.util.Array. We can convert them to numpy array if necessary with np.array.

frames[0].__class__
imageio.core.util.Array
import numpy as np

image = np.asarray(im)
image.__class__
numpy.ndarray

Crop a square in the center of the image

def crop_center_square(frame):
    y, x = frame.shape[0:2]
    min_dim = min(y, x)
    start_x = (x // 2) - (min_dim // 2)
    start_y = (y // 2) - (min_dim // 2)
    return frame[start_y : start_y + min_dim, start_x : start_x + min_dim]

Example:

i = 0
plt.figure(figsize=(10, 10))
ax = plt.subplot(1, 2, 1)
plt.imshow(frames[i])
ax = plt.subplot(1, 2, 2)
plt.imshow(crop_center_square(frames[0]))
<matplotlib.image.AxesImage at 0x148fe09d0>

Plot cropped frames

i = 0
plt.figure(figsize=(10, 10))
for idx, im in enumerate(frames[0:12]):
    ax = plt.subplot(3, 4, idx + 1)
    plt.imshow(crop_center_square(frames[idx]))

Save/load a frame

Save:

imageio.imwrite(os.environ["IMAGE_PATH"], frames[0])

Load:

image = imageio.imread(os.environ["IMAGE_PATH"])

plt.figure(figsize=(10, 10))
plt.imshow(image)
<matplotlib.image.AxesImage at 0x149aafe80>