Forum Archive

scene updating every second

jmv38

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.

jmv38

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())

cvp

@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.

see here

jmv38

@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!

jmv38

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...

jmv38

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.

jmv38

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.

mikael

@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.

JonB

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)

JonB

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.

jmv38

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)

jmv38

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')  

mikael

@jmv38, nice! Have you tried updating every 1/30 or even 1/60 sec and making it completely smooth?

jmv38

@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.

jmv38

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

jmv38

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...

jmv38

here is another video, technically more useful
https://youtu.be/6Qi0UBBXZVw