Beispiel #1
0
def whites_illusion_gil(shape, ppd, contrast, frequency, mean_lum=.5,
        start='low'):
    """
    Create a version of White's illusion on a square wave, in the style used by
    Gilchrist (2006, p. 281)

    Parameters
    ----------
    shape : tuple of 2 numbers
            The shape of the stimulus in degrees of visual angle. (y,x)
    ppd : number
          the number of pixels in one degree of visual angle
    contrast : number in [0,1]
               the contrast of the grating, defined as 
               (max_luminance - min_luminance) / mean_luminance
    frequency : number
                the spatial frequency of the wave in cycles per degree 
    mean_lum : number
               the mean luminance of the grating, i.e. (max_lum + min_lum) / 2.
               The average luminance of the actual stimulus can differ slightly
               from this value if the stimulus is not an integer of cycles big.
    start : string in ['high', 'low'] (optional)
            specifies if the wave starts with a high or low value. Default is
            'high'.

    Returns
    -------
    stim : 2D ndarray
           the stimulus

    References
    ----------
    Gilchrist A (2006). Seeing Black and White. New York, New York, USA: Oxford
    University Press.
    """
    stim = square_wave(shape, ppd, contrast, frequency, mean_lum, 'half',
                        start)
    half_cycle = int(degrees_to_pixels(1. / frequency / 2, ppd) + .5)
    on_dark_idx = [i for i in range(int(half_cycle * 2.5), 
                                        int(stim.shape[1] - half_cycle * .5)) 
                        if stim[0, i] < mean_lum]
    on_light_idx = [i for i in range(int(half_cycle * 1.5), 
                                        int(stim.shape[1] - half_cycle * 1.5)) 
                        if stim[0, i] > mean_lum]
    stim[stim.shape[0] / 5: stim.shape[0] / 5 * 2, on_light_idx] = mean_lum
    stim[stim.shape[0] / 5 * 3: stim.shape[0] / 5 * 4, on_dark_idx] = mean_lum

    # randomize border cutoff
    max_cut = stim.shape[0] / 10
    bg = stim[0, half_cycle]
    for start_idx in range(0 if start is 'low' else half_cycle,
                            stim.shape[1] - half_cycle, 2 * half_cycle):
        
        stim[0 : np.random.randint(max_cut), 
                start_idx : start_idx + half_cycle] = bg
        stim[stim.shape[0] - np.random.randint(max_cut):, 
                start_idx : start_idx + half_cycle] = bg
    return stim
Beispiel #2
0
def whites_illusion_bmcc(shape,
                         ppd,
                         contrast,
                         frequency,
                         mean_lum=.5,
                         start='high'):
    """
    Create a version of White's illusion on a square wave, in the style used by
    Blakeslee and McCourt (1999).

    Parameters
    ----------
    shape : tuple of 2 numbers
            The shape of the stimulus in degrees of visual angle. (y,x)
    ppd : number
          the number of pixels in one degree of visual angle
    contrast : number in [0,1]
               the contrast of the grating, defined as
               (max_luminance - min_luminance) / mean_luminance
    frequency : number
                the spatial frequency of the wave in cycles per degree
    mean_lum : number
               the mean luminance of the grating, i.e. (max_lum + min_lum) / 2.
               The average luminance of the actual stimulus can differ slightly
               from this value if the stimulus is not an integer of cycles big.
    start : string in ['high', 'low'] (optional)
            specifies if the wave starts with a high or low value. Default is
            'high'.

    Returns
    -------
    stim : 2D ndarray
           the stimulus

    References
    ----------
    Blakeslee B, McCourt ME (1999). A multiscale spatial filtering account of
    the White effect, simultaneous brightness contrast and grating induction.
    Vision research 39(26):4361-77.
    """
    stim = square_wave(shape, ppd, contrast, frequency, mean_lum, 'full',
                       start)
    half_cycle = int(degrees_to_pixels(1. / frequency / 2, ppd) + .5)
    stim[stim.shape[0] / 3:stim.shape[0] / 3 * 2, stim.shape[1] / 2 -
         2 * half_cycle:stim.shape[1] / 2 - half_cycle] = mean_lum
    stim[stim.shape[0] / 3:stim.shape[0] / 3 * 2, stim.shape[1] / 2 +
         half_cycle:stim.shape[1] / 2 + 2 * half_cycle] = mean_lum
    return stim
Beispiel #3
0
    def __init__(self,
                 spatial_scales=3. / 2. ** np.arange(-2,5), 
                 orientations=np.arange(0,180,30),
                 pixels_per_degree=30,
                 weights_slope=.1):
        """
        Create an ODOG model instance.

        Parameters
        ----------
        spatial_scales : list of numbers, optional
                         the spatial frequencies of the filters. Each number
                         corresponds to one DOG filter and specifies the
                         center size, i.e. the distance from zero-crossing to
                         zero-crossing, in degrees of visual angle. Default is
                         an octave range from 12 to 3/16.
        orientations : list of numbers, optional
                       the orientations of the filters in degrees. 0 degrees is
                       a vertical filter, 90 degrees is a horizontal one.
                       Default is 30deg steps from 0 to 150.
        pixels_per_degree : number, optional
                            specifies how many pixels fit within one degree of
                            visual angle in the experimental setup. Default is
                            30.
        weights_slope : number, optional
                        the slope of the log-log function that relates a filter
                        spatial frequency to its weight in the summation.
                        Default is 0.1.
        """
        # determine standard deviation from zero_crossing distance,
        # assuming that the surround sigma is 2 times center sigma.
        center_sigmas = np.array(spatial_scales)
        center_sigmas = (center_sigmas / 2.) / (2 * np.sqrt(2 * np.log(2) / 3))
        center_sigmas = degrees_to_pixels(center_sigmas, pixels_per_degree)

        self.multiscale_filters = []
        for angle in orientations:
            scale_filters = []
            for center_sigma in center_sigmas:
                scale_filters.append(
                    difference_of_gaussians((center_sigma, 2 * center_sigma),
                                            center_sigma, angle))
            self.multiscale_filters.append(scale_filters)

        self.scale_weights = np.exp(weights_slope * np.log(spatial_scales))
        self.spatial_scales = spatial_scales
        self.orientations = orientations
Beispiel #4
0
def whites_illusion_bmcc(shape, ppd, contrast, frequency, mean_lum=.5,
        start='high'):
    """
    Create a version of White's illusion on a square wave, in the style used by
    Blakeslee and McCourt (1999).

    Parameters
    ----------
    shape : tuple of 2 numbers
            The shape of the stimulus in degrees of visual angle. (y,x)
    ppd : number
          the number of pixels in one degree of visual angle
    contrast : number in [0,1]
               the contrast of the grating, defined as 
               (max_luminance - min_luminance) / mean_luminance
    frequency : number
                the spatial frequency of the wave in cycles per degree 
    mean_lum : number
               the mean luminance of the grating, i.e. (max_lum + min_lum) / 2.
               The average luminance of the actual stimulus can differ slightly
               from this value if the stimulus is not an integer of cycles big.
    start : string in ['high', 'low'] (optional)
            specifies if the wave starts with a high or low value. Default is
            'high'.

    Returns
    -------
    stim : 2D ndarray
           the stimulus

    References
    ----------
    Blakeslee B, McCourt ME (1999). A multiscale spatial filtering account of
    the White effect, simultaneous brightness contrast and grating induction.
    Vision research 39(26):4361-77.
    """
    stim = square_wave(shape, ppd, contrast, frequency, mean_lum, 'full',
                        start)
    half_cycle = int(degrees_to_pixels(1. / frequency / 2, ppd) + .5)
    stim[stim.shape[0] / 3: stim.shape[0] / 3 * 2,
         stim.shape[1] / 2 - 2 * half_cycle: 
            stim.shape[1] / 2 - half_cycle] = mean_lum
    stim[stim.shape[0] / 3: stim.shape[0] / 3 * 2,
         stim.shape[1] / 2 + half_cycle: 
            stim.shape[1] / 2 + 2 * half_cycle] = mean_lum
    return stim
