Animation #1 - Simple animation using numpy
Yesterday, I wrote a blog post on rotating an image with OpenCV. I will explain how to create a simple animation using the rotate and pan functions of an image. I hope this learning will give you a deeper opportunity to learn more about OpenCV and numpy.
You need a bit of math knowledge to create natural animations.
Angular velocity refers to how fast an object rotates or revolves relative to another point, i.e. how fast the angular position or orientation of an object changes with time. I'm going to make an 30 FPS(frame per second) animation. Thus, the time per frame is 1/30 seconds (0.0333). If it takes 2 seconds to rotate the image 360 degrees, the angular velocity is π(radian)/sec. Thus, the angle traveled for 1/30 second is π(radian) / 30, and the distance that the circle rolled is R x π(radian) / 30.
Let's summarize.
Run the code.
You can get a animation file like this.
You can download the source codes here(https://github.com/raspberry-pi-maker/OpenCV)
Basic concept
Add an overlay image to the right of the canvas image. As time goes, rotate the overlay image and move it to the left.You need a bit of math knowledge to create natural animations.
Angular Velocity
Angular velocity refers to how fast an object rotates or revolves relative to another point, i.e. how fast the angular position or orientation of an object changes with time. I'm going to make an 30 FPS(frame per second) animation. Thus, the time per frame is 1/30 seconds (0.0333). If it takes 2 seconds to rotate the image 360 degrees, the angular velocity is π(radian)/sec. Thus, the angle traveled for 1/30 second is π(radian) / 30, and the distance that the circle rolled is R x π(radian) / 30.
<image from https://www.shelovesmath.com/trigonometry/linear-and-angular-speeds-area-of-sectors-and-length-of-arcs/>
Let's summarize.
- FPS = 30
- Angular Velocity(radian) = π(radian) / sec
- Angular Velocity(degree) = 180(degree) / sec
- step_angle(radian) = π(radian) / FPS
- step_angle(degree) = 180(degree) / FPS
- step_movement(pixel) = step_angle(radian) * R = step_angle(radian) * (h/2)
Make animation
import argparse import cv2 import numpy as np import time FPS = 30 angular_velocity = np.degrees(np.pi) # I'll make 1 rotation per 2 seconds step_angle = angular_velocity / FPS step_radian = np.radians(step_angle) max_count = 3 def process_masking(base, mask, pos): h, w, c = mask.shape hb, wb, _ = base.shape x = pos[0] y = pos[1] #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)): 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 delay_fps(s): while (time.time() - s < (1.0 / FPS) ): time.sleep(0.001) parser = argparse.ArgumentParser(description="OpenCV Example") parser.add_argument("--file", type=str, required=True, help="filename of the input image to process") args = parser.parse_args() mask = cv2.imread(args.file, cv2.IMREAD_COLOR) height, width, channels = mask.shape print("image H:%d W:%d, Channel:%d"%(height, width, channels)) print('Angular Velocity:%f step_angle:%f'%(angular_velocity, step_angle)) canvas = np.zeros((height * 2, width * 5, 3), np.uint8) c_height, c_width, c_channels = canvas.shape fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v') out_video = cv2.VideoWriter('./animation.mp4', fourcc, 30, (c_width, c_height)) angle = step_angle x_pos = (c_width - width)*1.0 count = 0 while count < max_count: matrix = cv2.getRotationMatrix2D((width/2, height/2), angle, 1) rotate = cv2.warpAffine(mask, matrix, (width, height)) s = time.time() angle += step_angle if(angle > 360): angle = angle % 360 print('x_pos:%f'%(x_pos)) img = process_masking(canvas, rotate, (int(x_pos),0)) x_pos -= step_radian * height / 2.0 print('x_pos:%f'%(x_pos)) out_video.write(img) cv2.imshow('rotate', img) if(x_pos < count * width): x_pos = (c_width - width)*1.0 count += 1 canvas = img.copy() k = cv2.waitKey(1) delay_fps(s) out_video.release() cv2.waitKey(0) cv2.destroyAllWindows()
Run the code.
python animation_rotate.py --file=sbear.png image H:64 W:64, Channel:3 Angular Velocity:180.000000 step:6.000000
You can get a animation file like this.
You can download the source codes here(https://github.com/raspberry-pi-maker/OpenCV)
댓글
댓글 쓰기