[visionegg] Re: questions on eye - screen distance adjustment

  • From: Andrew Straw <astraw@xxxxxxxxxxx>
  • To: visionegg@xxxxxxxxxxxxx
  • Date: Sat, 30 Aug 2008 08:25:34 -0700

Hi Alexandre,

Alexandre Santos wrote:
> Hello,
> 
> I'm planning to use VisionEgg for my experiments, and the script
> gratingTCP.py fits nearly all my needs except for one thing: The
> distance between the mouse and the screen is not always the same, and
> I need to create a new parameter (distance) so that the spatial_freq
> parameter remains consistent for different mouse distances from the
> screen. This brings me two questions:
> 
> 1) Which parameter should I adjust?
> Initially I wanted to manipulate spatial_freq or size directly with
> distance, but according to the documentation (p.9 of
> http://visionegg.org/visionegg.pdf) size is expressed in arbitrary eye
> coordinate units and converted to pixel coordinates through a
> Projection class. If so, it makes more sense to manipulate this
> projection class with the distance parameter than size or spatial_freq
> which refer to arbitrary eye coordinates. The problem is that while
> reading the SinGrating2D source code I saw no reference to this
> Projection class, it seems that the documentation is either outdated
> or not yet implemented. Unless I completely misunderstood the code,
> the projection is directly calculated in SinGrating2D itself through
> the floating_point_sin variable. Should I adjust for distance at the
> following line of code?
> 
> floating_point_sin =
> numpy.sin(2.0*math.pi*p.spatial_freq*numpy.arange(0.0,w,inc,dtype=numpy.float)+(phase/180.0*math.pi))*0.5*p.contrast+p.pedestal

From your description, it seems that you're not using the projection /
distortion stuff to project a grating of constant angular spatial
frequency across the screen (a la mouse_gabor_perspective.py). In that
case, you're using purely 2D stimuli as opposed to using something like
the SinGrating3D or SphereGrating classes. For 2D stimuli, I would
recommend keeping the projection at the default value -- object space is
transformed window space (pixel coordinates), so that a vertex specified
at (1,2) gets rendered at pixel location (1,2) in your window.

Thus, you should manipulate the spatial frequency variable directly as
your mouse changes distance from the screen.

> 2) How to implement the change?
> Unfortunately I'm learning python as I learn to use VisionEgg, so this
> question is more python than VisionEgg related - sorry for the bother:
> once I figure out how to correct spatial frequency for distance I
> could simply copy SinGrating2D to gratingTCP.py and modify it
> accordingly. But this solution is cumbersome and not very sustainable.
> Since SinGrating2D is an object, I guess the best would be to use a
> new object which would inherit from SinGrating2D, but with the added
> distance parameter. Would the following syntax work?
> 
> gratingTCP.py:
> [snip]
> # Create a new class modified from SinGrating2D
> class ModSinGrating2D(SinGrating2D):
>     """
>     Modified SinGrating2D allowing to enter mouse distance from screen in cm
>     """
>     def __init__(self, distance = None):
>         """
>         if distance not specified don't bother adjusting spatial frequency
>         """
>         self.distance = distance
>     # the following adjustment is totally wrong, I'm just using it as an 
> example
>     if self.distance: p.spatial_freq = 1.0 / ( 2.0 * self.distance *
> numpy.tan( ( ( 1.0 / p.spacial_freq ) * numpy.pi / 180.0 ) / 2.0 ) *
> 1024.0 / screen.size )
> 
> # Create the instance SinGrating with appropriate parameters
> stimulus = ModSinGrating2D(anchor='center')
> [snip]

That's the right idea as far as object-orientedness goes, but you'd need
to update spatial_freq on every call to draw, not in the __init__
function. Also, if you want to be fully VE compliant (to pick an
adjective that pokes fun of myself), you'd want the distance variable to
 have the type checking associated with being a defined as a
parameters_and_defaults.

class ModSinGrating2D(SinGrating2D):
    parameters_and_defaults = {
        'distance':(1.0, ve_types.Real),
    }
    def draw(self):
        # the following adjustment is totally wrong, I'm just using it
as an example
        if self.parameters.distance:
            p.spatial_freq = 1.0 / ( 2.0 * self.distance * numpy.tan( (
( 1.0 / p.spacial_freq ) * numpy.pi / 180.0 ) / 2.0 ) * 1024.0 /
screen.size )
        SinGrating2D.draw(self) # call parent class

I hope those answers help!
-Andrew
======================================
The Vision Egg mailing list
Archives: //www.freelists.org/archives/visionegg
Website: http://www.visionegg.org/mailinglist.html

Other related posts: