【问题标题】:PsychoPy Coder: define image duration based on framesPsychoPy Coder:根据帧定义图像持续时间
【发布时间】:2015-01-09 17:58:08
【问题描述】:

我有一些 Matlab 经验,但对 PsychoPy 很陌生。

现在我想在两个图像之间不断切换,直到有键盘响应。 每个图像都应该在屏幕上准确停留 100 毫秒,我希望能够验证是否是这种情况(例如在日志文件中)。

我通过在 win.flip() 之后使用 core.wait(.084) 来做对了 - 在一个 60Hz 的屏幕上,大约需要 100 毫秒。 我通过使用 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()

【问题讨论】:

    标签: ios time frames psychopy


    【解决方案1】:

    是的,还有更好的方法!标准解决方案利用win.flip() 暂停代码执行直到下一次监视器更新这一事实。所以循环win.flip() 会给你每个循环一帧。所以要在两个imageStims(bitmap1bitmap2)之间切换,直到有响应:

    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() 记录的是执行此行的时间,而不是按键被按下的时间。因此它增加了一个小的延迟。在这个“帧锁定循环”中,关键响应因此被离散到帧间隔。如果您想获得真正的键盘状态异步轮询(即,如果 RT 记录中出现高达 +16ms 的错误),请使用iohub 模块。无论如何,许多键盘都有 10-30 毫秒的固有延迟,因此您无法消除所有延迟。

    【讨论】:

    • 您好乔纳斯,非常感谢您的回复。根据您的建议,现在以 100 毫秒/6 帧的速度显示图像。不幸的是,我不确定精确的时间,因为实验现在永远不会停止(一旦图像来回切换,它就不会占用空格键),并且没有写入日志文件(创建了一个空白日志文件) .使用 print clock.getTime() 打印到输出窗口的时间在 0.0002 范围内,我不明白。时钟不应该以秒为单位吗?所以。现在怎么办?再次感谢。
    • 缺少日志文件:只是因为我选择将翻转持续时间输出到控制台而不是日志文件。如果您想要文件(使用win.logOnFlip),您可以插入您的方法。翻转时间:是的,应该是 ~0.0167。也许您的计算机与显示器不同步。尝试运行 Coder --> Demos --> Timing --> timesByFrames.py,它会为您提供从计算机上看到的帧持续时间的直方图。它应该在 0.01667 附近收窄。如果不是,请升级显卡驱动程序或使用其他计算机。
    • 注册密钥:抱歉,三个循环中只有一个中断。我已经更新了答案并创建了一个 keepLooping 变量来控制它是否应该继续循环。不是很优雅,但它有效:-)
    • 嗨乔纳斯,现在一切正常。我的计算机与显示器同步良好,正如 timesByFrames 演示所测试的那样,我认为应该创建一个日志文件的开头,即使我没有在每个 win.flip() 中写入它。但没关系,我已经回到使用 lonOnFlip 并且它有效。再次感谢。
    • 不客气。如果它解决了您的问题,请记住接受此答案(左侧的勾号)。这样其他用户就可以看到有解决方案。
    猜你喜欢
    • 1970-01-01
    • 2021-04-17
    • 1970-01-01
    • 2020-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多