在心理学中绘制连续线的有效方法

efficient way to draw continuous line in psychopy

我正在寻找一种更有效的方法来在 PsychoPy 中绘制连续线条。这就是我想出的,现在...

编辑:我能想到的唯一改进是仅在鼠标真正移动时通过添加 if (mspos1-mspos2).any():

添加新行
ms = event.Mouse(myWin)

lines = []

mspos1 = ms.getPos()
while True:
    mspos2 = ms.getPos()
    if (mspos1-mspos2).any():
        lines.append(visual.Line(myWin, start=mspos1, end=mspos2))
    for j in lines:
        j.draw()
    myWin.flip()
    mspos1 = mspos2

编辑:我尝试使用 Shape.Stim(下面的代码),希望它能更好地工作,但它变得更加急躁..

vertices = [ms.getPos()]
con_line = visual.ShapeStim(myWin,
        lineColor='red',
        closeShape=False)
myclock.reset()
i = 0
while myclock.getTime() < 15:
    new_pos = ms.getPos()
    if (vertices[i]-new_pos).any():
        vertices.append(new_pos)
        i += 1
    con_line.vertices=vertices
    con_line.draw()
    myWin.flip()

问题是在循环的每次迭代中绘制那么多 visual.Line 或在 visual.ShapeStim 中操作那么多顶点变得过于耗费资源。因此它将挂在绘图(对于线)或顶点分配(对于 ShapeStim)上,只要鼠标移动到足以使线显示不连续性("edgy")。

所以这是一个性能问题。这里有两个想法:

  1. 在要向直线添加新坐标之前,鼠标移动的最小距离的阈值较低。在下面的示例中,我施加了一个标准,即鼠标位置应与要记录的前一个顶点至少相距 10 个像素。在我的测试中,这将每秒记录的顶点数量压缩到大约三分之一。仅此策略将推迟性能问题,但不能阻止它,依此类推...
  2. 使用 ShapeStim 解决方案,但定期使用新的 ShapeStims,每个顶点都较少,因此要更新的刺激不会太复杂。在下面的示例中,我在转向新刺激之前将复杂度设置为 500 像素。生成新刺激时可能会出现小故障,但我没有注意到。

所以结合这两种策略,通过按下键盘开始和结束鼠标绘图:

# Setting things up
from psychopy import visual, event, core
import numpy as np

# The crucial controls for performance. Adjust to your system/liking.
distance_to_record = 10  # number of pixels between coordinate recordings
screenshot_interval = 500  # number of coordinate recordings before shifting to a new ShapeStim

# Stimuli
myWin = visual.Window(units='pix')
ms = event.Mouse()
myclock = core.Clock()

# The initial ShapeStim in the "stimuli" list. We can refer to the latest
# as stimuli[-1] and will do that throughout the script. The others are 
# "finished" and will only be used for draw.
stimuli = [visual.ShapeStim(myWin,
        lineColor='white',
        closeShape=False,
        vertices=np.empty((0, 2)))]

# Wait for a key, then start with this mouse position
event.waitKeys()
stimuli[-1].vertices = np.array([ms.getPos()])
myclock.reset()
while not event.getKeys():
    # Get mouse position
    new_pos = ms.getPos()

    # Calculating distance moved since last. Pure pythagoras.
    # Index -1 is the last row.index
    distance_moved = np.sqrt((stimuli[-1].vertices[-1][0]-new_pos[0])**2+(stimuli[-1].vertices[-1][1]-new_pos[1])**2)

    # If mouse has moved the minimum required distance, add the new vertex to the ShapeStim.
    if distance_moved > distance_to_record:
        stimuli[-1].vertices = np.append(stimuli[-1].vertices, np.array([new_pos]), axis=0)

    # ... and show it (along with any "full" ShapeStims
    for stim in stimuli:
        stim.draw()
    myWin.flip()

    # Add a new ShapeStim once the old one is too full
    if len(stimuli[-1].vertices) > screenshot_interval:
        print "new shapestim now!"
        stimuli.append(visual.ShapeStim(myWin, 
                                        lineColor='white', 
                                        closeShape=False, 
                                        vertices=[stimuli[-1].vertices[-1]]))  # start from the last vertex