はじめに
pythonで万華鏡(のような動作をする)ようなコードを書きました。完成物のデモ動画が以下です。
画像の一部を切り取って、鏡に見立てて複製していきます。複製はopencvの関数である、フリップとスタックでおこなっていきました。
今回デモに使用した元画像です。
Code
作成したコードはこちらです。
import cv2
import numpy as np
import time
class Kaleidoscope():
def __init__(self, image, rotate=0):
self.h, self.w, _ = image.shape
self.crop_size = (self.h//2, self.w//2)
self.rotate = rotate
self.image = image
self.croped_image = image
self.kaleidoscope_img = None
# initialize position
self.top = np.random.randint(0, self.h - self.crop_size[0])
self.left = np.random.randint(0, self.w - self.crop_size[1])
def random_crop(self):
# set bottom, right
bottom = self.top + self.crop_size[0]
right = self.left + self.crop_size[1]
# generate croped img
self.croped_image = self.image[self.top:bottom, self.left:right, :]
self.croped_image = cv2.resize(self.croped_image, dsize=(self.h, self.w))
def generate_kaleidoscope(self):
# transpose the image
imgt = cv2.transpose(self.croped_image)
# create diagonal bi-tonal mask
mask = np.zeros((self.w, self.h), dtype=np.uint8)
points = np.array([[[0,0], [self.w,0], [self.w,self.h]]])
cv2.fillPoly(mask, points, 255)
# composite img and imgt using mask
compA = cv2.bitwise_and(imgt, imgt, mask=mask)
compB = cv2.bitwise_and(self.croped_image, self.croped_image, mask=255-mask)
comp = cv2.add(compA, compB)
# rotate -> flip -> concat -> flip -> concat -> resize
comp = self.set_rotate(comp)
mirror = cv2.flip(comp, 1)
top = np.hstack((comp, mirror))
bottom = cv2.flip(top, 0)
kaleidoscope_big = np.vstack((top, bottom))
self.kaleidoscope_img = cv2.resize(kaleidoscope_big, (0,0), fx=0.5, fy=0.5, interpolation=cv2.INTER_LINEAR)
def update(self):
r = np.random.randint(0,1)
if r == 0:
self.top += 1
else:
self.left += 1
# reset
if self.top > self.h-self.crop_size[0] or self.left > self.w-self.crop_size[1]:
self.top = np.random.randint(0, self.h - self.crop_size[0])
self.left = np.random.randint(0, self.w - self.crop_size[1])
self.random_crop()
self.generate_kaleidoscope()
return self.kaleidoscope_img
def set_rotate(self, comp):
if self.rotate == 90:
comp = cv2.rotate(comp,cv2.ROTATE_90_CLOCKWISE)
elif self.rotate == 180:
comp = cv2.rotate(comp,cv2.ROTATE_180)
elif self.rotate == 270:
comp = cv2.rotate(comp,cv2.ROTATE_90_COUNTERCLOCKWISE)
return comp
def main():
img = cv2.imread('liver.png')
myKaleidoscope = Kaleidoscope(img)
while True:
kaleidoscope = myKaleidoscope.update()
time.sleep(0.03)
cv2.imshow('kaleidoscope', kaleidoscope)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyWindow('kaleidoscope')
if __name__ == "__main__":
main()
おわりに
万華鏡は簡単なアルゴリズムの割に見栄えがとても綺麗ですよね。調べてもそれらしいコードが見つからなかったので、自作してみました。これを使ったインタラクティブ系の作品とかもできたら面白そうです。