Source code for stimupy.papers.RHS2007

"""Stimuli from Robinson, Hammon & de Sa (2007)
https://doi.org/10.1016/j.visres.2007.02.017

This module reproduces all of the stimuli used by Robinson,
Hammon & de Sa (2007) as they were provided to the model described
in that paper.

Each stimulus is provided by a separate function,
a full list can be found as stimupy.papers.RHS2007.__all__

The output of each of these functions is a stimulus dictionary.

For a visual representation of all the stimuli and their mask,
simply run this module as a script:

    $ python stimuli/papers/RHS2007.py

Attributes
----------
__all__ (list of str): list of all stimulus-functions
    that are exported by this module when executing
        >>> from stimupy.papers.RHS2007 import *

References
----------
Robinson, A. E., Hammon, P. S., & de Sa, V. R. (2007).
    Explaining brightness illusions
    using spatial filtering and local response normalization.
    Vision Research, 47(12), 1631-1644.
    https://doi.org/10.1016/j.visres.2007.02.017
"""

import numpy as np

import stimupy
from stimupy.utils import (
    flip_dict,
    pad_dict_by_visual_size,
    pad_dict_to_shape,
    pad_dict_to_visual_size,
    resolution,
    rotate_dict,
    stack_dicts,
)

__all__ = [
    "WE_thick",
    "WE_thin_wide",
    "WE_dual",
    "WE_anderson",
    "WE_howe",
    "WE_zigzag",
    "WE_radial_thick_small",
    "WE_radial_thick",
    "WE_radial_thin_small",
    "WE_radial_thin",
    "WE_circular1",
    "WE_circular05",
    "WE_circular025",
    "grating_induction",
    "sbc_large",
    "sbc_small",
    "todorovic_equal",
    "todorovic_in_large",
    "todorovic_in_small",
    "todorovic_out",
    "checkerboard_016",
    "checkerboard_094",
    "checkerboard_21",
    "corrugated_mondrian",
    "benary_cross",
    "todorovic_benary1_2",
    "todorovic_benary3_4",
    "todorovic_benary1_2_3_4",
    "bullseye_thin",
    "bullseye_thick",
]

VISEXTENT = (32.0, 32.0)
PPD = 32
v1, v2, v3 = 0.0, 0.5, 1.0


def gen_all(ppd=PPD, pad=True, skip=False):
    stims = {}  # save the stimulus-dicts in a larger dict, with name as key
    for stim_name in __all__:
        print(f"Generating RHS2007.{stim_name}")

        # Get a reference to the actual function
        func = globals()[stim_name]
        try:
            stim = func(ppd=ppd, pad=pad)

            # Accumulate
            stims[stim_name] = stim
        except NotImplementedError as e:
            if not skip:
                raise e
            # Skip stimuli that aren't implemented
            print("-- not implemented")
            pass

    return stims


