PsychoPy Coder:根据帧定义图像持续时间
PsychoPy Coder: define image duration based on frames
我有一些 Matlab 经验,但对 PsychoPy 还是个新手。
现在我想在两个图像之间不断切换,直到有键盘响应。
每张图片都应在屏幕上准确停留 100 毫秒,我希望能够验证情况是否如此(例如在日志文件中)。
我通过在 win.flip() 之后使用 core.wait(.084) 得到了正确的结果 - 在 60Hz 的屏幕上给出了大约 100ms。
我通过使用 win.logOnFlip()
将每个翻转的帧写入日志文件来验证它
但我相信我可以更精确,我只知道如何根据帧来定义图像的持续时间。
函数 core.wait() 只需要以秒为单位的时间,而不是以帧为单位,对吗?
如果你能给我一些关于如何实现(并验证)每张图像 6 帧的呈现的提示,我将不胜感激。
提前致谢
最佳
塞巴斯蒂安
这是我的代码:
import os # for file/folder operations
from psychopy import visual, event, core, gui, data, logging
# Ensure that relative paths start from the same directory as this script
_thisDir = os.path.dirname(os.path.abspath(__file__))
os.chdir(_thisDir)
# screen size in pixels
scrsize = (600,400)
# gather info participant
exp_name = 'MyFirstPsychoPy'
exp_info = {
'participant': '',
}
dlg = gui.DlgFromDict(dictionary=exp_info, title=exp_name)
# if user pressed cancel quit
if dlg.OK == False:
core.quit()
# Get date and time
exp_info['date'] = data.getDateStr()
exp_info['exp_name'] = exp_name
#save a log file for detail verbose info
filename = _thisDir + os.sep + 'data/%s_%s_%s' %(exp_info['participant'], exp_name, exp_info['date'])
# print filename #to see if path correct
logFile = logging.LogFile(filename+'.log', level=logging.DEBUG)
logging.console.setLevel(logging.WARNING) # outputs to the screen, not a file
# Create a window small window
win = visual.Window(size=scrsize, color='white', units='pix', fullscr=False)
# or go full screen
#win = visual.Window([1280,1024], fullscr=True, allowGUI=False, waitBlanking=True)
# this is supposed to record all frames
win.setRecordFrameIntervals(True)
# show instructions until spacebar
start_message = visual.TextStim(win,
text="hello. you will see mondrians. press space to respond.",
color='red', height=20)
event.clearEvents()
keys = event.getKeys(keyList=['space', 'escape']) #allow only space and escape keys
while len(keys) == 0:
start_message.draw()
win.flip()
keys = event.getKeys(keyList=['space', 'escape'])
if len(keys)>0:
break
print keys #show on output screen
keys = event.clearEvents() # empty keys
keys = event.getKeys(keyList=['space', 'escape'])
# define 2 pictures
bitmap1 = visual.ImageStim(win, 'Mondrians/Mask_1.bmp', size=scrsize)
bitmap2 = visual.ImageStim(win, 'Mondrians/Mask_2.bmp', size=scrsize)
bitmap = bitmap1
# Initialize clock to register response time
rt_clock = core.Clock()
rt_clock.reset() # set rt clock to 0
# show alternating pics until response
frameN = 0
while len(keys) == 0:
if bitmap == bitmap1:
bitmap = bitmap2
else:
bitmap = bitmap1
bitmap.draw()
win.logOnFlip(msg='frame=%i' %frameN, level=logging.DEBUG) #record the time of win.flip() in the log file
win.flip() # show image
frameN = frameN + 1
core.wait(.084) # wait 100 ms
keys = event.getKeys(keyList=['space', 'escape']) #record resp
# if response stop
if len(keys)>0:
rt = rt_clock.getTime()
break
print keys, rt #show resp and rt on screen
win.saveFrameIntervals(filename+'.log', clear=True)
win.close()
core.quit()
是的,还有更好的方法!标准解决方案利用了 win.flip()
暂停代码执行直到下一次监视器更新这一事实。所以循环 win.flip()
会给你每个循环正好一帧。所以要在两个 imageStims(bitmap1
和 bitmap2
)之间切换,直到有响应:
clock = core.Clock() # to assess timing
keepLooping = True
while keepLooping: # continue until break
for thisBitmap in [bitmap1, bitmap2]: # alternate between images
if keepLooping: # do not show bitmap2 if a key was pressed on bitmap1
for frameN in range(6): # 100 ms
thisBitmap.draw()
print clock.getTime()
win.callOnFlip(clock.reset) # ... or use win.logOnFlip
win.flip() # inner loop is timed to this, as long as the rest of the code in here doesn't take longer than a frame.
keys = event.getKeys(keyList=['space', 'escape'])
if keys: # notice simplification. [] evaluates to False.
rt = rt_clock.getTime()
keepLooping = False
break
...然后剩下的。我用 core.Clock()
来评估这里的时间,但你的 win.logOnFlip()
也一样好。取决于你想要什么样的输出。
注意event.getKeys()
记录的是执行该行的时间,而不是按键被按下的时间。因此它增加了一个小的延迟。因此,在这个 "frame-locked loop" 中,关键响应被离散化为帧间隔。如果你想获得键盘状态的真正异步轮询(即如果在 RT 记录中有高达 +16ms 的错误),请使用 iohub
模块。无论如何,许多键盘都有 10-30 毫秒的固有延迟,因此您无法消除所有延迟。
我有一些 Matlab 经验,但对 PsychoPy 还是个新手。
现在我想在两个图像之间不断切换,直到有键盘响应。 每张图片都应在屏幕上准确停留 100 毫秒,我希望能够验证情况是否如此(例如在日志文件中)。
我通过在 win.flip() 之后使用 core.wait(.084) 得到了正确的结果 - 在 60Hz 的屏幕上给出了大约 100ms。 我通过使用 win.logOnFlip()
将每个翻转的帧写入日志文件来验证它但我相信我可以更精确,我只知道如何根据帧来定义图像的持续时间。
函数 core.wait() 只需要以秒为单位的时间,而不是以帧为单位,对吗?
如果你能给我一些关于如何实现(并验证)每张图像 6 帧的呈现的提示,我将不胜感激。
提前致谢
最佳
塞巴斯蒂安
这是我的代码:
import os # for file/folder operations
from psychopy import visual, event, core, gui, data, logging
# Ensure that relative paths start from the same directory as this script
_thisDir = os.path.dirname(os.path.abspath(__file__))
os.chdir(_thisDir)
# screen size in pixels
scrsize = (600,400)
# gather info participant
exp_name = 'MyFirstPsychoPy'
exp_info = {
'participant': '',
}
dlg = gui.DlgFromDict(dictionary=exp_info, title=exp_name)
# if user pressed cancel quit
if dlg.OK == False:
core.quit()
# Get date and time
exp_info['date'] = data.getDateStr()
exp_info['exp_name'] = exp_name
#save a log file for detail verbose info
filename = _thisDir + os.sep + 'data/%s_%s_%s' %(exp_info['participant'], exp_name, exp_info['date'])
# print filename #to see if path correct
logFile = logging.LogFile(filename+'.log', level=logging.DEBUG)
logging.console.setLevel(logging.WARNING) # outputs to the screen, not a file
# Create a window small window
win = visual.Window(size=scrsize, color='white', units='pix', fullscr=False)
# or go full screen
#win = visual.Window([1280,1024], fullscr=True, allowGUI=False, waitBlanking=True)
# this is supposed to record all frames
win.setRecordFrameIntervals(True)
# show instructions until spacebar
start_message = visual.TextStim(win,
text="hello. you will see mondrians. press space to respond.",
color='red', height=20)
event.clearEvents()
keys = event.getKeys(keyList=['space', 'escape']) #allow only space and escape keys
while len(keys) == 0:
start_message.draw()
win.flip()
keys = event.getKeys(keyList=['space', 'escape'])
if len(keys)>0:
break
print keys #show on output screen
keys = event.clearEvents() # empty keys
keys = event.getKeys(keyList=['space', 'escape'])
# define 2 pictures
bitmap1 = visual.ImageStim(win, 'Mondrians/Mask_1.bmp', size=scrsize)
bitmap2 = visual.ImageStim(win, 'Mondrians/Mask_2.bmp', size=scrsize)
bitmap = bitmap1
# Initialize clock to register response time
rt_clock = core.Clock()
rt_clock.reset() # set rt clock to 0
# show alternating pics until response
frameN = 0
while len(keys) == 0:
if bitmap == bitmap1:
bitmap = bitmap2
else:
bitmap = bitmap1
bitmap.draw()
win.logOnFlip(msg='frame=%i' %frameN, level=logging.DEBUG) #record the time of win.flip() in the log file
win.flip() # show image
frameN = frameN + 1
core.wait(.084) # wait 100 ms
keys = event.getKeys(keyList=['space', 'escape']) #record resp
# if response stop
if len(keys)>0:
rt = rt_clock.getTime()
break
print keys, rt #show resp and rt on screen
win.saveFrameIntervals(filename+'.log', clear=True)
win.close()
core.quit()
是的,还有更好的方法!标准解决方案利用了 win.flip()
暂停代码执行直到下一次监视器更新这一事实。所以循环 win.flip()
会给你每个循环正好一帧。所以要在两个 imageStims(bitmap1
和 bitmap2
)之间切换,直到有响应:
clock = core.Clock() # to assess timing
keepLooping = True
while keepLooping: # continue until break
for thisBitmap in [bitmap1, bitmap2]: # alternate between images
if keepLooping: # do not show bitmap2 if a key was pressed on bitmap1
for frameN in range(6): # 100 ms
thisBitmap.draw()
print clock.getTime()
win.callOnFlip(clock.reset) # ... or use win.logOnFlip
win.flip() # inner loop is timed to this, as long as the rest of the code in here doesn't take longer than a frame.
keys = event.getKeys(keyList=['space', 'escape'])
if keys: # notice simplification. [] evaluates to False.
rt = rt_clock.getTime()
keepLooping = False
break
...然后剩下的。我用 core.Clock()
来评估这里的时间,但你的 win.logOnFlip()
也一样好。取决于你想要什么样的输出。
注意event.getKeys()
记录的是执行该行的时间,而不是按键被按下的时间。因此它增加了一个小的延迟。因此,在这个 "frame-locked loop" 中,关键响应被离散化为帧间隔。如果你想获得键盘状态的真正异步轮询(即如果在 RT 记录中有高达 +16ms 的错误),请使用 iohub
模块。无论如何,许多键盘都有 10-30 毫秒的固有延迟,因此您无法消除所有延迟。