Animation #2 - Make gif animation using OpenCV, PIL
In a previous post, you learned how to create simple animations using OpenCV and numpy. In this post, I'll show you how to create animations that move your eyes and save them as gif files. Prepare the following images in advance. These files can be downloaded from the following repo: https://github.com/raspberry-pi-maker/OpenCV
The animation loops indefinitely, but in the first loop we made a gif file. The thing to watch for is moving the pupil image to the count1.bmp image. Masking function process_masking is a function often used in the previous example. However, this function has changed slightly from the previous one.The reason for this is that when the pupil moves out of the eye region, it should not be drawn. The previous masking function does not have this feature.
Therefore, in order to avoid drawing pupils outside the eye area, the image background color and masking process must be done once again. The bold and italicized parts of the source code below have been modified for this purpose.
If you run the code above, you can see that the eye_test.gif file is created as follows.
You can download the source codes here(https://github.com/raspberry-pi-maker/OpenCV)
The animation loops indefinitely, but in the first loop we made a gif file. The thing to watch for is moving the pupil image to the count1.bmp image. Masking function process_masking is a function often used in the previous example. However, this function has changed slightly from the previous one.The reason for this is that when the pupil moves out of the eye region, it should not be drawn. The previous masking function does not have this feature.
<Result of using original masking function>
Therefore, in order to avoid drawing pupils outside the eye area, the image background color and masking process must be done once again. The bold and italicized parts of the source code below have been modified for this purpose.
<Result of using new masking function>
import cv2 import numpy as np from PIL import Image from PIL import ImageDraw import time, os images = ('count0.bmp', 'count1.bmp', 'count2.bmp') count = 0 #frame 0 ~ 9: closed eye #frame 10 ~ 59: open eye -->create eyeball FPS = 10 SLEEP = 1.0 / FPS img1 = cv2.imread(images[0]) img2 = cv2.imread(images[1]) img3 = cv2.imread(images[2]) left_eye = cv2.imread('left.png') right_eye = cv2.imread('right.png') gif_frames = [] def save_gif(frames, gifname, speed): #speed 100 frames[0].save(gifname, format='GIF', append_images=frames[1:], save_all=True, duration=speed, loop=0) def process_masking(base, mask, pos): h, w, c = mask.shape hb, wb, _ = base.shape x = pos[0] y = pos[1] masking_color = (103, 178, 199) #RGB #check mask position if(x > wb or y > hb): print(' invalid overlay position(%d,%d)'%(x, y)) return None #remove alpha channel if c == 4: mask = cv2.cvtColor(mask, cv2.COLOR_BGRA2BGR) #adjust mask if(x + w > wb): mask = mask[:, 0:wb - x] print(' mask X size adjust[W:%d] -> [W:%d]'%(w, wb - x)) if(y + h > hb): mask = mask[0:hb - y, :] print(' mask Y size adjust[H:%d] -> [H:%d]'%(h, hb - y)) h, w, c = mask.shape img = base.copy() bg = img[y:y+h, x:x+w] #overlay area try: for i in range(0, h): for j in range(0, w): B = mask[i][j][0] G = mask[i][j][1] R = mask[i][j][2] # if (int(B) + int(G) + int(R)): if ((int(B) + int(G) + int(R)) and int(bg[i][j][0]) != masking_color[2] and int(bg[i][j][1]) != masking_color[1] and int(bg[i][j][2]) != masking_color[0] ): bg[i][j][0] = B bg[i][j][1] = G bg[i][j][2] = R img[y:y+h, x:x+w] = bg except IndexError: #index (i, j) is out of the screen resolution. (화면 범위를 벗어남.) print(' index Error') return None return img def draw_eyeball(lx, ly, rx, ry): #left eye POS, right eye POS img = img2.copy() img = process_masking(img, left_eye, (lx, ly)) if img is None: return img = process_masking(img, right_eye, (rx, ry)) if img is None: return cv2.imshow('eye', img) cv2.waitKey(1) if(count == 0): img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) im_pil = Image.fromarray(img) gif_frames.append(im_pil) def play_eye(img, tm): start = time.time() cv2.imshow('eye', img) cv2.waitKey(1) if(count == 0): img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) im_pil = Image.fromarray(img) gif_frames.append(im_pil) end = time.time() time.sleep(max(0, (tm - (end - start)))) def play_open_eye(): reye_center = (350, 160) reye_left = (250, 160) reye_right = (450, 160) leye_center = (115, 150) leye_left = (20, 150) leye_right = (214, 150) dx_cnt = 10 drx = (reye_center[0] - reye_left[0]) / dx_cnt dlx = (leye_center[0] - leye_left[0]) / dx_cnt for i in range(dx_cnt): start = time.time() print('(%d, %d), (%d,%d)'%(leye_center[0] + dlx * i, leye_center[1], reye_center[0] + drx * i, reye_center[1])) draw_eyeball(int(leye_center[0] + dlx * i), leye_center[1], int(reye_center[0] + drx * i) , reye_center[1]) end = time.time() time.sleep(max(0, SLEEP - (end - start))) #right->left for i in range(dx_cnt * 2): start = time.time() draw_eyeball(int(leye_right[0] - dlx * i), leye_right[1], int(reye_right[0] - drx * i), reye_right[1]) end = time.time() time.sleep(max(0, SLEEP - (end - start))) #left -> center for i in range(dx_cnt ): start = time.time() draw_eyeball(int(leye_left[0] + dlx * i), leye_left[1], int(reye_left[0] + drx * i), reye_left[1]) end = time.time() time.sleep(max(0, SLEEP - (end - start))) #center stop for i in range(dx_cnt ): start = time.time() draw_eyeball(int(leye_center[0] ), leye_center[1], int(reye_center[0] ) , reye_center[1]) end = time.time() time.sleep(max(0, SLEEP - (end - start))) #close eye #half eye play_eye(img3, SLEEP) # play_eye(img1, SLEEP * 2) count = 0 while True: try: print('play closed eye') play_eye(img1, SLEEP * FPS) print('play open eye') play_open_eye() if(count == 0): save_gif(gif_frames, "./eye_test.gif", 100) count += 1 except KeyboardInterrupt: break
If you run the code above, you can see that the eye_test.gif file is created as follows.
Wrapping up
If you are familiar with image processing tools like Photoshop, you can easily create simple gif animations. But I'm very bad at using image processing tools like Photoshop, gimp, etc. Therefore, it is much easier to create simple animations with programming.You can download the source codes here(https://github.com/raspberry-pi-maker/OpenCV)
댓글
댓글 쓰기