diff --git a/stimuli/illusions/cornsweet.py b/stimuli/illusions/cornsweet.py index cc37897d..fc6097e7 100644 --- a/stimuli/illusions/cornsweet.py +++ b/stimuli/illusions/cornsweet.py @@ -1,62 +1,68 @@ import numpy as np -from stimuli.Stimulus import Stimulus -def cornsweet(size=(10,10), ppd=10, contrast=0.5, ramp_width=2, exponent=2.75, - mean_lum=.5): - #TODO: the parameters aren't analogous to the other stimuli +def cornsweet(size=(10.,10.), ppd=10., vmax=1., vmin=0., vtarget=0.5, ramp_width=2., exponent=2.75): """ Create a matrix containing a rectangular Cornsweet edge stimulus. The 2D luminance profile of the stimulus is defined as - L = L_mean +/- (1 - X / w) ** a * L_mean * C/2 for the ramp and - L = L_mean for the area beyond the ramp. + Left side: + v = vtarget + (1 - X / w) ** a * (vmax-vtarget) for the ramp and v = vtarget beyond. + Right side: + v = vtarget - (1 - X / w) ** a * (vmin-vtarget) for the ramp and v = vtarget beyond. X is the distance to the edge, w is the width of the ramp, a is a variable - determining the steepness of the ramp, and C is the contrast at the edge, - defined as C = (L_max-L_min) / L_mean. + determining the steepness of the ramp, vtarget is the luminance of the targets and + vmax/vmin are the max/min luminances. Parameters ---------- size : tuple of 2 numbers - the size of the matrix in degrees of visual angle - ppd : number - the number of pixels in one degree of visual angle - contrast : float, in [0,1] - the contrast at the Cornsweet edge, defined as Michelson contrast - (max_luminance - min_luminance) / (max_luminance + min_luminance) - ramp_width : number (optional) - the width of the luminance ramp in degrees of visual angle. - Default is 3. - exponent : number (optional) - Determines the steepness of the ramp. Default is 2.75. An - exponent value of 0 leads to a stimulus with uniform flanks. - mean_lum : number - The mean luminance of the stimulus, i.e. the value outside of - the ramp area. + size in degrees of visual angle + ppd : float + number of pixels in one degree of visual angle + vmax : float + maximum luminance value + vmin : float + minimum luminance value + vtarget : float + luminance value of targets (=plateaus) + ramp_width : float + width of luminance ramp in degrees of visual angle + exponent : float + determines steepness of ramp (default is 2.75. 1 would be linear) Returns ------- - Dictionary with img: ndarray (2D) and empty mask + Dictionary with img: ndarray (2D) and mask References ---------- - The formula and default values are taken from Boyaci, H., Fang, F., Murray, + The formula and default values are adapted from Boyaci, H., Fang, F., Murray, S.O., Kersten, D. (2007). Responses to Lightness Variations in Early Human Visual Cortex. Current Biology 17, 989-993. """ + size = [int(size[0]*ppd), int(size[1]*ppd)] - img = np.ones(size) * mean_lum + ramp_width = int(ramp_width*ppd) + img = np.ones(size) * vtarget + mask = np.zeros(size) + + # Create ramp profiles individually for left and right side dist = np.arange(size[1] / 2.) - dist = dist / (ramp_width*ppd) + dist = dist / ramp_width dist[dist > 1.] = 1. - profile = (1. - dist) ** exponent * mean_lum * contrast - img[:, :int(np.ceil(size[1]/2.))] += profile[::-1] - img[:, size[1] // 2:] -= profile - mask = None + profile1 = (1. - dist) ** exponent * (vmax-vtarget) + profile2 = (1. - dist) ** exponent * (vmin-vtarget) + img[:, :int(size[1]/2.)] += profile1[::-1] + img[:, size[1] // 2:] += profile2 + + # Generate the target mask + mask[:, 0:int(size[1]/2. - ramp_width - 1)] = 1 + mask[:, int(size[1]/2. + ramp_width+1)::] = 2 return {"img": img, "mask": mask} if __name__ == '__main__': import matplotlib.pyplot as plt stim = cornsweet() - plt.imshow(stim, cmap='gray') + plt.imshow(stim['img'], cmap='gray') plt.show()