[docs]def WE_thick(ppd=PPD, pad=True): """White stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1a. Grating size: 12x16 deg Grating frequency: 0.25 cpd Target size: 4x2 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (1999). A multiscale spatial filtering account of the White effect, simultaneous brightness contrast and grating induction. Vision Research, 39, 4361-4377. White, M. (1979). A new effect of pattern on perceived lightness. Perception, 8, 413-416. """ height, width = 12.0, 16.0 params = { "ppd": ppd, "frequency": 4.0 / width, "intensity_bars": (v3, v1), "intensity_target": v2, "target_indices": (3, 6), "target_heights": 4.0, "period": "even", } stim = stimupy.whites.white( visual_size=(height, width), **params, ) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 4.18, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def WE_thin_wide(ppd=PPD, pad=True): """White stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1b. Grating size: 12x16 deg Grating frequency: 0.5 cpd Target size: 2x1 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (1999). A multiscale spatial filtering account of the White effect, simultaneous brightness contrast and grating induction. Vision Research, 39, 4361-4377. White, M. (1979). A new effect of pattern on perceived lightness. Perception, 8, 413-416. """ height, width = 12.0, 16.0 params = { "ppd": ppd, "frequency": 8.0 / width, "intensity_bars": (v1, v3), "intensity_target": v2, "target_indices": (4, 13), "target_heights": 2.0, "period": "even", } stim = stimupy.whites.white( visual_size=(height, width), **params, ) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 4.6, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def WE_dual(ppd=PPD, pad=True): """Dual White stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1c. Grating sizes: 6x8 deg Grating frequency: 0.5 cpd Target size: 2x1 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters """ height, width = 6.0, 8.0 params = { "ppd": ppd, "frequency": 4.0 / width, "intensity_bars": (v3, v1), "intensity_target": v2, "target_indices": (3, 6), "target_heights": 2.0, "period": "even", } stim1 = stimupy.whites.white( visual_size=(height, width), **params, ) stim2 = stimupy.whites.white( visual_size=(height, width), **params, ) stim2 = rotate_dict(stim2, 3) if pad: shape = np.array(resolution.shape_from_visual_size_ppd(VISEXTENT, ppd)) / (1, 2) else: shape = np.max([stim1["img"].shape, stim2["img"].shape], axis=1) # Pad and stack stim1 = pad_dict_to_shape(stim1, shape, pad_value=v2) stim2 = pad_dict_to_shape(stim2, shape, pad_value=v2) stim = stack_dicts(stim1, stim2, keep_mask_indices=False) params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), ) return {**stim, **params}
[docs]def WE_anderson(ppd=PPD, pad=True): """Anderson variation of White stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1d. Grating size: 16x16 deg Grating frequency: 0.5 cpd Target size: 3.2x1 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Anderson, B. L. (2001). Contrasting theories of White's illusion. Perception, 30, 1499-1501 Blakeslee, B., Pasieka, W., & McCourt, M. E. (2005). Oriented multiscale spatial filtering and contrast normalization: a parsimonious model of brightness induction in a continuum of stimuli including White, Howe and simultaneous brightness contrast. Vision Research, 45, 607-615. """ height, width = 16.0, 16.0 params = { "ppd": ppd, "frequency": 8.0 / width, "intensity_bars": (v3, v1), "intensity_target": v2, "target_indices_top": (6,), "target_indices_bottom": (11,), "target_center_offset": height / 10.0, "target_height": height / 5.0, "intensity_stripes": (v1, v3), "stripe_center_offset": height / 5.0, "stripe_height": height / 5.0, "period": "even", } stim = stimupy.whites.anderson( visual_size=(height, width), **params, ) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 6.43, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def WE_howe(ppd=PPD, pad=True): """Howe variation of White stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1e. Grating size: 16x16 deg Grating frequency: 0.5 cpd Target size: 3.2x1 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., Pasieka, W., & McCourt, M. E. (2005). Oriented multiscale spatial filtering and contrast normalization: a parsimonious model of brightness induction in a continuum of stimuli including White, Howe and simultaneous brightness contrast. Vision Research, 45, 607-615. Howe, P. D. L. (2001). A comment on the Anderson (1997), the Todorovic (1997), and the Ross and Pessoa (2000) explanations of White's effect. Perception, 30, 1023-1026 """ height, width = 16.0, 16.0 params = { "ppd": ppd, "frequency": 8.0 / width, "intensity_bars": (v3, v1), "intensity_target": v2, "target_indices_top": (6,), "target_indices_bottom": (11,), "target_center_offset": height / 5.0, "target_height": height / 5.0, "intensity_stripes": (v1, v3), "period": "even", } stim = stimupy.whites.howe( visual_size=(height, width), **params, ) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 0.0, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def WE_zigzag(ppd=PPD, pad=True): """Wedding cake stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1f. Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Clifford, C. W. G., & Spehar, B. (2003). Using colour to disambiguate contrast and assimilation in White's effect. Journal of Vision, 3, 294a. https://doi.org/10.1167/3.9.294 """ i1, i2 = 1, 2 stim = stimupy.wedding_cakes.wedding_cake( visual_size=(16.0, 17.0), ppd=PPD, L_size=(4.0, 4, 1.0), target_height=2.0, target_indices1=((i1, -1), (i1, 0), (i1, 1), (i1, 2)), target_indices2=((i2, 0), (i2, 1), (i2, 2), (i2, 3)), intensity_bars=(1.0, 0.0), intensity_target=0.5, ) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) return stim
[docs]def WE_radial_thick_small(ppd=PPD, pad=True): """Radial White stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1g. Circle size: 16x16 deg Number of segments: 14 Target length: 4 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Anstis, S. (2003). White's effect in brightness & color. Online Demonstration """ n_segments = 14 params = { "ppd": ppd, "n_segments": n_segments, "rotation": 90 - (90 / (n_segments / 2)), "target_indices": (1, 8), "target_width": 4.0, "target_center": 4.5, "intensity_segments": (v1, v3), "intensity_background": v2, "intensity_target": v2, } stim = stimupy.whites.angular( visual_size=(16, 16), **params, ) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), ) return {**stim, **params}
[docs]def WE_radial_thick(ppd=PPD, pad=True): """Radial White stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1h. Circle size: 24x24 deg Number of segments: 18 Target length: 4 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Anstis, S. (2003). White's effect in brightness & color. Online Demonstration """ n_segments = 18 params = { "ppd": ppd, "n_segments": n_segments, "rotation": 90 - (90 / (n_segments / 2)), "target_indices": (1, 10), "target_width": 4.0, "target_center": 6.0, "intensity_segments": (v1, v3), "intensity_background": v2, "intensity_target": v2, } stim = stimupy.whites.angular( visual_size=(24, 24), **params, ) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), ) return {**stim, **params}
[docs]def WE_radial_thin_small(ppd=PPD, pad=True): """Radial White stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1i. Circle size: 16x16 deg Number of segments: 26 Target length: 2 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Anstis, S. (2003). White's effect in brightness & color. Online Demonstration """ n_segments = 26 params = { "ppd": ppd, "n_segments": n_segments, "rotation": 90 - (90 / (n_segments / 2)), "target_indices": (1, 14), "target_width": 2.0, "target_center": 4.0, "intensity_segments": (v1, v3), "intensity_background": v2, "intensity_target": v2, } stim = stimupy.whites.angular( visual_size=(16, 16), **params, ) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), ) return {**stim, **params}
[docs]def WE_radial_thin(ppd=PPD, pad=True): """Radial White stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1j. Circle size: 24x24 deg Number of segments: 42 Target length: 2 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Anstis, S. (2003). White's effect in brightness & color. Online Demonstration """ n_segments = 42 params = { "ppd": ppd, "n_segments": n_segments, "rotation": 90 - (90 / (n_segments / 2)), "target_indices": (1, 22), "target_width": 2.0, "target_center": 6.0, "intensity_segments": (v1, v3), "intensity_background": v2, "intensity_target": v2, } stim = stimupy.whites.angular( visual_size=(24, 24), **params, ) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), ) return {**stim, **params}
[docs]def WE_circular1(ppd=PPD, pad=True): """Ring (or circular White) stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1k. Circle size: 16x16 deg Ring frequency: 0.5 cpd Ring width: 1 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Howe, P. D. L. (2005). White's effect: removing the junctions but preserving the strength of the illusion. Perception, 34, 557-564. """ height, width = 16.0, 16.0 params = { "ppd": ppd, "frequency": 8.0 / height, "target_indices": 5, "intensity_background": v2, "intensity_target": v2, "clip": True, } stim1 = stimupy.whites.radial( visual_size=(height, width), intensity_rings=(v1, v3), **params, ) stim2 = stimupy.whites.radial( visual_size=(height, width), intensity_rings=(v3, v1), **params, ) stim = stack_dicts(stim1, stim2) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), ) return {**stim, **params}
[docs]def WE_circular05(ppd=PPD, pad=True): """Ring (or circular White) stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1l. Circle size: 16x16 deg Ring frequency: 1 cpd Ring width: 0.5 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Howe, P. D. L. (2005). White's effect: removing the junctions but preserving the strength of the illusion. Perception, 34, 557-564. """ height, width = 16.0, 16.0 params = { "ppd": ppd, "frequency": 16.0 / height, "target_indices": 11, "intensity_background": v2, "intensity_target": v2, "clip": True, } stim1 = stimupy.whites.radial( visual_size=(height, width), intensity_rings=(v1, v3), **params, ) stim2 = stimupy.whites.radial( visual_size=(height, width), intensity_rings=(v3, v1), **params, ) stim = stack_dicts(stim1, stim2) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), ) return {**stim, **params}
[docs]def WE_circular025(ppd=PPD, pad=True): """Ring (or circular White) stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1m. Circle size: 16x16 deg Ring frequency: 2 cpd Ring width: 0.25 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Howe, P. D. L. (2005). White's effect: removing the junctions but preserving the strength of the illusion. Perception, 34, 557-564. """ height, width = 16.0, 16.0 params = { "ppd": ppd, "frequency": 32.0 / height, "target_indices": 23, "intensity_background": v2, "intensity_target": v2, "clip": True, } stim1 = stimupy.whites.radial( visual_size=(height, width), intensity_rings=(v1, v3), **params, ) stim2 = stimupy.whites.radial( visual_size=(height, width), intensity_rings=(v3, v1), **params, ) stim = stack_dicts(stim1, stim2) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), ) return {**stim, **params}
[docs]def grating_induction(ppd=PPD, pad=True): """Grating induction as shown in Robinson, Hammon, & de Sa (2007) Fig 1n. Circle size: 12x16 deg Grating frequency: 0.25 cpd Target size: 1x16 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (1999). A multiscale spatial filtering account of the White effect, simultaneous brightness contrast and grating induction. Vision Research, 39, 4361-4377. McCourt, M. E. (1982). A spatial frequency dependent grating-induction effect. Vision Research, 22, 119-134. https://doi.org/10.1016/0042-6989(82)90173-0 """ height, width = 12.0, 16.0 params = { "ppd": ppd, "frequency": 4.0 / width, "target_width": 1.0, "intensities": (0.0, 1.0), "intensity_target": (0.5), "period": "ignore", } stim = stimupy.gratings.grating_induction( visual_size=(height, width), **params, ) mask1 = np.where(stim["target_mask"] % 2, 1, 2) mask2 = np.where(stim["target_mask"] == 0, 0, 1) stim["target_mask"] = (mask1 * mask2).astype(int) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 6.23, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def sbc_large(ppd=PPD, pad=True): """Simultaneous brightness contrast as shown in Robinson, Hammon, & de Sa (2007) Fig 1o. Stimulus size: 13x31 deg Target sizes: 3x3 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (1999). A multiscale spatial filtering account of the White effect, simultaneous brightness contrast and grating induction. Vision Research, 39, 4361-4377. """ stim = stimupy.sbcs.basic_two_sided( visual_size=(13.0, 31.0), ppd=ppd, target_size=3.0, intensity_target=v2, intensity_background=(0.0, 1.0), ) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 11.35, } stim.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return stim
[docs]def sbc_small(ppd=PPD, pad=True): """Simultaneous brightness contrast as shown in Robinson, Hammon, & de Sa (2007) Fig 1p. Stimulus size: 13x31 deg Target sizes: 1x1 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (1999). A multiscale spatial filtering account of the White effect, simultaneous brightness contrast and grating induction. Vision Research, 39, 4361-4377. """ stim = stimupy.sbcs.basic_two_sided( visual_size=(13.0, 31.0), ppd=ppd, target_size=1.0, intensity_background=(0.0, 1.0), intensity_target=v2, ) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 19.78, } stim.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return stim
[docs]def todorovic_equal(ppd=PPD, pad=True): """Todorovic stimulus - equal as shown in Robinson, Hammon, & de Sa (2007) Fig 1q. Stimulus size: 13x31 deg Target size: 8x8 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (1999). A multiscale spatial filtering account of the White effect, simultaneous brightness contrast and grating induction. Vision Research, 39, 4361-4377. Pessoa, L., Baratoff, G., Neumann, H., & Todorovic, D. (1998). Lightness and junctions: variations on White's display. Investigative Ophthalmology and Visual Science (Supplement), 39, S159. """ params = { "visual_size": (13.0, 15.5), "ppd": ppd, "cross_size": 8.0, "cross_thickness": 1.6, "intensity_target": v2, } stim1 = stimupy.todorovics.equal( intensity_background=1.0, intensity_covers=0.0, **params, ) stim2 = stimupy.todorovics.equal( intensity_background=0.0, intensity_covers=1.0, **params, ) stim = stack_dicts(stim1, stim2) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 2.2, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def todorovic_in_large(ppd=PPD, pad=True): """Todorovic stimulus - in as shown in Robinson, Hammon, & de Sa (2007) Fig 1r. Stimulus size: 13x31 deg Target size: 5.3x5.3 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (1999). A multiscale spatial filtering account of the White effect, simultaneous brightness contrast and grating induction. Vision Research, 39, 4361-4377. Todorovic, D. (1997). Lightness and junctions. Perception, 26, 379-395. """ params = { "visual_size": (13.0, 15.5), "ppd": ppd, "target_size": 5.3125, "covers_size": 3.2, "covers_offset": 2.4, "intensity_target": v2, } stim1 = stimupy.todorovics.rectangle( intensity_background=1.0, intensity_covers=0.0, **params, ) stim2 = stimupy.todorovics.rectangle( intensity_background=0.0, intensity_covers=1.0, **params, ) stim = stack_dicts(stim1, stim2) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 2.4, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def todorovic_in_small(ppd=PPD, pad=True): """Todorovic stimulus - in as shown in Robinson, Hammon, & de Sa (2007) Fig 1s. Stimulus size: 13x31 deg Target size: 3x3 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (1999). A multiscale spatial filtering account of the White effect, simultaneous brightness contrast and grating induction. Vision Research, 39, 4361-4377. Todorovic, D. (1997). Lightness and junctions. Perception, 26, 379-395. """ params = { "visual_size": (13.0, 15.5), "ppd": ppd, "cross_size": 3.0, "cross_thickness": 1.6, "covers_size": 3.2, "intensity_target": v2, } stim1 = stimupy.todorovics.cross( intensity_background=1.0, intensity_covers=0.0, **params, ) stim2 = stimupy.todorovics.cross( intensity_background=0.0, intensity_covers=1.0, **params, ) stim = stack_dicts(stim1, stim2) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 4.4, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def todorovic_out(ppd=PPD, pad=True): """Todorovic stimulus - out as shown in Robinson, Hammon, & de Sa (2007) Fig 1t. Stimulus size: 13x31 deg Target size: 9.4x9.4 deg (note: in RHS2007, it says 8.7x8.7 deg, however that does not match with Fig 1t) Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (1999). A multiscale spatial filtering account of the White effect, simultaneous brightness contrast and grating induction. Vision Research, 39, 4361-4377. Pessoa, L., Baratoff, G., Neumann, H., & Todorovic, D. (1998). Lightness and junctions: variations on White's display. Investigative Ophthalmology and Visual Science (Supplement), 39, S159. """ params = { "visual_size": (13.0, 15.5), "ppd": ppd, "cross_size": 9.2, "cross_thickness": 1.6, "covers_size": 3.2, "intensity_target": v2, } stim1 = stimupy.todorovics.cross( intensity_background=1.0, intensity_covers=0.0, **params, ) stim2 = stimupy.todorovics.cross( intensity_background=0.0, intensity_covers=1.0, **params, ) stim = stack_dicts(stim1, stim2) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 1.53, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def checkerboard_016(ppd=PPD, pad=True): """Checkerboard stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1u. Stimulus size: 6.25x15.9375 deg Target size: 0.156x0.156 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (2004). A unified theory of brightness contrast and assimilation incorporating oriented multi-scale spatial filtering and contrast normalization. Vision Research, 44, 2483-2503. DeValois, R. L., & DeValois, K. K. (1988). Spatial vision. New York: Oxford University Press. """ nchecks_height, nchecks_width = 40, 102 target_row = nchecks_height // 2 params = { "ppd": ppd, "board_shape": (nchecks_height, nchecks_width), "check_visual_size": (5 / 32, 5 / 32), "target_indices": ((target_row, 16), (target_row, 85)), "extend_targets": False, "intensity_checks": (v3, v1), "intensity_target": v2, } stim = stimupy.checkerboards.checkerboard(**params) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 7.46, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def checkerboard_094(ppd=PPD, pad=True): """Checkerboard stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1v. Stimulus size: 6.5625x23.4375 deg Target size: 0.938x0.938 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (2004). A unified theory of brightness contrast and assimilation incorporating oriented multi-scale spatial filtering and contrast normalization. Vision Research, 44, 2483-2503. DeValois, R. L., & DeValois, K. K. (1988). Spatial vision. New York: Oxford University Press. """ nchecks_height, nchecks_width = 7, 25 target_row = nchecks_height // 2 params = { "ppd": ppd, "board_shape": (nchecks_height, nchecks_width), "check_visual_size": (30 / 32, 30 / 32), "target_indices": ((target_row, 6), (target_row, 17)), "extend_targets": False, "intensity_checks": (v1, v3), "intensity_target": v2, } stim = stimupy.checkerboards.checkerboard(**params) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 2.84, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def checkerboard_21(ppd=PPD, pad=True): """Checkerboard stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1w. Stimulus size: 6.28125x20.9375 deg Target size: 2.09x2.09 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (2004). A unified theory of brightness contrast and assimilation incorporating oriented multi-scale spatial filtering and contrast normalization. Vision Research, 44, 2483-2503. DeValois, R. L., & DeValois, K. K. (1988). Spatial vision. New York: Oxford University Press. """ nchecks_height, nchecks_width = 3, 10 target_row = nchecks_height // 2 params = { "ppd": ppd, "board_shape": (nchecks_height, nchecks_width), "check_visual_size": (67 / 32, 67 / 32), "target_indices": ((target_row, 2), (target_row, 7)), "extend_targets": False, "intensity_checks": (v1, v3), "intensity_target": v2, } stim = stimupy.checkerboards.checkerboard(**params) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 5.67, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def corrugated_mondrian(ppd=PPD, pad=True): """Corrugated Mondrians as shown in Robinson, Hammon, & de Sa (2007) Fig 1x. Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (2001). A multiscale spatial filtering account of the Wertheimer-Benary effect and the corrugated Mondrian. Vision Research, 41, 2487-2502. Adelson, E. H. (1993). Perceptual organization and the judgment of brightness. Science, 262, 2042-2044. https://doi.org/10.1126/science.8266102 """ v1, v2, v3, v4 = 0.0, 0.4, 0.75, 1.0 values = ( (v3, v2, v3, v2, v3), (v4, v3, v2, v3, v4), (v3, v2, v3, v2, v3), (v2, v1, v2, v1, v2), (v3, v2, v3, v2, v3), ) params = { "visual_size": (5 * 2, 5 * 2 + 1), "ppd": ppd, "depths": (0.0, -1.0, 0.0, 1.0, 0.0), "intensities": values, "target_indices": ((1, 2), (3, 2)), "intensity_background": 0.5, } stim = stimupy.mondrians.corrugated_mondrian(**params) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=0.5) experimental_data = { "effect_strength": 10.85, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v4), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def benary_cross(ppd=PPD, pad=True): """Benarys cross as shown in Robinson, Hammon, & de Sa (2007) Fig 1y. Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (2001). A multiscale spatial filtering account of the Wertheimer-Benary effect and the corrugated Mondrian. Vision Research, 41, 2487-2502. Benary, W. (1924). Beobachtungen zu einem Experiment über Helligkeitskontrast. Psychologische Forschung, 5, 131-142. https://doi.org/10.1007/BF00402398 """ params = { "ppd": ppd, "cross_thickness": 4.0, "target_size": 2.5, "intensity_background": v3, "intensity_cross": v1, "intensity_target": v2, } stim = stimupy.benarys.cross_triangles( visual_size=(13, 23), **params, ) stim = flip_dict(stim) # Switch target indices mask1 = np.where(stim["target_mask"] == 1, 1, 0) mask2 = np.where(stim["target_mask"] == 2, 1, 0) stim["target_mask"] = (mask1 * 2 + mask2).astype(int) if pad: stim = pad_dict_by_visual_size(stim, ((0.0, 0.0), (4.0, 4.0)), ppd, pad_value=v3) stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) experimental_data = { "effect_strength": 9.2, } params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), experimental_data=experimental_data, ) return {**stim, **params}
[docs]def todorovic_benary1_2(ppd=PPD, pad=True): """Todorovic variation of Benarys cross as shown in Robinson, Hammon, & de Sa (2007) Fig 1z. Only contains the first two targets (1-2). Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (2001). A multiscale spatial filtering account of the Wertheimer-Benary effect and the corrugated Mondrian. Vision Research, 41, 2487-2502. Todorovic, D. (1997). Lightness and junctions. Perception, 26, 379-395. """ # Generate full stim stim = todorovic_benary1_2_3_4(ppd=ppd, pad=pad) # Remove unused targets stim["img"] = np.where(stim["target_mask"] == 3, v3, stim["img"]) stim["img"] = np.where(stim["target_mask"] == 4, v1, stim["img"]) stim["target_mask"] = np.where(stim["target_mask"] > 2, 0, stim["target_mask"]) stim["target_type"] = stim["target_type"][:2] stim["target_rotation"] = stim["target_rotation"][:2] stim["target_x"] = stim["target_x"][:2] stim["target_y"] = stim["target_y"][:2] # Add experimental data stim["effect_strength"] = 11.96 return stim
[docs]def todorovic_benary3_4(ppd=PPD, pad=True): """Todorovic variation of Benarys cross as shown in Robinson, Hammon, & de Sa (2007) Fig 1z. Only contains the last two targets (3-4). Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (2001). A multiscale spatial filtering account of the Wertheimer-Benary effect and the corrugated Mondrian. Vision Research, 41, 2487-2502. Todorovic, D. (1997). Lightness and junctions. Perception, 26, 379-395. """ # Generate full stim stim = todorovic_benary1_2_3_4(ppd=ppd, pad=pad) # Remove unused targets stim["img"] = np.where(stim["target_mask"] == 1, v3, stim["img"]) stim["img"] = np.where(stim["target_mask"] == 2, v1, stim["img"]) stim["target_mask"] = np.where(stim["target_mask"] < 3, 0, stim["target_mask"]) stim["target_mask"] = np.where( stim["target_mask"], stim["target_mask"] - 2, stim["target_mask"] ) stim["target_type"] = stim["target_type"][2:] stim["target_rotation"] = stim["target_rotation"][2:] stim["target_x"] = stim["target_x"][2:] stim["target_y"] = stim["target_y"][2:] # Add experimental data stim["effect_strength"] = 9.55 return stim
[docs]def todorovic_benary1_2_3_4(ppd=PPD, pad=True): """Todorovic variation of Benarys cross as shown in Robinson, Hammon, & de Sa (2007) Fig 1z. Contains all four targets (1-2-3-4). Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Blakeslee, B., & McCourt, M. E. (2001). A multiscale spatial filtering account of the Wertheimer-Benary effect and the corrugated Mondrian. Vision Research, 41, 2487-2502. Todorovic, D. (1997). Lightness and junctions. Perception, 26, 379-395. """ params = { "ppd": ppd, "L_width": 2.5, "target_size": 2.5, "target_type": ("t", "t", "t", "t"), "target_rotation": (0.0, 45.0, 225.0, 180.0), "target_x": (2.5, 9.5, 18.0, 26.0), "target_y": (4.0, 6.5, 6.5 - np.sqrt(12.5) / 2.0 + 1 / ppd, 6.5), "intensity_background": v3, "intensity_cross": v1, "intensity_target": v2, } stim = stimupy.benarys.todorovic_generalized( visual_size=(13.0, 31.0), **params, ) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), ) return {**stim, **params}
[docs]def bullseye_thin(ppd=PPD, pad=True): """Bullseye stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1aa. Target size: 0.608x0.608 deg Ring widths: 0.122 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Bindman, D., & Chubb, C. (2004). Brightness assimilation in bullseye displays. Vision Research, 44, 309-319. https://doi.org/10.1016/S0042-6989(03)00430-9 """ radii = np.array([0.304, 0.426, 0.548, 0.670, 0.792]) params = { "visual_size": 0.792 * 2, "ppd": ppd, "radii": radii, "intensity_target": v2, "origin": "mean", } stim1 = stimupy.bullseyes.rectangular_generalized( **params, intensity_frames=(v1, v3), ) stim2 = stimupy.bullseyes.rectangular_generalized( **params, intensity_frames=(v3, v1), ) # Individual padding if pad: stim1 = pad_dict_to_visual_size(stim1, np.array(VISEXTENT) / 2, ppd, pad_value=v2) stim2 = pad_dict_to_visual_size(stim2, np.array(VISEXTENT) / 2, ppd, pad_value=v2) stim = stack_dicts(stim1, stim2) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), ) return {**stim, **params}
[docs]def bullseye_thick(ppd=PPD, pad=True): """Bullseye stimulus as shown in Robinson, Hammon, & de Sa (2007) Fig 1bb. Target size: 0.608x0.608 deg Ring widths: 0.243 deg Parameters ---------- ppd : int Resolution of stimulus in pixels per degree. (default: 32) pad : bool If True, include padding to 32x32 deg (default: True) Returns ------- dict of str dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Bindman, D., & Chubb, C. (2004). Brightness assimilation in bullseye displays. Vision Research, 44, 309-319. https://doi.org/10.1016/S0042-6989(03)00430-9 """ radii = np.array([0.304, 0.547, 0.790, 1.033, 1.276]) params = { "visual_size": 1.276 * 2, "ppd": ppd, "radii": radii, "intensity_target": v2, "origin": "mean", } stim1 = stimupy.bullseyes.rectangular_generalized( **params, intensity_frames=(v1, v3), ) stim2 = stimupy.bullseyes.rectangular_generalized( **params, intensity_frames=(v3, v1), ) # Individual padding if pad: stim1 = pad_dict_to_visual_size(stim1, np.array(VISEXTENT) / 2, ppd, pad_value=v2) stim2 = pad_dict_to_visual_size(stim2, np.array(VISEXTENT) / 2, ppd, pad_value=v2) stim = stack_dicts(stim1, stim2) if pad: stim = pad_dict_to_visual_size(stim, VISEXTENT, ppd, pad_value=v2) params.update( visual_size=np.array(stim["img"].shape) / ppd, shape=stim["img"].shape, intensity_range=(v1, v3), ) return {**stim, **params}
if __name__ == "__main__": from stimupy.utils import plot_stimuli stims = gen_all(pad=True, skip=True) plot_stimuli(stims, mask=True)