-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
131 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
Infinite Blossom | ||
================ | ||
|
||
|image0| | ||
|
||
How does it work | ||
---------------- | ||
|
||
The petals rotate around the center while getting closer. | ||
Therefore, they are represented by **polar coordinates**: an angle and a distance. | ||
The polar coordinates make the updating of petal positions very easy. | ||
Of course, some trigonometric functions need to be applied to convert polar coordinates to cartesian (x/y) coordinates. | ||
|
||
The animation happens on a canvas that is a lot bigger than the actual image. | ||
This is because new petals appear regularly at the borders of the image, but that part is cropped off for better aesthetics. | ||
The rest is optimizing the intervals in which the petals are places. | ||
|
||
For drawing filled polygons I originally wanted to write a numpy function from scratch. | ||
ChatGPT-3 told me there is a function `np.fill_poly()` and gave me a quite sophisticated code example. | ||
It turned out it was hallucinating and no such function exists. | ||
However, OpenCV has a fast enough function for drawing polygons. | ||
|
||
Prerequisites | ||
------------- | ||
|
||
This script requires two libraries: **OpenCV** for displaying the live | ||
animation and **imageio** for exporting animated GIFs. | ||
|
||
:: | ||
|
||
pip install opencv-python | ||
pip install imagio | ||
|
||
The Script | ||
---------- | ||
|
||
.. literalinclude:: blossom.py | ||
|
||
.. |image0| image:: infinite_blossom.gif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
|
||
import math | ||
import numpy as np | ||
import cv2 | ||
import time | ||
import imageio | ||
|
||
MAXX, MAXY = 3000, 3000 | ||
SIZE = 5 | ||
|
||
|
||
class Petal: | ||
""" | ||
Position of a petal in polar coordinates | ||
""" | ||
def __init__(self, angle, dist): | ||
self.angle = angle | ||
self.dist = dist | ||
|
||
@property | ||
def moving(self): | ||
return self.dist > 0 | ||
|
||
def update(self): | ||
self.angle += 1 | ||
self.dist -= 1 | ||
|
||
def polar_to_cartesian(self, angle, dist): | ||
rad = math.pi * angle / 180 | ||
x = math.cos(rad) * dist | ||
y = math.sin(rad) * dist | ||
return int(y), int(x) | ||
|
||
def draw(self, frame): | ||
multiplier = 1.2 + self.dist / 200 | ||
y1, x1 = self.polar_to_cartesian(self.angle, self.dist) | ||
y2, x2 = self.polar_to_cartesian(self.angle - 30, self.dist * multiplier) | ||
y3, x3 = self.polar_to_cartesian(self.angle + 30, self.dist * multiplier) | ||
|
||
col = (0, 64 - (64 * self.dist) // 360, 255 - (255 * self.dist)//360) | ||
|
||
offset = np.array([MAXY // 2, MAXX // 2]) | ||
vertices = np.array([[y1, x1], [y2, x2], [y3, x3]]) + offset | ||
cv2.fillPoly(frame, [vertices], col) | ||
|
||
|
||
def create_petals(dist, angle_offset=0): | ||
return [ | ||
Petal(angle_offset + 0, dist), | ||
Petal(angle_offset + 120, dist), | ||
Petal(angle_offset + 240, dist), | ||
] | ||
|
||
|
||
background = np.zeros((MAXY, MAXX, 3), np.uint8) | ||
petals = [] | ||
angle = 60 | ||
for dist in range(40, 400, 40): | ||
petals += create_petals(dist, angle) | ||
angle = 60 - angle | ||
|
||
|
||
frames = [] | ||
angle_ofs = 0 | ||
|
||
for i in range(240): | ||
frame = background.copy() | ||
# more all petals | ||
for p in petals: | ||
p.update() | ||
p.draw(frame) | ||
petals = [p for p in petals if p.moving] # remove finished petals | ||
|
||
cropped = frame[1200:-1200,1200:-1200] # cut off border where new petals appear | ||
cv2.imshow('frame', cropped) | ||
rgb = cv2.cvtColor(cropped, cv2.COLOR_BGR2RGB) | ||
frames.append(rgb) | ||
|
||
if i % 40 == 0: | ||
petals += create_petals(400, angle_ofs + i) | ||
angle_ofs = 60 - angle_ofs | ||
|
||
key = chr(cv2.waitKey(1) & 0xFF) | ||
if key == 'q': | ||
break | ||
|
||
time.sleep(0.03) | ||
|
||
cv2.destroyAllWindows() | ||
|
||
imageio.mimsave('infinite_blossom.gif', frames[::2], fps=20) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -94,6 +94,7 @@ Effects | |
vortex/README.rst | ||
sand/README.rst | ||
starwars/README.rst | ||
blossom/README.rst | ||
|
||
---- | ||
|
||
|