diff --git a/rolling-shutter-continuous.py b/rolling-shutter-continuous.py new file mode 100644 index 0000000..ec2ce38 --- /dev/null +++ b/rolling-shutter-continuous.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +import tkinter as tk +import numpy as np +import time +from PIL import Image, ImageTk # pillow fork of PIL + +root = tk.Tk() +label = tk.Label(root) +label.pack() +height = 600 +x, y = np.ogrid[-height/2: height/2, -height/2: height/2] +plane = x + 1j * y +plane_abs = abs(plane) +propeller_angular_speed=1 + +frame_cache = {} +propeller_cache = {} +frame = 0 + +while True: + frame_base_angle = 2 * np.pi * ( propeller_angular_speed * frame / height + 1/12) + frame_base_angle %= np.pi/3 + frame_base_angle = round(frame_base_angle, 3) + if frame_base_angle in frame_cache: + print('frame hit') + image = frame_cache[frame_base_angle] + time.sleep(1/500) + else: + print('frame miss') + bentprop = np.zeros_like(plane, dtype=np.bool) + for line in range(height): + line_base_angle = 2 * np.pi * ( propeller_angular_speed * (frame+line) / height + 1/12) + line_base_angle %= np.pi/3 + line_base_angle = round(line_base_angle, 3) + if line_base_angle in propeller_cache: + propellors = propeller_cache[line_base_angle] + else: + propellors = np.zeros_like(plane, dtype=np.bool) + for blade in range(6): + this_angle = line_base_angle + blade * np.pi/3 + phase = np.exp( 1j * this_angle) + ellipse = abs(plane - 0.49 * height * phase) + plane_abs + this_propellor = ellipse < 0.5 * height + propellors |= this_propellor + propeller_cache[line_base_angle] = propellors + + bentprop[line] = propellors[line] + #greenbar = list(range(frame, min(frame + 3, height -3))) + colors = ("white","lightblue","red","green") + rgbcolors = np.array(list(map(root.winfo_rgb, colors))) / 256 + composite = bentprop*2 + #composite[greenbar] = 3 + rgb = rgbcolors.astype(np.uint8)[composite] + image = ImageTk.PhotoImage(Image.fromarray(rgb, mode="RGB")) + frame_cache[frame_base_angle] = image + label.config(image=image) + root.update() + frame += 1 + +root.mainloop() + diff --git a/rolling-shutter-tkinter.py b/rolling-shutter-tkinter.py index 0b8a2f4..a90c8a0 100644 --- a/rolling-shutter-tkinter.py +++ b/rolling-shutter-tkinter.py @@ -10,27 +10,40 @@ height = 600 x, y = np.ogrid[-height/2: height/2, -height/2: height/2] plane = x + 1j * y +plane_abs = abs(plane) bentprop = np.zeros_like(plane, dtype=np.bool) +propeller_angular_speed=1 +animation_speed=3 + +propeller_cache = {} for frame in range(height): - backgnd = np.zeros_like(plane, dtype=np.uint8) - propellor = np.zeros_like(plane, dtype=np.bool) - angle = 2 * np.pi * ( frame / height + 1/12) - for blade in range(6): - phase = np.exp( 1j * (angle + blade * np.pi/3)) - ellipse = abs(plane - 0.49 * height * phase) + abs(plane) - propellor |= ellipse < 0.5 * height + base_angle = 2 * np.pi * ( propeller_angular_speed * frame / height + 1/12) + base_angle %= np.pi/3 + base_angle = round(base_angle, 3) + if base_angle in propeller_cache: + propellors = propeller_cache[base_angle] + else: + propellors = np.zeros_like(plane, dtype=np.bool) + for blade in range(6): + this_angle = base_angle + blade * np.pi/3 + phase = np.exp( 1j * this_angle) + ellipse = abs(plane - 0.49 * height * phase) + plane_abs + this_propellor = ellipse < 0.5 * height + propellors |= this_propellor + propeller_cache[base_angle] = propellors - bentprop[frame] = propellor[frame] - greenbar = [f for f in range(frame, min(frame + 3, height -3))] - colors = ("white","lightblue","red","green") - rgbcolors = np.array(list(map(root.winfo_rgb, colors))) / 256 - composite = np.maximum.reduce((backgnd, propellor*1, bentprop*2)) - composite[greenbar] = 3 - rgb = rgbcolors.astype(np.uint8)[composite] - image = ImageTk.PhotoImage(Image.fromarray(rgb, mode="RGB")) - label.config(image=image) - root.update() + bentprop[frame] = propellors[frame] + if frame % animation_speed == 0: + greenbar = list(range(frame, min(frame + 3, height -3))) + colors = ("white","lightblue","red","green") + rgbcolors = np.array(list(map(root.winfo_rgb, colors))) / 256 + composite = np.maximum.reduce((propellors*1, bentprop*2)) + composite[greenbar] = 3 + rgb = rgbcolors.astype(np.uint8)[composite] + image = ImageTk.PhotoImage(Image.fromarray(rgb, mode="RGB")) + label.config(image=image) + root.update() root.mainloop() diff --git a/rolling-shutter-vary_propeller_speed.py b/rolling-shutter-vary_propeller_speed.py new file mode 100644 index 0000000..94d552d --- /dev/null +++ b/rolling-shutter-vary_propeller_speed.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 + +import tkinter as tk +import numpy as np +import os +from PIL import Image, ImageTk # pillow fork of PIL + +root = tk.Tk() +label = tk.Label(root) +label.pack() +height = 600 +x, y = np.ogrid[-height/2: height/2, -height/2: height/2] +plane = x + 1j * y +plane_abs = abs(plane) +propeller_cache = {} +file_name_counter=0 + +for propeller_angular_speed in np.arange(0.03, 2.001, 0.03): + bentprop = np.zeros_like(plane, dtype=np.bool) + + for frame in range(height): + base_angle = 2 * np.pi * ( propeller_angular_speed * frame / height + 1/12) + base_angle %= np.pi/3 + base_angle = round(base_angle, 3) + if base_angle in propeller_cache: + propellors = propeller_cache[base_angle] + else: + propellors = np.zeros_like(plane, dtype=np.bool) + for blade in range(6): + this_angle = base_angle + blade * np.pi/3 + phase = np.exp( 1j * this_angle) + ellipse = abs(plane - 0.49 * height * phase) + plane_abs + this_propellor = ellipse < 0.5 * height + propellors |= this_propellor + propeller_cache[base_angle] = propellors + + bentprop[frame] = propellors[frame] + #greenbar = list(range(frame, min(frame + 3, height -3))) + colors = ("white","lightblue","red","green") + rgbcolors = np.array(list(map(root.winfo_rgb, colors))) / 256 + composite = np.maximum.reduce((propellors*1, bentprop*2)) + #composite[greenbar] = 3 + rgb = rgbcolors.astype(np.uint8)[composite] + image = Image.fromarray(rgb, mode="RGB") + image.save('vary_speed/{}.png'.format(file_name_counter)) + file_name_counter += 1 + tk_image = ImageTk.PhotoImage(image) + label.config(image=tk_image) + root.update() + +os.system("ffmpeg -y -loglevel warning -r 7 -i vary_speed/%d.png " + + "-framerate 25 -pix_fmt yuv420p vary_speed.mp4") + +root.mainloop() +