Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Preview: Example of Viewing a Video

stough, 202-

I’ve written put together two utility functions that could be helpful. First is loadvideo, which given a filename uses opencv to read the video file into a numpy array (frames x height x width x 3 color channels) for further evaluation. The second is makeVideo, which takes such an array shape that you might have made yourself and makes a video object that can be displayed in a notebook. See the implementation details in vis_utils.

(143, 204, 204, 3)

A video is just a stack of images. loadvideo gives us a 4D ndarray of shape (frames×height×width×3)(frames \times height \times width \times 3), of 8-bit unsigned integers. Everything we know about indexing images from the numpy tutorial still applies, with one more axis at the front for time:

  • vid[0] is the first frame, an ordinary RGB image;

  • vid[:, 100, 200] is the color of one pixel location over the whole video, a (frames×3)(frames \times 3) array;

  • vid[::10] keeps every tenth frame.

Let’s look at a few frames directly before animating.

<Figure size 1000x250 with 4 Axes>

To actually play the video, makeVideo builds a matplotlib FuncAnimation. That’s an object that calls an update function once per frame, swapping the image data with set_array, the same trick we used for sliders in the interactive visualization tutorial. It then renders the whole thing to an HTML/JavaScript player that the notebook can display. The %%capture magic in the next cell keeps the static figure matplotlib creates along the way from also showing up.

Loading...

 

Neighboring Frames Are Nearly the Same

Watch the video and you’ll notice that very little changes from one frame to the next. We can measure that directly by subtracting each frame from the one after it. (We cast to a signed type first: subtracting uint8s that would go negative wraps around instead.)

<Figure size 900x300 with 2 Axes>

The difference image is mostly black, nonzero only along the edges of things that moved. This scene has a lot of black background, so even the raw pixel values pile up at zero. Still, the frame differences are far more concentrated: more than half of them are exactly zero, and nearly all of the rest are small. This temporal coherence is the time analog of the spatial coherence between neighboring pixels. It’s exactly what video codecs exploit: rather than storing every frame, they store occasional full frames and, in between, mostly the (very compressible) differences. We’ll make this idea precise with entropy and predictive coding.