0

I'm using Shady to display images (PILLOW images) in a loop. For that I'm using the following commands:

Shady.Require( 'numpy', 'Image' )

w = Shady.World(  )

s = w.Stimulus( imList )

s.frame = lambda t: t * 60

Where imList is a list of 60 PIL images. Somehow, Shady doesn't produce anything on my screen. But, if I reduce the size of the list to 17, then it works.

Shady.Require( 'numpy', 'Image' )

w = Shady.World(  )

s = w.Stimulus( imList[0:17] )

s.frame = lambda t: t * 60

I've no idea what is going on. I'm new to Shady and there is not much documentation that I can read to understand what is going on. I just want to display 60 images (at 60 FPS) in a loop. I thought the above code should do it. But it doesn't work. Any help would be highly appreciated. I've been stuck on this for a couple of days now. Also, why does

s.frame = lambda t: t * 60

mean 60 FPS? I'm not sure I completely understand that as well. I tried to look for some explanation of s.frame and the lambda function but couldn't find an answer.

Thanks for your attention!

Best regards.

Shrini
  • 25
  • 7

1 Answers1

0

From Shady's Stimulus constructor documentation (with emphasis added):

multipage (bool) – If you set this to True, multiple image frames will loaded using the LoadPages() method: this transfers each frame to the graphics card as a separate texture, which you switch between using the .page property.

By contrast, if you leave it at the default value False, multiple image frames are handled by concatenating them horizontally into a single texture, and you switch between them using the .frame property, which indirectly manipulates .carrierTranslation.

You may need to use multipage=True for animated images that have a large width and/or high number of frames, because the normal concatenation method may lead to the texture exceeding the maximum allowable width.

So:

w = Shady.World()
s = w.Stimulus( imList, multipage=True )
s.page = lambda t: t * 60  # note the use of .page rather than .frame

This is also explained in the animated-textures demo. That demo also introduces you to the lambda idea, explaining that the property is being set to a function of time in seconds. This concept is explained in detail in the "Key Concepts" chapter "Making Properties Dynamic". (I'm not sure how you have ended up with the impression that there is "not much documentation you can read".)

That specific function, lambda t: t*60 takes in time t in seconds, multiplies it by 60 frames per second, and returns the result. If you multiply seconds by frames-per-second you get a frame number, which is what s.frame (or s.page) are expected to be. When you assign to .frame or .page, the necessary rounding, and the wrapping-around modulo the number of available frames, will be handled automatically.

Your dynamic properties don't have to be lambdas. They can be any callable: a vanilla function, an object method, an instance of some full-blown custom class that defines a __call__ method, ... whatever you like, as long as it takes precisely one argument. A lambda is just a compact and nicely oneliney option—see How are lambdas useful?

jez
  • 14,867
  • 5
  • 37
  • 64
  • Amazing! You must be a genius :-). This works! Thanks so much for taking time to explain and also give the solution. Thanks again! Also, yes I see now that there is enough documentation. I guess I was just impatient having spent a couple of days with this. I'll read the documentation more before I ask the next question :-). – Shrini Jan 12 '22 at 18:55
  • I'm glad it was useful. If it solves your problem, please "accept" the answer using the green check-mark symbol to the left. That's how answers are validated here. – jez Jan 12 '22 at 19:04
  • Got it! Accepted the answer. – Shrini Jan 12 '22 at 19:09