psychopy.org | Reference | Downloads | Github

Square gratings at different orientations

Hi all,

I’m trying to design a stimulus that consists of multiple overlaid (somewhat transparent) square gratings of different sizes. They will look like visual noise. The overall shape of the stimulus will be a square (128 x 128 pixels).

The overlaid gratings differ in orientation, there are 6 overlaid gratings ranging in steps of 30°, i.e.,
orientations = range(0,180,30).

There are also different sized gratings (128x128; 64x64; 32x32x; 16x16 pixels), which are ‘tiled up’ side by side to form the final visual noise (128x128 pixels, as above). These are a 1x1, 2x2, 4x4, and 8x8 2D matrix respectively.

Here is the challenge I have found: changing the orientation of the default square grating orients the entire shape, but what I need to be able to do is to maintain the default orientation of the square shape (i.e., horizontal and vertical edges at 0° and 90°) and instead only change the orientation of the grating:

Any help here would be appreciated. Here is the code I’ve been using:

from psychopy import visual,event
from psychopy.tools import imagetools
import numpy as np
import math
import random

imageSize = 128
winHeight = 256
winLength = 256

win = visual.Window(
    size=[winLength, winHeight],
    units="pix",
    fullscr=False,
    allowGUI=False,
    blendMode='add',
    useFBO=True,
    color=[0, 0, 0]
)

grating = visual.GratingStim(
    win=win,
    units='pix',
    tex='sin',    
    interpolate=True,
    size=[imageSize, imageSize]
)

grating_hpos = 0

grating_vpos = 0

orientations = range(0,180,30)*2 

for i in range(6):
	grating.sf 		 = 2.0 / imageSize
	grating.contrast = np.random.uniform(-1,1)
	grating.ori 	 = orientations[i]
	grating.opacity  = 1/6.0	
	grating.pos 	 = [grating_hpos,grating_vpos]	
	grating.draw()

win.flip()
event.waitKeys()`
win.close()

You need to use visual.filters.makeGrating() so that the texture itself is changed rather than the way it gets applied to the stimulus:


from psychopy import visual, event, core
from psychopy.visual import filters
import numpy as np

win = visual.Window([800, 600], units='pix')

oriGrat = filters.makeGrating(res=128,
                ori=30.0,  # in degrees
                cycles=3.0,
                phase=0.0,  # degrees 0-360
                gratType="sin",
                contr=1.0)

stim = visual.ImageStim(win, image=oriGrat, size=128)

for n in range(100):
    stim.draw()
    win.flip()

There are some caveats when you get into providing your own gratings likes this:

  • they can’t be changed as rapidly as changing the orientation of the whole stimulus - each time you recalculate the texture (to create a new orientation) the CPU has to do the work and then send the new texture to the graphics card. That’s slower than the usual operation which just changes a transformation matrix on the card
  • you don’t get to benefit from PsychoPy calculating your spatial freq any more, in fact it can confuse things because the GratingStim is trying to set cycles horizontally and vertically whereas you want them obliquely. So you better just calculate spatial freq yourself and using ImageStim to present your custom texture (as above)

Or use the aperture stimulus http://www.psychopy.org/api/visual/aperture.html to just draw a fixed-orientation square subset of a larger underlying grating that could be oriented at will?

Super, that’s working great thanks :grin:
If copying Jon’s code, note that you’ll probably need to change ‘psychopy.visual import filters’ to ‘from psychopy import filters’

I’ve been playing around with this and it seems that changing the phase doesn’t have any effect. Appears this is the case regardless of the type of grating drawn, resolution, cycles etc. Any suggestions on why the phase isn’t changing, or what i’m, missing? Thanks again.

Ah, my bad. Looks from the source code like the phase should be in degrees not in the normal 0-1 range that PsychoPy uses elsewhere.I’ve edited my post to give the correct range.