how to render a multicolored radial grating at fast framerates?

214 views
Skip to first unread message

Alex Holcombe

unread,
Dec 28, 2010, 9:30:27 PM12/28/10
to psychopy-users
Dear Psychopyers,

I need to create two rotating radial red-green (or blue-yellow, etc.)
grating annuli, like shown here:
http://www.psych.usyd.edu.au/staff/alexh/research/trackingPairing/radialMulticoloredGratings.png
Actually, even better than alternating between two colors as shown in
the picture, would instead be to alternate among three colors, e.g.
red-green-blue as one goes around the circle. However, I'd settle for
two colors.

The drawing must be fast, so that I can update the two annuli at 120
Hz. How should I do this in PsychoPy?
I see two solutions, but each has possible stumbling blocks I need
help with:

1. Use RadialStim with tex='sqr', and mask the inner part to create an
annulus. I can set the color of one patch using RadialStim's *color*
parameter, however, the other color cannot be chosen, but rather is
created essentially by multiplying -1 by the RGB value of the *color*.
For example, if color=[1,-1,-1] and contrast=1, then the other color
appears to be cyan (-1,1,1). Is there a way to control the other
color, perhaps by creating a custom texture? Maybe not, because going
in another direction in color space would seem to require
multiplication by a vector rather than a scalar, and according to the
documentation of RadialStim, the tex parameter can be no more complex
than a 2-D array of scalars.
Second possible problem: the documentation for RadialStim says "it
also takes longer to draw than a typical PatchStim, so not recommended
for tasks where high frame rates are needed."

2. Use visual.PatchStim with a custom 256x256x3 arraytexture, a la
customTextures.py demo. I suppose that this method can allow the
creation of arbitrary stimuli, including my multicolored annuli.
However, I presume that this routine is not fast enough to support
high frame rates?

Can the slow updating of either of these solutions be compensated for
by a sufficiently fancy graphics card and Mac Pro? For instance, I see
the NVIDIA has released a $1199 Quadro 4000 for Mac graphics card
"capable of processing 890 million triangles per second". I suspect
that's be just fine, if only I know how to take advantage of all those
millions...

Jonathan Peirce

unread,
Dec 28, 2010, 10:55:23 PM12/28/10
to psychop...@googlegroups.com

On 29/12/2010 02:30, Alex Holcombe wrote:
> Dear Psychopyers,
>
> I need to create two rotating radial red-green (or blue-yellow, etc.)
> grating annuli, like shown here:
> http://www.psych.usyd.edu.au/staff/alexh/research/trackingPairing/radialMulticoloredGratings.png
> Actually, even better than alternating between two colors as shown in
> the picture, would instead be to alternate among three colors, e.g.
> red-green-blue as one goes around the circle. However, I'd settle for
> two colors.

To create a 3-color progression you would need to create a 256x256x3
numpy array of your colour sequence and pass that to the RadialStim as a
texture, but right now it doesn't support that (PatchStim does, and I
should be able to make this possible in Radial too).


> The drawing must be fast, so that I can update the two annuli at 120
> Hz. How should I do this in PsychoPy?
> I see two solutions, but each has possible stumbling blocks I need
> help with:
>
> 1. Use RadialStim with tex='sqr', and mask the inner part to create an
> annulus. I can set the color of one patch using RadialStim's *color*
> parameter, however, the other color cannot be chosen, but rather is
> created essentially by multiplying -1 by the RGB value of the *color*.
> For example, if color=[1,-1,-1] and contrast=1, then the other color
> appears to be cyan (-1,1,1). Is there a way to control the other
> color, perhaps by creating a custom texture?

To create two different colors you should just create two separate stimuli::

#!/usr/bin/env python
from psychopy import visual, event, core

globalClock = core.Clock()
win = visual.Window([800,800])
#make two wedges (in opposite contrast) and alternate them for flashing
ring1 = visual.RadialStim(win, tex='sqrXsqr', color=[-1,-1,1],size=1,
mask=[0,0,1,1,0,0,0,0,0,0,], radialCycles=0, angularCycles=8,
interpolate=False)
ring2 = visual.RadialStim(win, tex='sqrXsqr', color=[1,-1,-1],size=1,
mask=[0,0,0,0,0,0,1,1,0,0,], radialCycles=0, angularCycles=8,
interpolate=False)

