0

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

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)

当我收到显示第一帧的命令时,我会执行以下操作:

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

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

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 作为参数的函数,但忽略它并使用保存在全局变量中的计数器,但我想了解这样做的正确方法是什么。

4

2 回答 2

0

当您使 s.page 成为动态属性时,分配给它的函数必须带有一个参数 (t),但您仍然可以在定义该函数时只使用空间中的任何变量,甚至根本不使用 time 参数。

因此,例如,您可以执行以下简单的操作:

w = Shady.World(...)
s = w.Stimulus(...)
s.page = lambda t: w.framesCompleted

这会将page属性设置为当前帧数。听起来它可能对您的问题有用。

于 2019-05-30T17:37:14.117 回答
0

您的全局变量想法是一种完全有效的方法。或者,因为看起来您将事物定义为您自己的自定义类的实例的方法,您可以使用实例方法作为动画回调和/或动态属性值——然后,而不是真正的全局变量,它是有意义的使用以下属性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)

等效于那个简单的示例,您可以在更通用的动画回调中包含语句(以及任何其他逻辑)。 self.stim.page += 1

用于逐帧动画的另一个有用工具是支持 python 的生成器函数,即包含yield语句的函数。工作示例包含在python -m Shady demo precision和中python -m Shady demo dithering

它也可以在StateMachine我对这些事情的首选答案中完成:

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)
于 2019-05-30T17:55:03.327 回答