Pygameを使ってフラクタルツリー(FractalTree)を作る方法


0.はじめに

今回作るものがどういう感じで動くのか見てみたい、この記事を読むのが面倒くさい方はこちら(Youtubeの動画)をご覧ください。

1.実装

fractal_tree.py
import pygame
import math
import random

pygame.init()
win = pygame.display.set_mode((750, 650))

def drawTree(a, b, pos, deepness):
   if deepness:
      branch1 = random.randint(1,10)
      branch2 = random.randint(1,10)
      c = a + int(math.cos(math.radians(pos)) * deepness * branch1)
      d = b + int(math.sin(math.radians(pos)) * deepness * branch2)
      pygame.draw.line(win, (255,255,255), (a, b), (c, d), 1)
      drawTree(c, d, pos - 20, deepness - 1)
      drawTree(c, d, pos + 20, deepness- 1)
   else:
      pygame.draw.circle(win,(0,255,0),(a,b),2,0)

drawTree(370, 650, -90,10)
pygame.display.flip()
while True:
   for event in pygame.event.get():
      if event.type == pygame.QUIT:
         pygame.quit()

ここでは、まず棒を描き、そこから一定の角度を引いたり足したりして三角関数を使って次の棒まで距離を縦横求め元の棒にそれを足してというのを繰り返しています。pygameでは下に行くほどyの値が大きくなり、木は上に伸ばしたいので角度はマイナスからスタートしています。また、ここではリアルな感じにするためにランダムにbranch1とbranch2を作っていますがそこを両方10にすると普通のフラクタルツリーになります。

2.OpenCVを使って木の形を変えてみる

FractalTree.py
import cv2
import math
import numpy as np

def nothing(x):
    pass

def drawTree(a, b, pos, deepness,angle,img):
    if deepness:
        c = a + int(math.cos(math.radians(pos)) * deepness * 10.0)
        d = b + int(math.sin(math.radians(pos)) * deepness * 10.0)
        cv2.line(img,(a, b), (c, d),(255,255,255),1)
        drawTree(c, d, pos - angle, deepness - 1,angle,img)
        drawTree(c, d, pos + angle, deepness- 1,angle,img)

def draw(event,x,y,flags,param):
    global img
    img = np.zeros((800,800,3),np.uint8)
    b = cv2.getTrackbarPos('bar','image')
    drawTree(370, 650, -90,10,angle=b,img=img)

img = np.zeros((800,800,3),np.uint8)
cv2.namedWindow('image')
cv2.createTrackbar('bar','image',0,360,nothing)
cv2.setMouseCallback('image',draw)

while True: 
    k = cv2.waitKey(1) & 0xFF
    if k == ord('q'):
        break
    cv2.imshow('image',img)
cv2.destroyAllWindows()

細かい説明はしませんが、ここでは、OpenCVを使ってトラックバーを作り、最初から引いたり足したりする角度を変えることで色々な木の形を作れるようにしています。動作が重くなってしまいましたが、なんとかできました。

最後に

今回作ったものはYoutubeでも解説しているのでそちらも良かったらご覧ください。質問、アドバイスがあればぜひコメントをよろしくお願いします。