t=0
rotationRate = 0.01 #revs per sec
while t<5:#for 5 secs
t=globalClock.getTime()

ring1.setOri(t*rotationRate*360.0)
ring1.draw()
ring2.setOri(-t*rotationRate*360.0)
ring2.draw()
win.flip()

win.close()

> Second possible problem: the documentation for RadialStim says "it
> also takes longer to draw than a typical PatchStim, so not recommended
> for tasks where high frame rates are needed."
>

Suck it and see - check your frame times for the code above. Radial
stimuli draw a large number of triangles, approximating a circle. This
is done in an efficient manner though with nearly all the calculations
being done on the graphics card if it supports opengl 2. Yes, because
the gfx card is doing the calculations it will make a difference having
a good one, but I'd be surprised if you need one as fancy as $1200!


> 2. Use visual.PatchStim with a custom 256x256x3 arraytexture, a la
> customTextures.py demo. I suppose that this method can allow the
> creation of arbitrary stimuli, including my multicolored annuli.
> However, I presume that this routine is not fast enough to support
> high frame rates?
>

If you're creating the stimulus just once and rotating it unchanged then
this could work, because you won't need to call the texture creation
code. But the code will be less intuitive (a circular image in a square
texture) and if you do anything that requires a new texture (e.g. a
change in radial SF) you'll possibly drop a frame during the update.
Basically, I think the radialstim will allow you more options as your
experiment evolves, provided the card does the drawing fast enough.

All the best,
Jon

--
Dr. Jonathan Peirce
Nottingham Visual Neuroscience

http://www.peirce.org.uk/

Jonathan Peirce

unread,
Dec 29, 2010, 12:43:22 AM12/29/10
to psychop...@googlegroups.com

On 29/12/2010 02:30, Alex Holcombe wrote:

> Dear Psychopyers,
>
> I need to create two rotating radial red-green (or blue-yellow, etc.)
> grating annuli, like shown here:
> http://www.psych.usyd.edu.au/staff/alexh/research/trackingPairing/radialMulticoloredGratings.png
> Actually, even better than alternating between two colors as shown in
> the picture, would instead be to alternate among three colors, e.g.
> red-green-blue as one goes around the circle. However, I'd settle for
> two colors.

I was wrong - I had already implemented the option to provide an rgb
(NxNx3) array to the RadialStim. I've updated the docs to reflect that,
but the below shows you how too. Beware to set the color to [1,1,1] if
you're setting an rgb array as the texture::


#!/usr/bin/env python
#rotate flashing wedge


from psychopy import visual, event, core

import numpy as np

#create texture (note imperfect rounding of 64/3)
rgb = np.zeros([64,64,3])-1#start with all channels in all locs = -1
rgb[:, 0:(64/3), 0]=1 #bottom 1/3rd of the first channel=1
rgb[:, (64/3):(64*2/3), 1]=1 #middle 1/3rd of the 2nd channel=1
rgb[:, (64*2/3):(64*3/3), 2]=1 #top 1/3rd of the 3rd channel=1

globalClock = core.Clock()
win = visual.Window([800,800])
#make two wedges (in opposite contrast) and alternate them for flashing

ring1 = visual.RadialStim(win, tex=rgb, color=[1,1,1],size=1,

Alex Holcombe

unread,
Dec 30, 2010, 12:55:06 AM12/30/10
to psychopy-users
Hi Jon, thanks very much for all this helpful advice. I don't
understand how your 2 gratings example could allow me to make a red-
green grating as opposed to a red-cyan one, but anyway I'll start by
trying for a tricolored grating using radialstim with the x3 mask.
Thanks again and happy new year.

On Dec 28, 10:55 pm, Jonathan Peirce <jon.pei...@gmail.com> wrote:
> On 29/12/2010 02:30, Alex Holcombe wrote:> Dear Psychopyers,
>
> > I need to create two rotating radial red-green (or blue-yellow, etc.)
> > grating annuli, like shown here:
> >http://www.psych.usyd.edu.au/staff/alexh/research/trackingPairing/rad...
Reply all
Reply to author
Forward
0 new messages