Skip to content

Instantly share code, notes, and snippets.

@smeschke
Created March 8, 2019 02:15
Show Gist options
  • Save smeschke/a55760c89aa8e59f9d126303077a1e04 to your computer and use it in GitHub Desktop.
Save smeschke/a55760c89aa8e59f9d126303077a1e04 to your computer and use it in GitHub Desktop.
Draws a spiraling swirl?
import cv2, numpy as np, math, random
# create a list for the particles
num_particles = 25000
particles = np.zeros((num_particles,5), np.float32)
# x, y, angle, size
for i in range(particles.shape[0]): particles[i] = -234,-1234,0,0,i
# define parameters
hw = 1080
center = int(hw/2),int(hw/2)
radius = 300
marks = 9
center_variability = 50
vector_length = 80
segment_length = 321
# For writing video
vid_writer = cv2.VideoWriter('/home/stephen/Desktop/olga.avi', cv2.VideoWriter_fourcc('M','J','P','G'), 60, (hw,hw))
# distance function
def distance(a,b): return math.sqrt((a[0]-b[0])**2 + (a[1]-b[1])**2)
# creates a new particle
def new_particle():
xy = (.5-random.random())*center_variability, (.5-random.random())*center_variability
return xy[0], xy[1], 0, 0, num_particles
# Sum of two vectors
def addVectors(a,b):
(angle1, length1), (angle2, length2) = a,b
x = math.sin(angle1) * length1 + math.sin(angle2) * length2
y = math.cos(angle1) * length1 + math.cos(angle2) * length2
angle = 0.5 * math.pi - math.atan2(y, x)
length = math.hypot(x, y)
return (angle, length)
# Get color
def get_color(d, h):
img = np.zeros((1,1,3), np.uint8)
r = d/4
r = int(r)
img[:,:,:] = r,255,255
img = cv2.cvtColor(img, cv2.COLOR_HSV2BGR)
return tuple(img[0,0])
# main loop
idx = 0
img = np.zeros((hw,hw,3), np.uint8)
for i in range(20): vid_writer.write(img)
while True:
idx += 1
# create a blank image
img = np.zeros((hw,hw,3), np.uint8)
# draw the particles
for x,y,_,_, size in particles:
color = get_color(distance((0,0), (x,y)), hw)
color= int(color[0]), int(color[1]), int(color[2])
cv2.circle(img, (int(x+center[0]),int(y+center[1])), 2, color, -1)
# move the particles
for i in range(particles.shape[0]):
x, y, angle, speed, size = particles[i]
new_x, new_y = math.sin(angle)*speed + x, math.cos(angle)*speed + y
# Draw the vector for the fluid
center_distance = distance((0,0), (x,y))
flow_angle = math.atan2(x/center_distance,y/center_distance) + math.pi/2
vector_end = x + math.sin(flow_angle)*67, y + math.cos(flow_angle)*67
xy = tuple(np.array((x+center[0],y+center[0]), int))
xy1 = tuple(np.array((vector_end[0]+center[0], vector_end[1]+center[0]), int))
#cv2.line(img, xy, xy1, (255,0,255), 1)
flow_speed = .6*(hw-center_distance)/hw
speed = speed * .9
new_angle, new_speed = addVectors((angle, speed), (flow_angle, flow_speed))
particles[i] = new_x, new_y, new_angle, new_speed, size-1
# replace the particles that are too small
new = 0
for i in range(particles.shape[0]):
if new < 8:
if particles[i][4] < 1: particles[i], new = new_particle(), new+ 1
if particles[i][0] < -hw/2: particles[i], new = new_particle(), new+ 1
if particles[i][0] > hw/2: particles[i], new = new_particle(), new+ 1
if particles[i][1] < -hw/2: particles[i], new = new_particle(), new+ 1
if particles[i][1] > hw/2: particles[i], new = new_particle(), new+ 1
cv2.imshow('img', img)
vid_writer.write(img)
k = cv2.waitKey(1)
if k == 27: break
cv2.destroyAllWindows()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment