A bad solution (with Pillow) and a good solution (with OpenCV).
- Bad Solution
- Good Solution
- Plans for this series
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.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.
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.