Neurostories: creating videos of the flash-lag effect
In [1]:
from __future__ import division, print_function
import numpy as np
np.set_printoptions(precision=6, suppress=True)
import os
%matplotlib inline
#%config InlineBackend.figure_format='retina'
%config InlineBackend.figure_format = 'svg'
import matplotlib.pyplot as plt
import proglog
proglog.notebook()
#%load_ext autoreload
#%autoreload 2
the simplest approach¶
In [2]:
__author__ = "Laurent Perrinet INT - CNRS"
__licence__ = 'BSD licence'
print('😎 Welcome to the script generating the movies 😎')
import os
home = os.environ['HOME']
figpath = '../files/'
def path2(fname):
return os.path.join(figpath, fname)
import numpy as np
import gizeh as gz
import moviepy.editor as mpy
W, H = 1000, 600
duration = 2.
fps = 100
def create_movie(figname, r = 16,
duration = duration,
start = duration*.2,
stop = duration*.8, do_stop=False,
t_flash = 1.,
duration_flash = .02,
flash_fill=(0,1,0),
dot_fill=(1,0,0),
fps = fps,
W=W, H=H):
flash = gz.rectangle(lx=r, ly=r, xy=(W/2., H/2.-r), fill=flash_fill)
def make_frame(t):
surface = gz.Surface(W, H, bg_color=(0, 0, 0))
if np.abs(t-t_flash) < duration_flash: flash.draw(surface)
if start < t < stop:
if do_stop and t >= duration/2:
flash.draw(surface)
rect = gz.rectangle(lx=r, ly=r, xy=(W/2, H/2.+r), fill=dot_fill)
else:
rect = gz.rectangle(lx=r, ly=r, xy=(W*t/duration, H/2.+r), fill=dot_fill)
rect.draw(surface)
return surface.get_npimage()
clip = mpy.VideoClip(make_frame, duration=duration)
clip.write_videofile(path2(figname), fps=fps)
return clip
figname = '2019-09-30_flash_lag.mp4'
if True: # not os.path.isfile(path2(figname)):
clip = create_movie(figname)
clip = mpy.VideoFileClip(path2(figname))
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
Out[2]:
In [3]:
figname = '2019-09-30_flash_lag_stop.mp4'
if True: # not os.path.isfile(path2(figname)):
clip = create_movie(figname, do_stop=True)
clip = mpy.VideoFileClip(path2(figname))
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
Out[3]:
In [4]:
t_flashes = [0.90, 0.95, 1, 1.05, 1.10]
n_flashes = len(t_flashes)
color_flashes = [(0, v, 1-v) for v in np.linspace(0, 1, n_flashes, endpoint=True)]
In [5]:
for i, (t_flash, flash_fill) in enumerate(zip(t_flashes, color_flashes)):
figname = f'2019-09-30_flash_lag_{i}.mp4'
if not os.path.isfile(path2(figname)):
clip = create_movie(figname, t_flash=t_flash, flash_fill=flash_fill)
#clip = mpy.VideoFileClip(path2(figname))
#clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
mutiple horizontal panels: varrying timing¶
In [6]:
__author__ = "Laurent Perrinet INT - CNRS"
__licence__ = 'BSD licence'
print('😎 Welcome to the script generating the movies 😎')
import os
home = os.environ['HOME']
figpath = '../files/'
def path2(fname):
return os.path.join(figpath, fname)
import numpy as np
import gizeh as gz
import moviepy.editor as mpy
W, H = 1000, 600
duration = 2.
fps = 100
def create_movie(figname, r = 16,
duration = duration,
start = duration*.2,
stop = duration*.8, do_stop=False,
#t_flashes = [1.05, 0.90, 1.10, 0.95, 1],
t_flashes = [1.05, .95, 1],
duration_flash = .05,
flash_fill=(0,1,0),
dot_fill=(1,0,0),
fps = fps,
W=W, H=H):
n_flashes = len(t_flashes)
color_flashes = [(0, v, 1-v) for v in np.linspace(0, 1, n_flashes, endpoint=True)]
Hs = [v for v in np.linspace(0, H, 2*n_flashes+1, endpoint=True)] # all intermediate positions
Hs = Hs[1::2] # from the first one, take one from two = +|+|+|+
def make_frame(t):
surface = gz.Surface(W, H, bg_color=(0, 0, 0))
for i, (t_flash, flash_fill, H_) in enumerate(zip(t_flashes, color_flashes, Hs)):
flash = gz.rectangle(lx=r, ly=r, xy=(W/2., H_-r), fill=flash_fill)
if np.abs(t-t_flash) < duration_flash: flash.draw(surface)
if start < t < stop:
rect = gz.rectangle(lx=r, ly=r, xy=(W*t/duration, H_+r), fill=dot_fill)
rect.draw(surface)
return surface.get_npimage()
clip = mpy.VideoClip(make_frame, duration=duration)
clip.write_videofile(path2(figname), fps=fps)
return clip
figname = '2019-09-30_flash_lag_parallel.mp4'
if True: # not os.path.isfile(path2(figname)):
clip = create_movie(figname)
clip = mpy.VideoFileClip(path2(figname))
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
Out[6]:
mutiple horizontal panels: varrying positional shift¶
In [7]:
__author__ = "Laurent Perrinet INT - CNRS"
__licence__ = 'BSD licence'
print('😎 Welcome to the script generating the movies 😎')
import os
home = os.environ['HOME']
figpath = '../files/'
def path2(fname):
return os.path.join(figpath, fname)
import numpy as np
import gizeh as gz
import moviepy.editor as mpy
W, H = 1000, 600
duration = 2.
fps = 100
def create_movie(figname, r = 16,
duration = duration,
start = duration*.2,
stop = duration*.8, do_stop=False,
shifts_flash=[0.5, -.5, .0],
duration_flash = .05,
flash_fill=(0,1,0),
dot_fill=(1,0,0),
fps = fps,
W=W, H=H):
n_flashes = len(shifts_flash)
color_flashes = [(0, v, 1-v) for v in np.linspace(0, 1, n_flashes, endpoint=True)]
Hs = [v for v in np.linspace(0, H, 2*n_flashes+1, endpoint=True)] # all intermediate positions
Hs = Hs[1::2] # from the first one, take one from two = +|+|+|+
def make_frame(t):
surface = gz.Surface(W, H, bg_color=(0, 0, 0))
for i, (shift_flash, flash_fill, H_) in enumerate(zip(shifts_flash, color_flashes, Hs)):
flash = gz.rectangle(lx=r, ly=r, xy=(W/2.+shift_flash*r, H_-r), fill=flash_fill)
if np.abs(t-1.) < duration_flash: flash.draw(surface)
if start < t < stop:
rect = gz.rectangle(lx=r, ly=r, xy=(W*t/duration, H_+r), fill=dot_fill)
rect.draw(surface)
return surface.get_npimage()
clip = mpy.VideoClip(make_frame, duration=duration)
clip.write_videofile(path2(figname), fps=fps)
return clip
figname = '2019-09-30_flash_lag_parallel_shift.mp4'
if True: # not os.path.isfile(path2(figname)):
clip = create_movie(figname)
clip = mpy.VideoFileClip(path2(figname))
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
Out[7]:
In [8]:
figname = '2019-09-30_flash_lag_parallel_shift_5.mp4'
if True: # not os.path.isfile(path2(figname)):
clip = create_movie(figname, shifts_flash=[0.5, -.25, -.5, .0, .25])
clip = mpy.VideoFileClip(path2(figname))
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
Out[8]:
a more complex approach¶
In [9]:
import gizeh as gz
W, H = 500, 300
r, gray, t = 25., .3, 1.
surface = gz.Surface(W,H, bg_color=(1, 1, 1)) # white background
gradient = gz.ColorGradient(type="radial", stops_colors=[(0,(gray, gray, gray)), (1, (1, 1, 1))],
xy1=[0, 0], xy2=[0, 0], xy3=[0, r])
rf = gz.circle(r=r, xy=(W/2., H/2.), fill=gradient)
#rect = gz.rectangle(lx=.3*H, ly=.02*H, xy=(W*t/duration, H/2.), fill=(0,1,0), angle=np.pi/2)
rf.draw(surface)
surface.ipython_display()
Out[9]:
The flash-lag clock¶
And now the animation for the straight trajectory of a segment with perpendicular orientation:
In [3]:
import numpy as np
import gizeh as gz
import moviepy.editor as mpy
W, H = 1000, 600
duration = 1
figpath = '../files/2019-09-30_'
fps = 60
fix = gz.circle(r=5, xy=(W/2., H/2.), fill=(1, 0, 0))
def make_frame(t):
surface = gz.Surface(W, H, bg_color=(0, 0, 0))
# rect = gz.rectangle(lx=.3*H, ly=.02*H, xy=(W*t/duration, H/2.), fill=(0,1,0), angle=np.pi/2)
# modul = 1 - .2*np.sin(2*np.pi*t/duration)
# ymodul = 1 + .2*(np.cos(2*np.pi*t/duration)+1)
lx = .4*H
for theta in np.linspace(0, 2*np.pi, 50, endpoint=False):
gray = .1
rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(gray, gray, gray), angle=theta)
rect.draw(surface)
pastille = gz.circle(r=25, xy=(W/2., H/2.), fill=(0, 0, 0))
theta = 2*np.pi*t/duration + np.pi
rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(0,1,0), angle=theta)
rect.draw(surface)
if np.abs(np.sin(.5*(theta+np.pi/2))) < np.sin(np.pi/64):
# print (theta, np.abs(np.tan(theta)), np.tan(np.pi/32), np.abs(np.tan(theta)) < np.tan(np.pi/32))
print ('flash for ', theta)
flash = gz.circle(r=5, xy=(W/2., H/2. - .48*H), fill=(1, 0, 0))
flash.draw(surface)
pastille.draw(surface)
fix.draw(surface)
return surface.get_npimage()
clip = mpy.VideoClip(make_frame, duration=duration)
#clip.write_videofile(figpath + 'clock.mp4', fps=fps) # Many options...
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
Out[3]:
avec un flash trait¶
In [4]:
def make_frame(t):
surface = gz.Surface(W, H, bg_color=(0, 0, 0))
lx = .4*H
for theta in np.linspace(0, 2*np.pi, 50, endpoint=False):
gray = .1
rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(gray, gray, gray), angle=theta)
rect.draw(surface)
pastille = gz.circle(r=25, xy=(W/2., H/2.), fill=(0, 0, 0))
theta = 2*np.pi*t/duration + np.pi
rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(0,1,0), angle=theta)
rect.draw(surface)
if np.abs(np.sin(.5*(theta+np.pi/2))) < np.sin(np.pi/64):
print ('flash for theta=', theta, ', t=', t)
flash = gz.rectangle(lx=.06*H, ly=2, xy=(W/2., H/2. - .47*H), fill=(1, 0, 0), angle=np.pi/2)
flash.draw(surface)
pastille.draw(surface)
fix.draw(surface)
return surface.get_npimage()
clip = mpy.VideoClip(make_frame, duration=duration)
#clip.write_videofile(figpath + 'clock.mp4', fps=fps) # Many options...
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
Out[4]:
avec plusieurs flash trait¶
In [5]:
duration = 3
def make_frame(t):
surface = gz.Surface(W, H, bg_color=(0, 0, 0))
lx = .4*H
for theta in np.linspace(0, 2*np.pi, 50, endpoint=False):
gray = .1
rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(gray, gray, gray), angle=theta)
rect.draw(surface)
pastille = gz.circle(r=25, xy=(W/2., H/2.), fill=(0, 0, 0))
N_spikes = 5
for theta_ in np.linspace(0, 2*np.pi, N_spikes, endpoint=False):
theta = 2*np.pi*t/duration + np.pi + theta_
rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(0,1,0), angle=theta)
rect.draw(surface)
#if np.abs(np.cos(np.pi*(t/duration-.5)*N_spikes)) > np.cos(np.pi/32):
if np.abs(np.sin(N_spikes*(theta_-theta)/2)) < np.sin(np.pi/64):
print ('flash for theta=', theta, ', t=', t)
flash = gz.rectangle(lx=.06*H, ly=5, xy=(W/2. + .47*H*np.cos(theta_), H/2. - .47*H*np.sin(theta_)), fill=(1, 0, 0),
angle=-theta_)
flash.draw(surface)
pastille.draw(surface)
fix.draw(surface)
return surface.get_npimage()
clip = mpy.VideoClip(make_frame, duration=duration)
#clip.write_videofile(figpath + 'clock.mp4', fps=fps)
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
Out[5]:
avec plusieurs flash trait + plusieurs alternatives¶
In [6]:
duration = 3
def make_frame(t):
surface = gz.Surface(W, H, bg_color=(0, 0, 0))
lx = .4*H
for theta in np.linspace(0, 2*np.pi, 50, endpoint=False):
gray = .1
rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(gray, gray, gray), angle=theta)
rect.draw(surface)
pastille = gz.circle(r=25, xy=(W/2., H/2.), fill=(0, 0, 0))
N_spikes = 5
theta_effects = [0, -7.5 * np.pi/180, -15 * np.pi/180]
for theta_ in np.linspace(0, 2*np.pi, N_spikes, endpoint=False):
theta = 2*np.pi*t/duration + np.pi + theta_
rect = gz.rectangle(lx=lx, ly=2, xy=(W/2.+lx/2*np.cos(theta), H/2.+lx/2*np.sin(theta)), fill=(1, 1, 1), angle=theta)
rect.draw(surface)
#if np.abs(np.cos(np.pi*(t/duration-.5)*N_spikes)) > np.cos(np.pi/32):
if np.abs(np.sin(N_spikes*(theta_-theta)/2)) < np.sin(np.pi/64):
# print ('flash for theta=', theta, ', t=', t)
for theta_effect, color in zip(theta_effects, [(1, 0.1, 0.1), (.1, 1., .1), (.1, 0.1, 1.)]):
flash = gz.rectangle(lx=.06*H, ly=5, xy=(W/2. + .47*H*np.cos(theta_+theta_effect), H/2. - .47*H*np.sin(theta_+theta_effect)), fill=color,
angle=-theta_-theta_effect)
flash.draw(surface)
pastille.draw(surface)
fix.draw(surface)
return surface.get_npimage()
clip = mpy.VideoClip(make_frame, duration=duration)
#clip.write_videofile(figpath + 'clock.mp4', fps=fps)
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
Out[6]:
mouvement rectiligne avec plusieurs flash trait¶
In [7]:
duration = 1
fix = gz.circle(r=5, xy=(W/2., H/2.), fill=(0, 0, 1))
red_fix = gz.circle(r=5, xy=(W/2., H/2.), fill=(1, 0, 0))
def make_frame(t):
surface = gz.Surface(W, H, bg_color=(0, 0, 0))
lh = .1*H
DX = .6*H
for x in np.linspace(-DX/2, DX/2, 25, endpoint=True):
gray = .1
rect = gz.rectangle(lx=2, ly=lh, xy=(W/2 + x, H/2.), fill=(gray, gray, gray))
rect.draw(surface)
x = -DX/2 + DX*t/duration
rect = gz.rectangle(lx=2, ly=lh, xy=(W/2 + x, H/2. + 0*lh*1.2), fill=(1, 1, 1))
rect.draw(surface)
fix.draw(surface)
if np.abs(x) < 10 :
# print ('flash for theta=', theta, ', t=', t)
shifts = [-25, 0, 25]
for shift, color in zip(shifts, [(1, 0.1, 0.1), (.1, 1., .1), (.1, 0.1, 1.)]):
flash = gz.rectangle(lx=2, ly=lh*.2, xy=(W/2+shift, H/2.-lh/2*1.4), fill=color)
flash.draw(surface)
# red_fix.draw(surface)
return surface.get_npimage()
clip = mpy.VideoClip(make_frame, duration=duration)
clip.write_videofile(figpath + 'clock.mp4', fps=fps)
clip.ipython_display(fps=fps, width=W, autoplay=True, loop=True)
Out[7]:
second principle¶
In [ ]:
#!youtube-dl https://www.youtube.com/watch\?v\=v30b5IAgwQw
fname = "20151115-Breaking Glass in Ultra Slow Motion _ 30000 FPS-v30b5IAgwQw.mp4"
# TODO: import movie, reduce size and then montage it with its reversed-time version
some book keeping for the notebook¶
In [9]:
!rm __temp__.mp4 debug.log
In [9]:
%load_ext watermark
%watermark