psychopy.org | Reference | Downloads | Github

Misaligned lines to produce illusory lines

Hello,

I wanted to construct a stimulus with misaligned lines that contains illusory lines (orthogonal to inducing lines, see below the code). I want to be able to control the orientation and drifting speed of the stimulus (like with regular gratings). I tried to use ElementArrayStim and Lines. However, I am not sure what would be the best way to achieve this. I am posting my current progress.

One way to do this would be to save stimuli and then use them as static images. Yet, if I want to change any parameter (eg line length), I would need to regenerate all stimuli of different orientations again. I am looking for a way to dynamically generate this stimulus.

I would appreciate any help on this.

import numpy as np
import psychopy.visual
import psychopy.event

mon_x, mon_y = 910, 540
win = psychopy.visual.Window(
    size=(mon_x, mon_y),
    fullscr=False,
    units="pix",
    color = 1
)
# gap between x lines
sf_ils_line = 300
# gap between y lines
sf_inducer = 100

# fill the screen with lines
x = np.arange(-1*(mon_x/2), (mon_x/2)+1, sf_ils_line)
y = np.arange(-1*(mon_y/2), (mon_y/2)+1, sf_inducer)
xx, yy = np.meshgrid(x, y)
# add misalignment
yy[:,::2] = yy[:,::2] + sf_inducer/2
n_lines = xx.shape[0]*xx.shape[1]

xys = np.zeros((n_lines, 2))
xys[:, 0] = xx[:,:].flatten()
xys[:, 1] = yy[:,:].flatten()



lines = psychopy.visual.ElementArrayStim(
    win=win,
    nElements= n_lines,
    xys = xys,
    elementTex=np.ones((1, 4))*(-1),
    elementMask=None,
    sizes=(sf_ils_line, 10)
)
lines.draw()

win.flip()
psychopy.event.waitKeys()

win.close()

image

Your ElementArrayStim way looks like a good approach.

Another option to consider is to make an image of a single ‘cell’, containing a single pair of lines. Then you can use that to create a GratingStim, and then use its sf, size, ori, and phase parameters to dynamically manipulate the stimulus into how you want it to look.

See the below for an example. The keys left and right changes the orientation, o and l increase and decrease the number of horizontal repeats, i and k increase and decrease the number of vertical repeats. And q quits.

import numpy as np

import psychopy.visual
import psychopy.event

cell_size = 512
line_width = 24

cell = np.ones((cell_size, cell_size))

cell[
    (cell_size // 4) - (line_width // 2):(cell_size // 4) + (line_width // 2),
    :(cell_size // 2)
] = -1

cell[
    (cell_size // 4 * 3) - (line_width // 2):(cell_size // 4 * 3) + (line_width // 2),
    (cell_size // 2):
] = -1

n_vert = 6
n_horiz = 1.5

phase = 0.0
ori = 0.0

with psychopy.visual.Window((600, 600), fullscr=False, units="pix") as win:

    stim = psychopy.visual.GratingStim(
        win=win, tex=cell, mask=None, size=(cell_size, cell_size)
    )

    stim.sf = (n_horiz / cell_size, n_vert / cell_size)

    stim.size = (cell_size, cell_size / 2)

    keep_going = True

    while keep_going:

        stim.phase = [0, stim.phase[1] + 0.01]

        stim.draw()

        win.flip()

        keys = psychopy.event.getKeys()

        for key in keys:
            if key == "left":
                stim.ori -= 15.0
            elif key == "right":
                stim.ori += 15.0
            elif key == "o":
                stim.sf = [stim.sf[0] + (0.5 / cell_size), stim.sf[1]]
            elif key == "l":
                stim.sf = [stim.sf[0] - (0.5 / cell_size), stim.sf[1]]
            elif key == "i":
                stim.sf = [stim.sf[0], stim.sf[1] + (0.5 / cell_size)]
            elif key == "k":
                stim.sf = [stim.sf[0], stim.sf[1] - (0.5 / cell_size)]
            elif key == "q":
                keep_going = False

Thanks for a quick reply. I tested the code and it seems to do what I want. Your apporach is definitely much better. I still need to figure out how it works.

Appreciate your help,