A bad solution (with Pillow) and a good solution (with OpenCV).
Contents:
- Bad Solution
- Good Solution
- Plans for this series
Bad Solution
My original approach was making another gif. I had to expect it was a bad idea as I wanted to merge a colorful JPEG background and an animated GIF.

So I used Pillow:
from PIL import Image, ImageSequence
background = 'data/background.jpg'
gif = 'data/intro.gif'
background = Image.open(background).convert("RGBA")
animated_gif = Image.open(gif)
fps = animated_gif.info['duration']
frames = []
for frame in ImageSequence.Iterator(animated_gif):
frame = frame.convert("RGBA")
clear_background = background.copy()
clear_background.paste(frame, mask=frame)
frames.append(clear_background)
frames.append(clear_background)
frames[0].save('output.gif', save_all=True, append_images=frames)
And as a result I got this:

It has decent FPS, but the number of colors is too low. It is typical and was to be expected.
However, if I change line 3 to:
background = Image.open(background) # .convert("RGBA")
Then the overall result changes, but it still corrupts the background:

See the difference between the original, RGBA and non-RGBA:

And of course they all are heavy af – all GIFs are.
Good Solution
I was too involved in the process of making the PIL script work I got carried away and spent too much time of what looked like a vain idea.
Let’s get back to our beloved OpenCV and try and find a solution for it.
First of all, we need to make a video that consists of just the background image:
import cv2
background_image = 'data/background.jpg'
gif_image = 'data/intro.gif'
# load the background picture nad get width/height
background = cv2.imread(background_image)
background = background.astype(float)
height, width, color = background.shape
# set up the final video with 25 fps
video_destination = 'clips/intro.avi'
video = cv2.VideoWriter(video_destination, 0, 25, (width, height))
# open GIF
gifcap = cv2.VideoCapture(gif_image)
# iterated GIF frames and add it to the background while the GIF lasts
while gifcap.isOpened():
ret, frame = gifcap.read()
if ret:
output = frame.copy()
foreground = output.astype(float)
output = cv2.add(foreground, background).astype(np.uint8)
video.write(output)
else: break
# close the GIF
gifcap.release()
# close the resulting video
video.release()
This became easy once I found the cv2.add(foreground, background) method.
As a result I got a perfectly good video. The result you see below is a GIF I generated from the video I got (as WordPress does not let me upload a video unless I pay them $100 – tough luck). The quality is not ideal.

Plans for this series
The next posts in the series will be about
- Making a small GIF out of a big video (like the result you see above).
- Resizing videos
- Adding a GIF on the foreground of a video (or GIF) background.
- Lowering the size of videos with python-ffmpeg.
[…] The video_1.avi and video_4.avi include GIFs, I wrote about how I achieved that in the previous post of the Video Generation series. […]
LikeLike
[…] I already have a post about it, go check it out: https://djangokatya.com/2021/07/06/how-to-add-gif-to-a-static-background-python-opencv/ […]
LikeLike
[…] code is pretty much the same as here How to add GIF to a static background (Python + OpenCV). Video Generation series (Part 1), except for the loop […]
LikeLike