Skip to content

Commit

Permalink
RHD2007 stimuli are mostly replicated
Browse files Browse the repository at this point in the history
  • Loading branch information
matko031 committed Jul 3, 2021
1 parent a7d6dd6 commit 4912557
Show file tree
Hide file tree
Showing 9 changed files with 1,303 additions and 765 deletions.
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -20,7 +20,7 @@
'stimuli.texture',
'stimuli.transparency',
'stimuli.illusions',
'stimuli.papers_stimuli'
'stimuli.papers'
),
package_data={'stimuli.transparency': ['checkerboard_mask.png']},
install_requires=[
Expand Down
2 changes: 1 addition & 1 deletion stimuli/__init__.py
Expand Up @@ -4,4 +4,4 @@
from . import texture
from . import transparency
from . import papers
from . import utils
from .utils import utils
58 changes: 34 additions & 24 deletions stimuli/illusions/grating_induction.py
@@ -1,37 +1,47 @@
import numpy as np
from scipy.ndimage.filters import gaussian_filter
from stimuli.utils import degrees_to_pixels, pad_img

import stimuli

###################################
# Grating induction #
###################################
def grating_illusion(n_grid, grating_shape, target_height, blur, padding=(10,10,10,10,)):
# Inputs:
# - n_grid: number of black and white stripes (int, unit: pixels)
# - target_shape: (height, width) of the target in px
# - blur: amount of blur added (float)
def grating_illusion(shape=(10,10), ppd=40, frequency=0.5, target_height=0.5, blur=None, high=1., low=0., target=.5, start='low', period='ignore', padding=(2,2,2,2)):
if blur == None:
blur = shape[0]/2

grating_height, grating_width = grating_shape
height_px, width_px = degrees_to_pixels(shape, ppd)
target_height_px = degrees_to_pixels(target_height, ppd)

# Create grid
grid = np.zeros((1,n_grid), dtype=np.float32)
grid[0, ::2] = 1
grid[0, 1::2] = 0
img, pixels_per_cycle = stimuli.illusions.square_wave(shape, ppd, frequency, high, low, period, start)
img = gaussian_filter(img, blur)
mask = np.zeros((height_px, width_px))

# Increase the resolution of the grid for blurring it later:
grid = np.repeat(grid, grating_height, axis=0)
grid = np.repeat(grid, grating_width, axis=1)
grid = gaussian_filter(grid, blur)
target_start = height_px//2 - target_height_px//2
target_end = target_start + target_height_px
img[target_start:target_end, :] = target
mask[target_start:target_end, :] = True

# Place target on blurred grid
target_start_y = (grating_height-target_height)//2
grid[target_start_y : target_start_y + target_height, :] = 0.5
return grid
img = pad_img(img, padding, ppd, target)
mask = pad_img(mask, padding, ppd, 0)

return (img, mask)

def RHS2007_grating_induction():
n_grid = 8
phase_width = 2
res_factor = 20
target_height, target_width = phase_width * res_factor * 6, phase_width * res_factor
return grating_induction(n_grid=8, grating_shape=(target_height, target_width),
target_height=phase_width * res_factor // 2, blur=5)
total_height, total_width, ppd = (32,)*3
n_cycles = 4
height, width = 12, 16
frequency = n_cycles / width
padding_horizontal = (total_width - width) / 2
padding_vertical = (total_height - height) / 2
padding = (padding_vertical, padding_vertical, padding_horizontal, padding_horizontal)
img = stimuli.illusions.grating_induction.grating_illusion(shape=(height, width), ppd=ppd, frequency=frequency, target_height=1, blur=10, start='high', padding=padding)
return img


if __name__ == '__main__':
import matplotlib.pyplot as plt
img, mask = grating_illusion()
plt.imshow(img, cmap='gray')
plt.show()
43 changes: 21 additions & 22 deletions stimuli/illusions/square_wave.py
Expand Up @@ -2,7 +2,7 @@
from stimuli.utils.utils import degrees_to_pixels


def square_wave(shape, ppd, contrast, frequency, mean_lum=.5, period='ignore',
def square_wave(shape=(10,10), ppd=10, frequency=1, high=1.0, low=0.0, period='ignore',
start='high'):
"""
Create a horizontal square wave of given spatial frequency.
Expand All @@ -13,15 +13,13 @@ def square_wave(shape, ppd, contrast, frequency, mean_lum=.5, period='ignore',
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 : float, in [0,1]
the contrast of the grating, defined as
(max_luminance - min_luminance) / mean_luminance
high: float
value of the bright pixels
low: float
value of the dark pixels
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.
Expand All @@ -38,7 +36,6 @@ def square_wave(shape, ppd, contrast, frequency, mean_lum=.5, period='ignore',
stim : ndarray (2D)
the square wave stimulus
"""
#TODO: very buggy, fix problems when being called in white_bmcc and white_gil


if period not in ['ignore', 'full', 'half']:
Expand All @@ -48,22 +45,24 @@ def square_wave(shape, ppd, contrast, frequency, mean_lum=.5, period='ignore',
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
height, width = degrees_to_pixels(shape, ppd)
pixels_per_cycle = degrees_to_pixels(1. / (frequency*2) , ppd) * 2

if period is 'full':
shape = (shape // pixels_per_cycle) * pixels_per_cycle
width = (shape_pixels // pixels_per_cycle) * pixels_per_cycle
elif period is 'half':
shape = (shape // 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)
width = (shape_pixels // pixels_per_cycle) * pixels_per_cycle + pixels_per_cycle / 2

stim = np.ones((height, width)) * (low if start is 'high' else high)

# TODO: shape[0] used to be just shape, Matko changed it to shape[0] just to make it work, look into it
index = [i + j for i in range(pixels_per_cycle // 2)
for j in range(0, shape[0], pixels_per_cycle)
if i + j < shape[0]]
for j in range(0, width, pixels_per_cycle)
if i + j < width]
stim[:, index] = low if start is 'low' else high
return stim
return (stim, pixels_per_cycle)


if __name__ == '__main__':
import matplotlib.pyplot as plt
plt.imshow(square_wave()[0], cmap='gray')
plt.show()

0 comments on commit 4912557

Please sign in to comment.