Представление частей предварительно подготовленного массива изображений в Shady - PullRequest
2 голосов
/ 16 мая 2019

Я заинтересован в переходе с psychtoolbox на shady для моей презентации стимула. Я просмотрел онлайн-документы, но мне не очень понятно, как воспроизвести то, что я сейчас делаю в matlab, в shady.

То, что я делаю, на самом деле очень просто. За каждое испытание

  1. Я загружаю с диска одно изображение (я делаю линеаризацию яркости в автономном режиме), которое содержит все кадры, которые я планирую отобразить в этом испытании (стимул 1000x1000 пикселей, и я представляю 25 кадров, следовательно, Размер изображения 5000x5000 пикселей. Я использую только черно-белые изображения, поэтому у меня одно значение int8 на пиксель).

  2. Я передаю все изображение из процессора в графический процессор

  3. В какой-то момент (с внешним управлением) я копирую первый кадр в видеобуфер и представляю его

  4. В какой-то другой точке (с внешним управлением) я запускаю презентацию оставшиеся 24 кадра (копирование соответствующей части изображения в видеобуфер для каждого видеокадра, а затем вызов flip ()).

  5. Внешнее управление происходит, когда другая машина связывается с кодом представления стимула по TCP / IP. После того, как управляющий ПК отправляет команду на презентационный ПК, и это выполняется, презентационный ПК должен отправить обратно сообщение подтверждения на управляющий ПК. Мне нужно отправить три сообщения ACK, одно, когда на экране появляется первый кадр, одно, когда на экране появляется 2-й кадр, и одно, когда на экране появляется 25-й кадр (таким образом управляющий ПК может легко проверить, пропущен ли кадр ). В Matlab я делаю это, вызывая метод блокировки flip () для представления кадра, а когда он возвращается, я отправляю ACK на управляющий ПК.

Вот и все. Как бы я сделал это в тенистой? Есть ли пример, на который я должен взглянуть?

1 Ответ

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

Местами для поиска этой информации являются строки документов Shady.Stimulus и Shady.Stimulus.LoadTexture, а также прилагаемый пример сценария animated-textures.py.

Как и большинство вещей Python, есть несколько способов сделать то, что вы хотите.Вот как я бы это сделал:

w = Shady.World()
s = w.Stimulus( [frame00, frame01, frame02, ...], multipage=True )

, где каждый frameNN представляет собой массив numpy размером 1000x1000 пикселей (либо с плавающей запятой, либо uint8).

В качестве альтернативы вы можетепопросите Shady загрузить непосредственно с диска:

s = w.Stimulus('trial01/*.png', multipage=True)

, где каталог trial01 содержит двадцать пять файлов изображений размером 1000x1000 пикселей, названных (скажем) 00.png - 24.png, чтобы они были правильно отсортированы.Или вы можете предоставить явный список имен файлов.

В любом случае, независимо от того, загружены вы из памяти или с диска, все кадры передаются в графическую карту в этом вызове.Затем вы можете (критично ко времени) переключаться между ними с помощью:

s.page = 0  # or any number up to 24 in your case

Обратите внимание, что из-за использования опции multipage мы используем механизм анимации «страницы» (создайте один OpenGLтекстура на кадр) вместо стандартного механизма «рамка» (создайте одну текстуру OpenGL 1000x25000), поскольку последняя будет превышать максимально допустимые размеры для одной текстуры на многих видеокартах.Различие между этими механизмами обсуждается в строке документации для класса Shady.Stimulus, а также в вышеупомянутой интерактивной демонстрации:

python -m Shady demo animated-textures

Чтобы подготовить следующее испытание, вы можете использовать .LoadPages() (новое в Shadyверсия 1.8.7).Это перебирает существующие «страницы», загружая новые текстуры в ранее использованные буферы текстур графической карты, и добавляет дополнительные страницы по мере необходимости:

s.LoadPages('trial02/*.png')

Теперь вы упоминаете, что ваш установленный рабочий процесс состоит в объединениикадры как одно изображение размером 5000x5000 пикселей.Мои решения, приведенные выше, предполагают, что вы проделали работу, снова разрезая его на кадры 1000x1000 пикселей, предположительно используя пустые вызовы (кажется, что вы могли бы сделать аналог в Matlab в данный момент).Если вы собираетесь сохранять сохранение в формате 5000x5000, лучшим способом сохранить контроль над ситуацией может быть поддержание собственного кода для его сокращения.Но стоит упомянуть, что вы могли бы использовать совершенно другую стратегию передачи всего этого за один раз:

s = w.Stimulus('trial01_5000x5000.png', size=1000)

Это загружает весь заранее подготовленный образ 5000x5000 с диска (или снова изпамяти, если вы хотите передать массив имен размером 5000x5000 вместо имени файла) в одну текстуру в памяти видеокарты.Однако, из-за спецификации size, Stimulus будет отображать только нижнюю левую часть массива 1000x1000 пикселей.Затем вы можете переключать «кадры», смещая носитель относительно конверта.Например, если бы вы сказали:

s.carrierTranslation = [-1000, -2000]

, вы бы посмотрели на фрейм, расположенный на расстоянии одного «столбца» и двух «строк» ​​в массиве 5x5.

Какпоследнее замечание, помните, что вы могли бы воспользоваться гамма-коррекцией и сглаживанием Шейди на лету - они происходят в любом случае, если вы явно не отключите их, хотя, конечно, они не оказывают никакого физического воздействия, если выоставьте стимул .gamma на уровне 1,0 и используйте целочисленные значения пикселей.Таким образом, вы можете генерировать свои стимулы в виде отдельных массивов 1000x1000, каждый из которых содержит нелинейные значения с плавающей запятой в диапазоне [0.0,1.0], и позволить Шейди беспокоиться обо всем, что за этим стоит.

...