我有兴趣从psychtoolbox迁移到shady进行我的刺激演示。我浏览了在线文档,但对我来说不清楚如何在Shady中复制我目前在matlab中所做的工作。
我所做的实际上很简单。对于每次审判,
我从磁盘加载单个图像(离线进行亮度线性化),其中包含我计划在该试验中显示的所有帧(刺激为1000x1000 px,我显示了25帧,因此图像为5000x5000px。使用BW图像,因此每个像素有一个int8值)。
我将整个图像从CPU传输到GPU
在某个时候(外部控制),我将第一帧复制到视频缓冲区并呈现
在其他地方(外部控制),我触发了
剩下的24帧(将每个视频帧的图像的相关部分复制到视频缓冲区,然后调用flip())。
外部控制是通过让另一台机器通过TCP / IP与刺激表示代码进行通信来实现的。在控制PC向演示PC发送命令并执行该命令之后,演示PC需要将确认消息发送回控制PC。我需要发送三条ACK消息,一条在屏幕上出现第一帧时,一条在屏幕上出现第二帧时,一条在屏幕上出现第25帧时发送(这样,控制PC可以轻松地验证是否丢失了帧) )。
在matlab中,我通过调用阻塞方法flip()来呈现帧来完成此操作,然后在返回时将ACK发送到控制PC。
而已。我该如何在阴暗的环境中做到这一点?有没有我应该看的例子?
最佳答案
查找此信息的位置是Shady.Stimulus
和Shady.Stimulus.LoadTexture
的文档字符串以及随附的示例脚本animated-textures.py
。
像大多数Python一样,有多种方法可以执行所需的操作。这是我的处理方式:
w = Shady.World()
s = w.Stimulus( [frame00, frame01, frame02, ...], multipage=True )
其中每个
frameNN
是1000x1000像素的numpy
数组(浮点或uint8
)。或者,您可以要求Shady直接从磁盘加载:
s = w.Stimulus('trial01/*.png', multipage=True)
其中目录
trial01
包含25个1000x1000像素的图像文件,它们分别通过(00.png
)命名为(例如)24.png
,以便正确排序。或者,您可以提供文件名的明确列表。无论哪种方式,无论您是从内存加载还是从磁盘加载,帧都将在该调用中传输到图形卡。然后,您可以(时间紧迫)在它们之间切换:
s.page = 0 # or any number up to 24 in your case
请注意,由于使用了
multipage
选项,我们使用的是“页面”动画机制(每帧创建一个OpenGL纹理),而不是默认的“帧”机制(创建一个1000x25000 OpenGL纹理),因为后者将超过许多图形卡上单个纹理的最大允许尺寸。这些机制之间的区别已在Shady.Stimulus
类的文档字符串以及上述交互式演示中讨论:python -m Shady demo animated-textures
要准备下一次试用,您可以使用
.LoadPages()
(Shady 1.8.7版中的新增功能)。这循环遍历现有的“页面”,将新纹理加载到以前使用的图形卡纹理缓冲区中,并根据需要添加其他页面:s.LoadPages('trial02/*.png')
现在,您提到您已建立的工作流程是将帧串联为单个5000x5000像素的图像。我上面的解决方案假定您已经完成了将其再次切成1000x1000像素帧的工作,大概是使用了numpy调用(听起来像您现在在Matlab中所做的一样)。如果您要保存为5000x5000,那么最好的控制方法可能就是维护自己的代码以进行裁剪。但是值得一提的是,您可以采取完全不同的策略来一次性转移所有内容:
s = w.Stimulus('trial01_5000x5000.png', size=1000)
这会将整个预先准备的5000x5000图像从磁盘(如果要传递5000x5000 numpy数组而不是文件名,则从内存中重新加载)到图形卡内存中的单个纹理中。但是,由于
size
规范,Stimulus
将仅显示阵列的左下1000x1000像素部分。然后,您可以通过相对于信封移动托架来切换“帧”。例如,如果您要说:s.carrierTranslation = [-1000, -2000]
那么您将看一下位于5x5阵列中的一个“列”和两个“行”的框架。
最后,请记住,您可以利用Shady的动态伽马校正和抖动功能-无论如何,除非您明确禁用它们,否则它们都会发生,尽管如果您将刺激为1.0,并使用整数像素值。因此,您可以将刺激生成为单独的1000x1000数组,每个数组包含在
.gamma
范围内的非线性浮点值,并让Shady担心除此以外的所有问题。