Beispiel #5
0
def whites_illusion_gil(shape,
                        ppd,
                        contrast,
                        frequency,
                        mean_lum=.5,
                        start='low'):
    """
    Create a version of White's illusion on a square wave, in the style used by
    Gilchrist (2006, p. 281)

    Parameters
    ----------
    shape : tuple of 2 numbers
            The shape of the stimulus in degrees of visual angle. (y,x)
    ppd : number
          the number of pixels in one degree of visual angle
    contrast : number in [0,1]
               the contrast of the grating, defined as
               (max_luminance - min_luminance) / mean_luminance
    frequency : number
                the spatial frequency of the wave in cycles per degree
    mean_lum : number
               the mean luminance of the grating, i.e. (max_lum + min_lum) / 2.
               The average luminance of the actual stimulus can differ slightly
               from this value if the stimulus is not an integer of cycles big.
    start : string in ['high', 'low'] (optional)
            specifies if the wave starts with a high or low value. Default is
            'high'.

    Returns
    -------
    stim : 2D ndarray
           the stimulus

    References
    ----------
    Gilchrist A (2006). Seeing Black and White. New York, New York, USA: Oxford
    University Press.
    """
    stim = square_wave(shape, ppd, contrast, frequency, mean_lum, 'half',
                       start)
    half_cycle = int(degrees_to_pixels(1. / frequency / 2, ppd) + .5)
    on_dark_idx = [
        i for i in range(int(half_cycle *
                             2.5), int(stim.shape[1] - half_cycle * .5))
        if stim[0, i] < mean_lum
    ]
    on_light_idx = [
        i for i in range(int(half_cycle *
                             1.5), int(stim.shape[1] - half_cycle * 1.5))
        if stim[0, i] > mean_lum
    ]
    stim[stim.shape[0] / 5:stim.shape[0] / 5 * 2, on_light_idx] = mean_lum
    stim[stim.shape[0] / 5 * 3:stim.shape[0] / 5 * 4, on_dark_idx] = mean_lum

    # randomize border cutoff
    max_cut = stim.shape[0] / 10
    bg = stim[0, half_cycle]
    for start_idx in range(0 if start is 'low' else half_cycle,
                           stim.shape[1] - half_cycle, 2 * half_cycle):

        stim[0:np.random.randint(max_cut),
             start_idx:start_idx + half_cycle] = bg
        stim[stim.shape[0] - np.random.randint(max_cut):,
             start_idx:start_idx + half_cycle] = bg
    return stim
