pythonimageimage-processingh5pypython-imageio

Adding Text to GIF made with `imageio.mimread()`


I am working with this data analysis pipeline that makes gifs of video recordings, the function used for this is:

def make_gif(self, datafile, save_file, frame_limit:int=20, fps:int=10, verbose=True):
    h5 = h5py.File(datafile, "r")
    frames = h5['frames'][::2][:frame_limit]
    imageio.mimwrite(save_file, frames, fps=fps)
    if verbose:
        print(f"Saved gif version: fps={fps}, nframes={frame_limit}", flush=True)

The only necessary imports for this are h5py and imageio.

I'm needing to append some text to these gifs. There's some metadata we need displayed for quick reading. For example, I have a stack of frames that look like this image:

Image 1 - no text

But what I need is something like this:

Image 2 - with text

How would I go about doing that with Python and imageio? I should note that I cannot save the individual images as jpgs for reuploading later, I need to create the gifs as part of the pipeline.


Solution

  • Our focus with ImageIO is on the IO side of images. If you want to add text to an image or perform any other processing of the image, you will want to bring in an image processing library. Common choices here are scikit-image or opencv.

    Here is an example of how you can do this using cv2. Note that I am using a standard image here for better reproducibility, but the same logic works with HDF5 and other video/image formats.

    import imageio.v3 as iio
    import cv2
    
    frames = iio.imread("imageio:newtonscradle.gif")  # example image/frames
    
    # add the text
    for frame in frames:
        foo = cv2.putText(
            frame,
            "Hey look some metadata",
            (5, 25),
            cv2.FONT_HERSHEY_SIMPLEX,
            .4,
            (0, 0, 0)
        )
    
    # write the output
    iio.imwrite("annotated.gif", frames, loop=0)
    

    Output:

    annotated animated image

    Weirdly, scikit-image doesn't allow rendering text onto an image, but there is an age-old issue to track that feature here.


    Alternatively, if visualization is what you are after, you could use matplotlib. This comes with the advantage of giving you all the power of the MPL but comes with the drawback of losing control over individual pixels. This is not ideal for scientific processing (where pixel values matter), but great for quick annotations, human consumption, and qualitative data.

    Here is an example how you could recreate the above:

    import imageio.v3 as iio
    import numpy as np
    import matplotlib.pyplot as plt
    from matplotlib.figure import figaspect
    
    frames = iio.imread("imageio:newtonscradle.gif")
    aspect_ratio = figaspect(frames[0, ..., 0])
    annotated_frames = list()
    for frame in frames:
        fig, ax = plt.subplots(figsize=aspect_ratio, dpi=50)
        ax.imshow(frame)
        ax.text(5, 5, "Hey look some metadata", fontsize="xx-large", va="top")
        ax.set_axis_off()
        ax.set_position([0, 0, 1, 1])
        fig.canvas.draw()
        annotated_frames.append(np.asarray(fig.canvas.renderer.buffer_rgba()))
        plt.close(fig)
    
    iio.imwrite("annotated.gif", annotated_frames, loop=0)
    

    Output:

    MPL gif