hello
i am trying to animate a series of png images computed with pythonista. I would like to display 1 image every second, and record the film with the ipad record, so i try to customize the scene example of the doc. But nothing works, i keep getting stupid errors, probably my bad.
Can anyone help? Thanks.
Forum Archive
scene updating every second
here is a code with no error, but the view_update is never called
# coding: utf-8
from scene import *
import ui
import photos
from PIL import Image
import io as io
def pil2ui(pil_img):
with io.BytesIO() as buffer:
pil_img.save(buffer, format='PNG')
return ui.Image.from_data(buffer.getvalue())
def view_update():
azim -= 10
file = 'CieLuv_'+str(azim)+'.png'
print(file)
im = Image.open(file)
ui_image = pil2ui(im)
class MyScene (Scene):
global ui_image,t0,azim
def setup(self):
self.background_color = 'ligtgray'
img = ui.Button(name='image')
img.frame = (25, 50, 1476/1.5, 1024/1.5) #1476 1024
img.background_image = ui_image
img.enable = False
img.hidden = False
self.view.add_subview(img)
# trying to update 1 per second
self.view.update_interval = 1
self.view.update = view_update
def disp_photo(self,sender):
img = sender.superview['image']
img.hidden = not img.hidden
if __name__ == '__main__':
global ui_image, azim
im = Image.open("CieLuv_-10.png")
ui_image = pil2ui(im)
azim = 190
run(MyScene())
@jmv38 the refresh method of a scene is update. You have mixed with view.update of an ui.View.
See animation sub-folder of examples
Perhaps it could be better that instead of a Scene, you use a ui.View.
In this cases, setup becomes the init, and the code of your view_update can be put in def update of the custom view class.
@cvp thanks, i’ll have a look.
The problem is that with Scene or ui.View some fair amount a background is needed to get it work smoothly. I wish i could just tweek a couple lines in an example and get what i need. The built in example are a bit too complex for that.
Thanks anyway. And happy new year!
also searching in the forum with keywords really leads me nowhere. The search engine does not seem very smart, cause i am fairly sure i saw that kind of problems disucussed in the past, but i dont get any usefull link...
with scene + update, how can i trigger something once per second? When i try to use globals to keep track of a global state t, i keep getting some ‘local variable t used before being assigned’ , although it is global and assigned in the main... I pbly dont get fully how python namespaces work or in which order things are called, so i am stuck.
btw, for anyone interested, here is the kind of video i want to make
https://youtu.be/eXBGYHKKytI
this one i made by assembling the images manually with Splice, i am trying to make it more automatic.
@jmv38, if you use a View, you can set its update_interval to 1 (second), and its update method gets automatically called once per second.
Also, for better results, use Google to search instead of the forum search.
you want to avoid globals in Scenes -- make those variables methods of your scene. The way threads work in scene, I think as written you could have issues.
by the way, most scene examples use run(amyScene()), but you are allowed to do:
```
s=MyScene(someparams,that,your,init,accepts)
s.someattrib=value
run(s)
Also, take a look at the scene docs.
You need to implement either a draw method, which is called once per frame (and you would use scene_drawing.image method, using a set of images where you prefiously called load_pil_image to precache inages), or else you would use update to set spritenode texture. the scene.run method takes a frame_interval parameter to set fps.
you may define a custom init that sets scene attributes etc based on globals -- but setup might not have access to globals (not sure if this is still true -- but it does run in a separate thread). Use setup just to handle actual display stuff,
Depending in how many images you have, it might be worth creating all your SpriteNodes up front.
thanks for your advices. I chose to go for the ui.view. It worked nicely https://youtu.be/Li5gV2tUj5M
(make sure to set 1080p when you watch the video, otherwise the quality is bad)
here is the code
import ui
from console import clear
from PIL import Image
import io as io
def pil2ui(pil_img):
with io.BytesIO() as buffer:
pil_img.save(buffer, format='PNG')
return ui.Image.from_data(buffer.getvalue())
class MyView (ui.View):
def __init__(self):
# global view settings
self.name = 'Viewing where colors lie in the CIE L*u*v* color space'
self.background_color = 'gray'
# trying to update 1 per second
self.update_interval = 1
# image settings
img = ui.Button(name='image')
img.width = 1476/1.5
img.height = 1024/1.5
img.enable = False
img.hidden = False
self.add_subview(img)
self.img = img
# add a copyright
txt = ui.Label()
txt.text = 'copyright JMV38 2019'
txt.text_color = (0.5, 0.5, 0.5, 0.2)
txt.width = 600
txt.height = 100
txt.alignment = ui.ALIGN_CENTER
fontName, fontSize = txt.font
txt.font = (fontName,30)
self.add_subview(txt)
self.txt = txt
def update(self):
self.img.center = (self.width * 0.5, self.height * 0.5)
self.txt.center = (self.width * 0.5, self.height * 0.5)
try:
self.azim -= 10
except:
self.azim = 180
file = 'CieLuv_'+str(self.azim)+'.png'
try:
print(file)
im = Image.open(file)
ui_image = pil2ui(im)
self.img.background_image = ui_image
except:
exit()
if __name__ == '__main__':
clear()
view = MyView()
view.present('full_screen')
@jmv38, nice! Have you tried updating every 1/30 or even 1/60 sec and making it completely smooth?
@mikael actually
1/ i have not computed enough intermediate frames (each take 30s on my ipad air)
2/ i use the video to view it frame by frame from the ipad photo roll, to turn around as i wish, so it is enough for my usage
3/ i have tried 0.5s once but it skipped 1 frame in the middle, so i thought i would remain at 1 Hz.
thanks.
still in trouble.
I am trying to save my numpy structured array with np.save, here is the code for details
# differents tests avec Luv
from labColor import *
import numpy as np
from console import clear
# compute all colors
def getAllColors(step):
dtype = [('L', float), ('u', float), ('v', float), ('c', tuple), ('d', float)]
data = []
for r in np.arange(0, 256, step):
print(r)
for g in np.arange(0, 256, step):
for b in np.arange(0, 256, step):
L, u, v = rgb_to_sLuv(r, g, b)
data.append((L, u, v, (r/255,g/255,b/255), 0.0))
ar = np.array(data,dtype=dtype)
return ar
clear()
ar = getAllColors(50)
print(len(ar))
print(ar.dtype)
np.save('rgb.npy',ar)
a = np.load('rgb.npy')
print(len(a))
print(a.dtype)
but i get this error
Traceback (most recent call last):
File "/private/var/mobile/Containers/Shared/AppGroup/..../Pythonista3/Documents/couleurs/labColor6.py", line 24, in <module>
np.save('rgb.npy',ar)
File "/var/containers/Bundle/Application/..../Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/numpy/lib/npyio.py", line 451, in save
format.write_array(fid, arr)
File "/var/containers/Bundle/Application/.../Pythonista3.app/Frameworks/Py3Kit.framework/pylib/site-packages/numpy/lib/format.py", line 407, in write_array
pickle.dump(array, fp, protocol=2)
_pickle.PicklingError: Can't pickle <built-in function _reconstruct>: import of module 'multiarray' failed
what am i doing wrong?
thanks
ok i got it. numpy.save cannot decode tuples by itself...
surprising that there is no simple way to save a structured array, and that i must flatten the structure to save it. Extra work and risk of errors... Anyway...
here is another video, technically more useful
https://youtu.be/6Qi0UBBXZVw