根据视频帧而不是时间控制Shady中的动态属性 [英] Controlling dynamic properties in Shady according to video frames not time

查看:95
本文介绍了根据视频帧而不是时间控制Shady中的动态属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Shady呈现一系列图像帧。我正在控制另一台计算机的流量,因此我首先指示运行Shady的计算机显示第一帧,然后再运行其余帧。
我创建一个World实例,并附加一个动画回调函数。在此回调中,我侦听来自另一台计算机的通信(使用UDP)。
首先,我收到一条命令,以加载给定序列(存储为numpy数组),然后执行

I am trying to use Shady to present a sequence of image frames. I'm controlling the flow from another machine, so that I first instruct the machine running Shady to present the first frame, and later on to run the rest of the frames. I create a World instance, and attach to it an animation callback function. Within this callback I listen for communications from the other machine (using UDP). First I receive a command to load a given sequence (stored as a numpy array), and I do

def loadSequence(self, fname):
    yy = np.load(fname)
    pages = []
    sz = yy.shape[0]
    for j in range(yy.shape[1]/yy.shape[0]):
         pages.append(yy[:, j*sz:(j+1)*sz])
    deltax, deltay = (self.screen_px[0] - sz) / 2, (self.screen_px[1] - sz) / 2
    if (self.sequence is None):
        self.sequence = self.wind.Stimulus(pages, 'sequence', multipage=True, anchor=Shady.LOCATION.UPPER_LEFT, position=[deltax, deltay], visible=False)
    else:
        self.sequence.LoadPages(pages, visible=False)

当我收到显示第一帧的命令时,我会这样做:

When I receive the command to show the first frame, I then do:

def showFirstFrame(self, pars):
    self.sequence.page = 0 if (pars[0] == 0) else (len(self.sequence.pages) - 1)
    self.sequence.visible = True

可是我现在该怎么做才能显示其他帧?在我看到的示例中,s.page被设置为时间的函数,但是我需要显示所有帧,而与时间无关。所以我正在考虑按照以下方式做些事情:

But what do I do now to get the other frames to be be displayed? In the examples I see, s.page is set as a function of time, but I need to show all frames, regardless of time. So I was thinking of doing something along these lines:

def showOtherFrames(self, pars, ackClient):
    direction, ack = pars[0], pars[2]
    self.sequence.page = range(1, len(self.sequence.pages)) if (direction == 0) else range(len(self.sequence.pages)-2, -1, -1)

但这是行不通的。另外,我想定义一个函数,将t作为参数,但忽略它,而使用保存在全局变量中的计数器,但是我想了解执行此操作的正确方法。

But this won't work. Alternatively I thought of defining a function that takes t as argument, but ignores it and uses instead a counter kept in a global variable, but I'd like to understand what is the proper way of doing this.

推荐答案

您的全局变量想法是执行此操作的一种完全有效的方法。或者,由于您似乎将事物定义为自己的自定义类的实例的方法,因此可以将实例方法用作动画回调和/或动态属性值-然后,而不是真正地全局变量,使用 self 的属性很有意义:

Your global-variable idea is one perfectly valid way to do this. Or, since it looks like you're defining things as methods of an instance of your own custom class, you could use instance methods as your animation callbacks and/or dynamic property values—then, instead of truly global variables, it makes sense to use attributes of self:

import Shady

class Foo(object):

    def __init__(self, stimSources):
        self.wind = Shady.World()
        self.stim = self.wind.Stimulus(stimSources, multipage=True)
        self.stim.page = self.determinePage  # dynamic property assignment

    def determinePage(self, t):
        # Your logic here.
        # Ignore `t` if you think that's appropriate.
        # Use `self.wind.framesCompleted` if it's helpful.
        # And/or use custom attributes of `self` if that's
        # helpful (or, similarly, global variables if you must).
        # But since this is called once per frame (whenever the
        # frame happens to be) it could be as simple as:
        return self.stim.page + 1
        # ...which is indefinitely sustainable since page lookup
        # will wrap around to the number of available pages.

# Let's demo this idea:
foo = Foo(Shady.PackagePath('examples/media/alien1/*.png'))
Shady.AutoFinish(foo.wind)

与该简单示例等效,您可以具有声明 <$在更一般的动画回调中使用c $ c> self.stim.page + = 1 (以及其他逻辑)。

Equivalent to that simple example, you could have the statement self.stim.page += 1 (and whatever other logic) inside a more-general animation callback.

另一个有用的功能用于逐帧动画的工具支持python的 generator函数,即包含 yield 语句的函数。有用的示例包含在 python -m Shady演示精度 python -m Shady demo dithering

Another useful tool for frame-by-frame animation is support for python's generator functions, i.e. functions that include a yield statement. Worked examples are included in python -m Shady demo precision and python -m Shady demo dithering.

这也可以在 StateMachine 始终是我对此类事情的首选答案:

It can also be done in a StateMachine which is always my preferred answer to such things:

import Shady

class Foo(object):
    def __init__(self, stimSources):
        self.wind = Shady.World()
        self.stim = self.wind.Stimulus(stimSources, multipage=True)


foo = Foo(Shady.PackagePath('examples/media/alien1/*.png'))         

sm = Shady.StateMachine()
@sm.AddState
class PresentTenFrames(sm.State):
    def ongoing(self): # called on every frame while the state is active
        foo.stim.page += 1
        if foo.stim.page > 9:
            self.ChangeState()

@sm.AddState
class SelfDestruct(sm.State):
    onset = foo.wind.Close

foo.wind.SetAnimationCallback(sm)

Shady.AutoFinish(foo.wind)

这篇关于根据视频帧而不是时间控制Shady中的动态属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