Beispiel #6
0
def square_wave(shape,
                ppd,
                contrast,
                frequency,
                mean_lum=.5,
                period='ignore',
                start='high'):
    """
    Create a horizontal square wave of given spatial frequency.

    Parameters
    ----------
    shape : tuple of 2 numbers
            The shape of the stimulus in degrees of visual angle. (y,x)
    ppd : number
          the number of pixels in one degree of visual angle
    contrast : number in [0,1]
               the contrast of the grating, defined as
               (max_luminance - min_luminance) / mean_luminance
    frequency : number
                the spatial frequency of the wave in cycles per degree
    mean_lum : number
               the mean luminance of the grating, i.e. (max_lum + min_lum) / 2.
               The average luminance of the actual stimulus can differ slightly
               from this value if the stimulus is not an integer of cycles big.
    period : string in ['ignore', 'full', 'half'] (optional)
             specifies if the period of the wave is taken into account when
             determining exact stimulus dimensions.
             'ignore' simply converts degrees to pixesl
             'full' rounds down to garuantee a full period
             'half' adds a half period to the size 'full' would yield.
             Default is 'ignore'.
    start : string in ['high', 'low'] (optional)
            specifies if the wave starts with a high or low value. Default is
            'high'.

    Returns
    -------
    stim : 2D ndarray
           the square wave stimulus

    """

    if not period in ['ignore', 'full', 'half']:
        raise TypeError('size not understood: %s' % period)
    if not start in ['high', 'low']:
        raise TypeError('start value not understood: %s' % start)
    if frequency > ppd / 2:
        raise ValueError('The frequency is limited to 1/2 cycle per pixel.')

    shape = degrees_to_pixels(np.array(shape), ppd).astype(int)
    pixels_per_cycle = int(degrees_to_pixels(1. / frequency / 2, ppd) + .5) * 2

    if period is 'full':
        shape[1] = shape[1] / pixels_per_cycle * pixels_per_cycle
    elif period is 'half':
        shape[1] = shape[1] / pixels_per_cycle * pixels_per_cycle + \
                                pixels_per_cycle / 2
    diff = type(mean_lum)(contrast * mean_lum)
    high = mean_lum + diff
    low = mean_lum - diff
    stim = np.ones(shape) * (low if start is 'high' else high)
    index = [
        i + j for i in range(pixels_per_cycle / 2)
        for j in range(0, shape[1], pixels_per_cycle) if i + j < shape[1]
    ]
    stim[:, index] = low if start is 'low' else high
    return stim
Beispiel #7
0
def square_wave(shape, ppd, contrast, frequency, mean_lum=.5, period='ignore',
        start='high'):
    """
    Create a horizontal square wave of given spatial frequency.

    Parameters
    ----------
    shape : tuple of 2 numbers
            The shape of the stimulus in degrees of visual angle. (y,x)
    ppd : number
          the number of pixels in one degree of visual angle
    contrast : number in [0,1]
               the contrast of the grating, defined as 
               (max_luminance - min_luminance) / mean_luminance
    frequency : number
                the spatial frequency of the wave in cycles per degree 
    mean_lum : number
               the mean luminance of the grating, i.e. (max_lum + min_lum) / 2.
               The average luminance of the actual stimulus can differ slightly
               from this value if the stimulus is not an integer of cycles big.
    period : string in ['ignore', 'full', 'half'] (optional)
             specifies if the period of the wave is taken into account when
             determining exact stimulus dimensions.
             'ignore' simply converts degrees to pixesl
             'full' rounds down to garuantee a full period
             'half' adds a half period to the size 'full' would yield.
             Default is 'ignore'.
    start : string in ['high', 'low'] (optional)
            specifies if the wave starts with a high or low value. Default is
            'high'.

    Returns
    -------
    stim : 2D ndarray
           the square wave stimulus
    """
    
    if not period in ['ignore', 'full', 'half']:
        raise TypeError('size not understood: %s' % period)
    if not start in ['high', 'low']:
        raise TypeError('start value not understood: %s' % start)
    if frequency > ppd / 2:
        raise ValueError('The frequency is limited to 1/2 cycle per pixel.')

    shape = degrees_to_pixels(np.array(shape), ppd).astype(int)
    pixels_per_cycle = int(degrees_to_pixels(1. / frequency / 2, ppd) + .5) * 2

    if period is 'full':
        shape[1] = shape[1] / pixels_per_cycle * pixels_per_cycle
    elif period is 'half':
        shape[1] = shape[1] / pixels_per_cycle * pixels_per_cycle + \
                                pixels_per_cycle / 2
    diff = type(mean_lum)(contrast * mean_lum)
    high = mean_lum + diff
    low = mean_lum - diff
    stim = np.ones(shape) * (low if start is 'high' else high)
    index = [i + j for i in range(pixels_per_cycle / 2) 
                      for j in range(0, shape[1], pixels_per_cycle)
                      if i + j < shape[1]]
    stim[:, index] = low if start is 'low' else high
    return stim