From 7314b85e480e350a47cf9b7719404e93ace1bcbd Mon Sep 17 00:00:00 2001 From: lynnschmittwilken Date: Wed, 15 Jun 2022 21:01:51 +0200 Subject: [PATCH] updated rings and bullseye to only create single stim and let paper-pys do the stacking and padding --- stimuli/illusions/bullseye.py | 54 +++++++++++++++-- stimuli/illusions/rings.py | 80 ++++++++++++++++++++++++- stimuli/papers/RHS2007.py | 107 +++++++++++++++++++++++++--------- stimuli/papers/domijan2015.py | 44 ++++++++++---- 4 files changed, 242 insertions(+), 43 deletions(-) diff --git a/stimuli/illusions/bullseye.py b/stimuli/illusions/bullseye.py index 4e946d1a..dbab2957 100644 --- a/stimuli/illusions/bullseye.py +++ b/stimuli/illusions/bullseye.py @@ -1,5 +1,6 @@ import numpy as np -from stimuli.illusions.rings import ring_pattern +from stimuli.illusions.rings import ring_pattern, ring_single +from stimuli.utils import plot_stim def bullseye_illusion( @@ -75,9 +76,54 @@ def bullseye_illusion( return {"img": img, "mask": mask} +def bullseye_single( + ppd=10, + n_rings=8, + target_idx=0, + ring_width=0.5, + vring1=1.0, + vring2=0.0, + vtarget=0.5 +): + """ + Bullseye Illusion. + + Parameters + ---------- + ppd : int + pixels per degree (visual angle) + n_rings : int + the number of rings + target_idx : int or tuple or list + indices of target ring(s) + ring_width : float + width per ring in degrees visual angle + vring1 : float + value for even rings + vring2 : float + value for odd rings + vtarget : float + value for target + + Returns + ------- + A stimulus object + """ + stim = ring_single( + ppd=ppd, + n_rings=n_rings, + target_idx=target_idx, + ring_width=ring_width, + vring1=vring1, + vring2=vring2, + vtarget=vtarget + ) + + return {"img": stim['img'], "mask": stim['mask']} + + if __name__ == "__main__": import matplotlib.pyplot as plt - stim = bullseye_illusion() - plt.imshow(stim.img, cmap="gray") - plt.show() + stim = bullseye_single() + plot_stim(stim, mask=True) diff --git a/stimuli/illusions/rings.py b/stimuli/illusions/rings.py index d1bbdcff..ce20dccd 100644 --- a/stimuli/illusions/rings.py +++ b/stimuli/illusions/rings.py @@ -116,8 +116,86 @@ def ring_pattern( return {"img": img, "mask": mask} +def ring_single( + ppd=10, + n_rings=8, + target_idx=4, + ring_width=0.5, + vring1=1.0, + vring2=0.0, + vtarget=0.5 +): + """ + Ring Pattern White's-like illusion + + Parameters + ---------- + ppd : int + pixels per degree (visual angle) + n_rings : int + the number of rings + target_idx : int or tuple or list + indices of target ring(s) + ring_width : float + width per ring in degrees visual angle + vring1 : float + value for even rings + vring2 : float + value for odd rings + vtarget : float + value for target + + Returns + ------- + A stimulus dictionary with the stimulus ['img'] and target mask ['mask'] + """ + + ring_width_px = degrees_to_pixels(ring_width, ppd) + + # calculate Minkowski-p=inf distances from centre + x = np.arange(0, n_rings) + x = np.hstack([np.flip(x), x]) + radii = np.maximum(np.abs(x[np.newaxis]), np.abs(x[:, np.newaxis])) + + # build array representing rings + arr = np.ones((n_rings * 2, n_rings * 2)) * vring1 + mask_arr = np.zeros((n_rings * 2, n_rings * 2)) + arr[radii % 2 == 1] = vring2 + if isinstance(target_idx, int): + target_idx = [target_idx] + elif isinstance(target_idx, tuple): + target_idx = list(target_idx) + target_idx = list(np.array(target_idx)) + for idx in target_idx: + arr[radii == idx] = vtarget + mask_arr[radii == idx] = 1 + + # build image from array + img = np.repeat( + np.repeat(arr, ring_width_px, axis=0), ring_width_px, axis=1 + ) + mask = np.repeat( + np.repeat(mask_arr, ring_width_px, axis=0), ring_width_px, axis=1 + ) + + y_c, x_c = img.shape + y_c //= 2 + x_c //= 2 + + row_c = img[y_c, :] + row_c_mask = mask[y_c, :] + img = np.insert(img, y_c, row_c, axis=0) + mask = np.insert(mask, y_c, row_c_mask, axis=0) + + col_c = img[:, x_c] + col_c_mask = mask[:, x_c] + img = np.insert(img, x_c, col_c, axis=1) + mask = np.insert(mask, x_c, col_c_mask, axis=1) + return {"img": img, "mask": mask} + + if __name__ == "__main__": import matplotlib.pyplot as plt - stim = ring_pattern() + stim = ring_single() plot_stim(stim, mask=True) diff --git a/stimuli/papers/RHS2007.py b/stimuli/papers/RHS2007.py index fb796883..7f87b7e3 100644 --- a/stimuli/papers/RHS2007.py +++ b/stimuli/papers/RHS2007.py @@ -625,36 +625,89 @@ def todorovic_benary3_4(): def bullseye_thin(ppd=PPD): - # The parameters are mostly guessed - stim = stimuli.illusions.bullseye.bullseye_illusion( - n_rings=8, - ring_width=1, - back=1.0, - rings=9.0, - target=5.0, - ) - shape = degrees_to_pixels(VISEXTENT, ppd) - stim["img"] = pad_img_to_shape(stim["img"], shape, val=0.5) - stim["mask"] = pad_img_to_shape(stim["mask"], shape, val=0) - - return stim + v1, v2, v3 = 1., 0.5, 0. + shape_ind = degrees_to_pixels(np.array(VISEXTENT)/2., ppd) + shape_all = degrees_to_pixels(VISEXTENT, ppd) + stim1 = stimuli.illusions.bullseye.bullseye_single( + ppd=ppd, + n_rings=8, + target_idx=(0, 1, 2, 3), + ring_width=0.1, + vring1=v1, + vring2=v3, + vtarget=v2, + ) + stim2 = stimuli.illusions.bullseye.bullseye_single( + ppd=ppd, + n_rings=8, + target_idx=(0, 1, 2, 3), + ring_width=0.1, + vring1=v3, + vring2=v1, + vtarget=v2, + ) + + # Individual padding + img1 = pad_img_to_shape(stim1['img'], shape_ind, v2) + mask1 = pad_img_to_shape(stim1['mask'], shape_ind, 0) + img2 = pad_img_to_shape(stim2['img'], shape_ind, v2) + mask2 = pad_img_to_shape(stim2['mask'], shape_ind, 0) + + # Increase target index of right stimulus half + mask2 = mask2 + 1 + mask2[mask2 == 1] = 0 + + # Stacking + img = np.hstack([img1, img2]) + mask = np.hstack([mask1, mask2]) + + # Full padding + img = pad_img_to_shape(img, shape_all, v2) + mask = pad_img_to_shape(mask, shape_all, 0) + return {"img": img, "mask": mask} def bullseye_thick(ppd=PPD): - # The parameters are mostly guessed - stim = stimuli.illusions.bullseye.bullseye_illusion( - n_rings=8, - ring_width=1, - back=1.0, - rings=9.0, - target=5.0, - ) - - shape = degrees_to_pixels(VISEXTENT, ppd) - stim["img"] = pad_img_to_shape(stim["img"], shape, val=0.5) - stim["mask"] = pad_img_to_shape(stim["mask"], shape, val=0) - - return stim + v1, v2, v3 = 1., 0.5, 0. + shape_ind = degrees_to_pixels(np.array(VISEXTENT)/2., ppd) + shape_all = degrees_to_pixels(VISEXTENT, ppd) + stim1 = stimuli.illusions.bullseye.bullseye_single( + ppd=ppd, + n_rings=6, + target_idx=(0, 1), + ring_width=0.2, + vring1=v1, + vring2=v3, + vtarget=v2, + ) + stim2 = stimuli.illusions.bullseye.bullseye_single( + ppd=ppd, + n_rings=6, + target_idx=(0, 1), + ring_width=0.2, + vring1=v3, + vring2=v1, + vtarget=v2, + ) + + # Individual padding + img1 = pad_img_to_shape(stim1['img'], shape_ind, v2) + mask1 = pad_img_to_shape(stim1['mask'], shape_ind, 0) + img2 = pad_img_to_shape(stim2['img'], shape_ind, v2) + mask2 = pad_img_to_shape(stim2['mask'], shape_ind, 0) + + # Increase target index of right stimulus half + mask2 = mask2 + 1 + mask2[mask2 == 1] = 0 + + # Stacking + img = np.hstack([img1, img2]) + mask = np.hstack([mask1, mask2]) + + # Full padding + img = pad_img_to_shape(img, shape_all, v2) + mask = pad_img_to_shape(mask, shape_all, 0) + return {"img": img, "mask": mask} if __name__ == "__main__": diff --git a/stimuli/papers/domijan2015.py b/stimuli/papers/domijan2015.py index 020f4685..9a17fce8 100644 --- a/stimuli/papers/domijan2015.py +++ b/stimuli/papers/domijan2015.py @@ -84,17 +84,39 @@ def rings(ppd=PPD): def bullseye(ppd=PPD): - return illusions.bullseye.bullseye_illusion( - ppd=ppd, - n_rings=8, - ring_width=0.5, - target_pos_l=0, - target_pos_r=0, - padding=(0.9, 1.0, 0.9, 1.0), - back=1.0, - rings=9.0, - target=5.0, - ) + v1, v2, v3 = 1., 5., 9. + pad = (0.9, 1.0, 0.9, 1.0) + stim1 = illusions.bullseye.bullseye_single( + ppd=ppd, + n_rings=8, + target_idx=0, + ring_width=0.5, + vring1=v1, + vring2=v3, + vtarget=v2, + ) + stim2 = illusions.bullseye.bullseye_single( + ppd=ppd, + n_rings=8, + target_idx=0, + ring_width=0.5, + vring1=v3, + vring2=v1, + vtarget=v2, + ) + + # Padding + img1, mask1 = pad_img(stim1['img'], pad, ppd, v1), pad_img(stim1['mask'], pad, ppd, 0) + img2, mask2 = pad_img(stim2['img'], pad, ppd, v1), pad_img(stim2['mask'], pad, ppd, 0) + + # Increase target index of right stimulus half + mask2 = mask2 + 1 + mask2[mask2 == 1] = 0 + + # Stacking + img_stacked = np.hstack([img1, img2]) + mask_stacked = np.hstack([mask1, mask2]) + return {"img": img_stacked, "mask": mask_stacked} def simultaneous_brightness_contrast(ppd=PPD):