Управление динамическими свойствами в Shady по кадрам видео не время - PullRequest
2 голосов
/ 30 мая 2019

Я пытаюсь использовать Shady для представления последовательности кадров изображения.Я управляю потоком с другой машины, поэтому сначала я проинструктирую машину, на которой запущен Shady, представить первый кадр, а затем - запустить остальные кадры.Я создаю экземпляр World и прикрепляю к нему функцию обратного вызова анимации.В рамках этого обратного вызова я слушаю сообщения от другого компьютера (используя UDP).Сначала я получаю команду для загрузки заданной последовательности (сохраняемой в виде массива), и я делаю

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 в качестве аргумента, но игнорирует его и использует вместо этого счетчик, хранящийся в глобальной переменной, но я хотел бы понять, как правильно сделать это.

Ответы [ 2 ]

2 голосов
/ 30 мая 2019

Когда вы делаете s.page динамическим свойством, назначенная ему функция должна принимать один аргумент (t), но вы все равно можете просто использовать любые переменные в пространстве при определении этой функции и даже не использовать аргумент time вall.

Так, например, вы можете сделать что-то простое:

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

, которое установит свойство page в текущее число кадров.Похоже, это может быть полезно для вашей проблемы.

1 голос
/ 30 мая 2019

Ваша идея с глобальными переменными - один из вполне допустимых способов сделать это. Или, поскольку похоже, что вы определяете вещи как методы экземпляра вашего собственного пользовательского класса, вы можете использовать экземпляры методы в качестве обратных вызовов анимации и / или значения динамических свойств - тогда вместо действительно глобальных переменные, имеет смысл использовать атрибуты 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 *1013*, то есть функций, которые включают оператор 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...