8.3.2 - Thank You#
Here is a simple assembly of a Thank You image.

How it works:#
The script uses two images with characters, and one with the bubble:



The main logic is to use a sine function to calculate smooth movements. For frame i the coordinate x would be:
\[x = sin(\frac{i}{i_{max}} \cdot (end - start)) + start\]
At the end, the image is cropped, so that the logo parts seem to move in from the outside.
Installation#
The script requires the OpenCV library for displaying the live animation and imageio for exporting animated GIFs.
pip install opencv-python
pip install imageio
The code#
import numpy as np
import cv2
import math
import imageio
import time
BLACK = (0, 0, 0)
FRAME1 = 80
FRAME2 = 20
FRAME3 = 10
MAXX = 2000
MAXY = 800
YCHARS = 300
XCENTER = 1000 - 341 // 2
def sine_move(start, end, frames, wait_frames=0):
"""
smooth movement from a to b using a sine function.
remain in end position forever
"""
for _ in range(wait_frames):
yield start
for i in range(frames):
angle_rad = i / frames * math.pi / 2
if end > start:
value = int(math.sin(angle_rad) * (end - start) + start)
else:
value = start - int(math.sin(angle_rad) * (start - end))
yield value
while True:
yield value
def create_text():
text = np.zeros((100, 300, 3), np.uint8) + 255
return cv2.putText(
text,
"Thank You",
(10, 50),
cv2.FONT_HERSHEY_TRIPLEX,
fontScale=1.0,
color=BLACK,
thickness=2,
)
background = np.zeros((MAXY, MAXX, 3), np.uint8) + 255
panda = cv2.imread("panda.png")[::2, ::2]
pingu = cv2.imread("pingu.png")[::2, ::2]
bubble = cv2.imread("bubble.png")[::2, ::2]
ysize, xsize, _ = panda.shape
text = create_text()
frames = []
xgen = sine_move(0, XCENTER, FRAME1)
ygen = sine_move(0, 170, FRAME2, wait_frames=FRAME1)
fade = sine_move(start=255, end=0, frames=50, wait_frames=FRAME1 + FRAME2 + 5)
while True:
# display frames
frame = background.copy()
xpanda = next(xgen)
xpingu = MAXX - pingu.shape[1] - xpanda
frame[YCHARS: YCHARS + ysize, xpanda : xpanda + xsize] = panda
frame[YCHARS: YCHARS + ysize, xpingu : xpingu + xsize] &= pingu
frame[YCHARS-150: YCHARS-150 + bubble.shape[0], XCENTER: XCENTER + bubble.shape[1]] =\
np.maximum(bubble, next(fade))
ytext = next(ygen)
frame[ytext: ytext + 100, XCENTER + 40:XCENTER + 340] &= text
frame = frame[100:550, 500:-500] # crop
cv2.imshow("frame", frame)
key = chr(cv2.waitKey(1) & 0xFF)
if key == "q":
break
time.sleep(0.03)
# shrink frame for using it on the web
rgb = cv2.cvtColor(frame[::2, ::2], cv2.COLOR_BGR2RGB)
frames.append(rgb)
cv2.destroyAllWindows()
# imageio.mimsave('thank_you_animation.gif', frames, fps=25)