Source code for stimupy.papers.domijan2015

"""Stimuli from Domijan (2015) https://doi.org/10.3389/fnhum.2015.00093

This module reproduces all of the stimuli used by Domijan (2015)
as they were provided to the model described in that paper.
Since the stimulus sizes were only defined in pixel-space,
there is some ambiguity with respect to the stimulus sizes in
degrees visual angle.
To help solve this ambiguity, we approximated a realistic resolution
of the stimuli (ppd = 10) which is set as default value.
However, because of the ambiguity, it is possible to change the
stimulus sizes by providing at least two of the following: a shape
(in pixels), a visual_size (in degrees) and/or a resolution (in ppd).

Each stimulus is provided by a separate function,
a full list can be found as stimupy.papers.domijan2015.__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/domijan2015.py

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

References
-----------
Domijan, D. (2015).
    A neurocomputational account
    of the role of contour facilitation in brightness perception.
    Frontiers in Human Neuroscience, 9, 93.
    https://doi.org/10.3389/fnhum.2015.00093
"""

import numpy as np

import stimupy
from stimupy.utils import pad_dict_by_visual_size, pad_dict_to_shape, resolution, stack_dicts

__all__ = [
    "dungeon",
    "cube",
    "grating",
    "rings",
    "bullseye",
    "simultaneous_brightness_contrast",
    "white",
    "benary",
    "todorovic",
    "checkerboard_contrast_contrast",
    "checkerboard",
    "checkerboard_extended",
    "white_yazdanbakhsh",
    "white_anderson",
    "white_howe",
]

# Default values:
PPD = 10
PAD = True
SHAPES = {
    "dungeon": (110, 220),
    "cube": (100, 200),
    "grating": (100, 220),
    "rings": (100, 200),
    "bullseye": (100, 200),
    "simultaneous_brightness_contrast": (100, 200),
    "white": (80, 80),
    "benary": (100, 100),
    "todorovic": (100, 200),
    "checkerboard_contrast_contrast": (80, 160),
    "checkerboard": (80, 80),
    "checkerboard_extended": (80, 80),
    "white_yazdanbakhsh": (80, 80),
    "white_anderson": (100, 100),
    "white_howe": (100, 100),
}

VSIZES = {
    "dungeon": resolution.visual_size_from_shape_ppd(shape=SHAPES["dungeon"], ppd=PPD),
    "cube": resolution.visual_size_from_shape_ppd(shape=SHAPES["cube"], ppd=PPD),
    "grating": resolution.visual_size_from_shape_ppd(shape=SHAPES["grating"], ppd=PPD),
    "rings": resolution.visual_size_from_shape_ppd(shape=SHAPES["rings"], ppd=PPD),
    "bullseye": resolution.visual_size_from_shape_ppd(shape=SHAPES["bullseye"], ppd=PPD),
    "simultaneous_brightness_contrast": resolution.visual_size_from_shape_ppd(
        shape=SHAPES["simultaneous_brightness_contrast"], ppd=PPD
    ),
    "white": resolution.visual_size_from_shape_ppd(shape=SHAPES["white"], ppd=PPD),
    "benary": resolution.visual_size_from_shape_ppd(shape=SHAPES["benary"], ppd=PPD),
    "todorovic": resolution.visual_size_from_shape_ppd(shape=SHAPES["todorovic"], ppd=PPD),
    "checkerboard_contrast_contrast": resolution.visual_size_from_shape_ppd(
        shape=SHAPES["checkerboard_contrast_contrast"], ppd=PPD
    ),
    "checkerboard": resolution.visual_size_from_shape_ppd(shape=SHAPES["checkerboard"], ppd=PPD),
    "checkerboard_extended": resolution.visual_size_from_shape_ppd(
        shape=SHAPES["checkerboard_extended"], ppd=PPD
    ),
    "white_yazdanbakhsh": resolution.visual_size_from_shape_ppd(
        shape=SHAPES["white_yazdanbakhsh"], ppd=PPD
    ),
    "white_anderson": resolution.visual_size_from_shape_ppd(
        shape=SHAPES["white_anderson"], ppd=PPD
    ),
    "white_howe": resolution.visual_size_from_shape_ppd(shape=SHAPES["white_howe"], ppd=PPD),
}

v1, v2, v3 = 0.0, 0.5, 1.0


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

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

            # 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


def resolve(shape, visual_size, ppd, original_visual_size):
    # Put in canonical form
    shape = resolution.validate_shape(shape)
    visual_size = resolution.validate_visual_size(visual_size)
    ppd = resolution.validate_ppd(ppd)

    # Try to resolve height; get resizing_factor from that
    try:
        _, visual_angle, ppd1 = resolution.resolve_1D(
            length=shape.height, visual_angle=visual_size.height, ppd=ppd.vertical
        )
        v1 = visual_angle / original_visual_size[0]
    except Exception:
        v1 = None
        ppd1 = None

    # Try to resolve width; get resizing_factor from that
    try:
        _, visual_angle, ppd2 = resolution.resolve_1D(
            length=shape.width, visual_angle=visual_size.width, ppd=ppd.horizontal
        )
        v2 = visual_angle / original_visual_size[1]
    except Exception:
        v2 = None
        ppd2 = None

    # Same resizing factor?
    visual_resize = [i for i in (v1, v2) if i is not None]
    visual_resize = np.unique(visual_resize)
    if len(visual_resize) != 1:
        # Different resizing factors -> not allowed
        raise ValueError(
            "Requested shape/visual_size is impossible given the stimulus defaults. "
            "Consider setting either the height or width to None"
        )
    else:
        # Same factor, resolve resolution using that
        visual_resize = visual_resize[0]
        ppd = np.unique([i for i in (ppd1, ppd2) if i is not None])
        shape, visual_size, ppd = resolution.resolve(
            shape, np.array(original_visual_size) * visual_resize, ppd
        )

    if ppd[0] % 2 != 0:
        raise ValueError("use an even ppd for domijan2015-stimuli")

    return shape, visual_size, ppd, visual_resize


[docs]def dungeon(visual_size=VSIZES["dungeon"], ppd=PPD, shape=SHAPES["dungeon"]): """Dungeon illusion, Domijan (2015) Fig 6A Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (11, 22) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (110, 220) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve(shape, visual_size, ppd, VSIZES["dungeon"]) ppd = ppd[0] # Define parameters for each side params = { "ppd": ppd, "n_cells": 5, "target_radius": 1, "cell_size": 1.0 * visual_resize, } # Generate each side stim1 = stimupy.dungeons.dungeon( **params, intensity_background=v1, intensity_grid=v3, intensity_target=v2, ) stim2 = stimupy.dungeons.dungeon( **params, intensity_background=v3, intensity_grid=v1, intensity_target=v2, ) # Pad and stack padding = np.array((0.9, 1.1)) * visual_resize stim1 = pad_dict_by_visual_size(stim1, padding, ppd, v1) stim2 = pad_dict_by_visual_size(stim2, padding, ppd, v3) stim = stack_dicts(stim1, stim2) params.update( original_shape=SHAPES["dungeon"], original_ppd=PPD, original_visual_size=VSIZES["dungeon"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
[docs]def cube(visual_size=VSIZES["cube"], ppd=PPD, shape=SHAPES["cube"]): """Cube illusion, Domijan (2015) Fig 6B Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (10, 20) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (100, 200) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve(shape, visual_size, ppd, VSIZES["cube"]) ppd = ppd[0] params = { "ppd": ppd, "cell_thickness": 1.1 * visual_resize, "cell_lengths": np.array([1.8, 1.5, 1.5, 1.8]) * visual_resize, "target_indices": (1, 2), "cell_spacing": 0.5 * visual_resize, } stim1 = stimupy.cubes.varying_cells( **params, intensity_background=v1, intensity_cells=v3, intensity_target=v2, ) stim2 = stimupy.cubes.varying_cells( **params, intensity_background=v3, intensity_cells=v1, intensity_target=v2, ) # Pad and stack padding = np.array((0.9, 1.0)) * visual_resize stim1 = pad_dict_by_visual_size(stim1, padding, ppd, v1) stim2 = pad_dict_by_visual_size(stim2, padding, ppd, v3) stim = stack_dicts(stim1, stim2) params.update( original_shape=SHAPES["cube"], original_ppd=PPD, original_visual_size=VSIZES["cube"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
[docs]def grating(visual_size=VSIZES["grating"], ppd=PPD, shape=SHAPES["grating"]): """Grating illusion, Domijan (2015) Fig 6C Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (10, 22) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (100, 220) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve(shape, visual_size, ppd, VSIZES["grating"]) visual_size_without_padding = ( visual_size.height - ((0.9 + 1.0) * visual_resize), visual_size.width - (2 * (0.9 + 1.1) * visual_resize), ) single_vissize = (visual_size_without_padding[0], visual_size_without_padding[1] / 2) params = { "visual_size": single_vissize, "ppd": ppd, "n_bars": 9, "target_indices": (5,), "bar_width": 1.0 * visual_resize, } stim1 = stimupy.waves.square_linear( **params, intensity_bars=(v1, v3), intensity_target=v2, ) stim2 = stimupy.waves.square_linear( **params, intensity_bars=(v3, v1), intensity_target=v2, ) # Pad and stack padding = np.array(((0.9, 1.0), (0.9, 1.1))) * visual_resize stim1 = pad_dict_by_visual_size(stim1, padding, ppd, v1) stim2 = pad_dict_by_visual_size(stim2, padding, ppd, v3) stim = stack_dicts(stim1, stim2) params.update( original_shape=SHAPES["grating"], original_ppd=PPD, original_visual_size=VSIZES["grating"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
[docs]def rings(visual_size=VSIZES["rings"], ppd=PPD, shape=SHAPES["rings"]): """Ring patterns, Domijan (2015) Fig 7A Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (10, 20) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (100, 200) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve(shape, visual_size, ppd, VSIZES["rings"]) radii = np.array((0.55, 1.05, 1.55, 2.05, 2.55, 3.05, 3.55, 4.05)) * visual_resize params = { "visual_size": radii.max() * 2, "ppd": ppd, "radii": radii, "origin": "mean", } stim1 = stimupy.rings.rectangular_generalized( **params, target_indices=5, intensity_frames=(v1, v3), intensity_target=v2, ) stim2 = stimupy.rings.rectangular_generalized( **params, target_indices=4, intensity_frames=(v1, v3), intensity_target=v2, ) # Pad and stack stim1 = pad_dict_to_shape(stim1, shape=np.array(shape) / (1, 2), pad_value=v1) stim2 = pad_dict_to_shape(stim2, shape=np.array(shape) / (1, 2), pad_value=v1) stim = stack_dicts(stim1, stim2) params.update( original_shape=SHAPES["rings"], original_ppd=PPD, original_visual_size=VSIZES["rings"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
[docs]def bullseye(visual_size=VSIZES["bullseye"], ppd=PPD, shape=SHAPES["bullseye"]): """Bullseye illusion, Domijan (2015) Fig 7B Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (10, 20) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (100, 200) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve(shape, visual_size, ppd, VSIZES["bullseye"]) radii = np.array((0.55, 1.05, 1.55, 2.05, 2.55, 3.05, 3.55, 4.05)) * visual_resize params = { "visual_size": radii.max() * 2, "ppd": ppd, "radii": radii, "origin": "mean", } stim1 = stimupy.bullseyes.rectangular_generalized( **params, intensity_frames=(v1, v3), intensity_target=v2, ) stim2 = stimupy.bullseyes.rectangular_generalized( **params, intensity_frames=(v3, v1), intensity_target=v2, ) # Pad and stack stim1 = pad_dict_to_shape(stim1, shape=np.array(shape) / (1, 2), pad_value=v1) stim2 = pad_dict_to_shape(stim2, shape=np.array(shape) / (1, 2), pad_value=v1) stim = stack_dicts(stim1, stim2) params.update( original_shape=SHAPES["bullseye"], original_ppd=PPD, original_visual_size=VSIZES["bullseye"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
[docs]def simultaneous_brightness_contrast( visual_size=VSIZES["simultaneous_brightness_contrast"], ppd=PPD, shape=SHAPES["simultaneous_brightness_contrast"], ): """Simultaneous brightness contrast, Domijan (2015) Fig 7C Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (10, 20) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (100, 200) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve( shape, visual_size, ppd, VSIZES["simultaneous_brightness_contrast"] ) stim = stimupy.sbcs.generalized_two_sided( visual_size=visual_size, ppd=ppd, target_size=(2.1 * visual_resize, 2.1 * visual_resize), target_position=(3.8 * visual_resize, 3.8 * visual_resize), intensity_background=(v3, v1), intensity_target=v2, ) stim.update( original_shape=SHAPES["simultaneous_brightness_contrast"], original_ppd=PPD, original_visual_size=VSIZES["simultaneous_brightness_contrast"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return stim
[docs]def white(visual_size=VSIZES["white"], ppd=PPD, pad=PAD, shape=SHAPES["white"]): """White stimulus, Domijan (2015) Fig 8A Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (8, 8) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (80, 80) pad : bool If True, include original padding (default: False) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve(shape, visual_size, ppd, VSIZES["white"]) ppd = ppd[0] params = { "visual_size": visual_size, "ppd": ppd, "frequency": 4.0 / visual_size[1], "target_indices": (3, 6), "target_heights": 2.1 * visual_resize, "period": "even", } stim = stimupy.whites.white( **params, intensity_bars=(v3, v1), intensity_target=v2, ) if pad: padding = np.array((0.9, 1.1)) * visual_resize stim = pad_dict_by_visual_size(stim, padding, ppd, pad_value=v2) params["padding"] = padding original_shape_np = SHAPES["white"] original_shape = np.array(original_shape_np) + 20 original_visual_size = resolution.visual_size_from_shape_ppd(original_shape, PPD) params.update( original_shape=original_shape, original_ppd=PPD, original_visual_size=original_visual_size, original_shape_no_padding=original_shape_np, original_visual_size_no_padding=VSIZES["white"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
[docs]def benary(visual_size=VSIZES["benary"], ppd=PPD, shape=SHAPES["benary"]): """Benarys cross, Domijan (2015) Fig 8B Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (10, 10) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (100, 100) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve(shape, visual_size, ppd, VSIZES["benary"]) ppd = ppd[0] params = { "visual_size": 8.1 * visual_resize, "ppd": ppd, "cross_thickness": 2.1 * visual_resize, "target_size": 1.1 * visual_resize, } stim = stimupy.benarys.cross_rectangles( **params, intensity_background=v3, intensity_cross=v1, intensity_target=v2, ) # Padding padding = np.array((0.9, 1.0)) * visual_resize stim = pad_dict_by_visual_size(stim, padding, ppd, pad_value=v3) params.update( original_shape=SHAPES["benary"], original_ppd=PPD, original_visual_size=VSIZES["benary"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
[docs]def todorovic(visual_size=VSIZES["todorovic"], ppd=PPD, shape=SHAPES["todorovic"]): """Todorovic stimulus, Domijan (2015) Fig 9A Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (10, 20) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (100, 200) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Note: Compared to original, targets are moved by one pixel # Resolve resolution shape, visual_size, ppd, visual_resize = resolve(shape, visual_size, ppd, VSIZES["todorovic"]) ppd = ppd[0] params = { "visual_size": visual_size[0], "ppd": ppd, "target_size": 4.1 * visual_resize, "target_position": 2.8 * visual_resize, "covers_size": 3.1 * visual_resize, "covers_offset": 2.0 * visual_resize, } stim1 = stimupy.todorovics.rectangle( **params, intensity_background=0.0, intensity_target=0.5, intensity_covers=1.0, ) stim2 = stimupy.todorovics.rectangle( **params, intensity_background=1.0, intensity_target=0.5, intensity_covers=0.0, ) # Stacking stim = stack_dicts(stim1, stim2) params.update( original_shape=SHAPES["todorovic"], original_ppd=PPD, original_visual_size=VSIZES["todorovic"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
[docs]def checkerboard_contrast_contrast( visual_size=VSIZES["checkerboard_contrast_contrast"], ppd=PPD, shape=SHAPES["checkerboard_contrast_contrast"], pad=PAD, ): """Checkerboard contrast-contrast effect, Domijan (2015) Fig 9B Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (8, 16) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (80, 160) pad : bool If True, include original padding (default: False) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve( shape, visual_size, ppd, VSIZES["checkerboard_contrast_contrast"] ) params = { "ppd": ppd, "check_visual_size": 1.0 * visual_resize, "target_shape": (4, 4), "tau": 0.5, "alpha": 0.5, "intensity_checks": (v1, v3), } # Large checkerboard, embedded target region stim1 = stimupy.checkerboards.contrast_contrast( **params, board_shape=(8, 8), ) # Isolated target region (smaller checkerboard) stim2 = stimupy.checkerboards.contrast_contrast( **params, board_shape=(4, 4), ) # Put smaller checkerboard on background (equally large as large checkerboard) stim2 = pad_dict_to_shape(stim2, stim1["img"].shape, pad_value=v2) # Overall padding if pad: padding = np.array((0.9, 1.1)) * visual_resize stim1 = pad_dict_by_visual_size(stim1, padding, ppd=ppd, pad_value=v2) stim2 = pad_dict_by_visual_size(stim2, padding, ppd=ppd, pad_value=v2) params["padding"] = padding # Stacking stim = stack_dicts(stim1, stim2) # Output original_shape_np = np.array(SHAPES["checkerboard_contrast_contrast"]) original_shape = original_shape_np + np.array((20, 40)) original_visual_size = resolution.visual_size_from_shape_ppd(original_shape, PPD) params.update( original_shape=original_shape, original_ppd=PPD, original_visual_size=original_visual_size, original_shape_no_padding=original_shape_np, original_visual_size_no_padding=VSIZES["checkerboard_contrast_contrast"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, board_shape_left=(8, 8), board_shape_right=(4, 4), ) return {**stim, **params}
[docs]def checkerboard( visual_size=VSIZES["checkerboard"], ppd=PPD, shape=SHAPES["checkerboard"], pad=PAD ): """Classic checkerboard contrast with single-check targets, Domijan (2015) Fig 10A Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (8, 8) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (80, 80) pad : bool If True, include original padding (default: False) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve( shape, visual_size, ppd, VSIZES["checkerboard"] ) params = { "ppd": ppd, "board_shape": (8, 8), "check_visual_size": (1.0 * visual_resize, 1.0 * visual_resize), "target_indices": [(3, 2), (5, 5)], "extend_targets": False, "intensity_checks": (v1, v3), "intensity_target": v2, } stim = stimupy.checkerboards.checkerboard(**params) if pad: padding = np.array((0.9, 1.1)) * visual_resize stim = pad_dict_by_visual_size(stim, padding, ppd=ppd, pad_value=v2) params["padding"] = padding original_shape_np = SHAPES["checkerboard"] original_shape = np.array(original_shape_np) + 20 original_visual_size = resolution.visual_size_from_shape_ppd(original_shape, PPD) params.update( original_shape=original_shape, original_ppd=PPD, original_visual_size=original_visual_size, original_shape_no_padding=original_shape_np, original_visual_size_no_padding=VSIZES["checkerboard"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
[docs]def checkerboard_extended( visual_size=VSIZES["checkerboard_extended"], ppd=PPD, shape=SHAPES["checkerboard_extended"], pad=PAD, ): """Checkerboard contrast with cross-like targets, Domijan (2015) Fig 10B Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (8, 8) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (80, 80) pad : bool If True, include original padding (default: False) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve( shape, visual_size, ppd, VSIZES["checkerboard_extended"] ) params = { "ppd": ppd, "board_shape": (8, 8), "check_visual_size": (1.0 * visual_resize, 1.0 * visual_resize), "target_indices": [(3, 2), (5, 5)], "extend_targets": True, "intensity_checks": (v1, v3), "intensity_target": v2, } stim = stimupy.checkerboards.checkerboard(**params) if pad: padding = np.array((0.9, 1.1)) * visual_resize stim = pad_dict_by_visual_size(stim, padding, ppd=ppd, pad_value=v2) params["padding"] = padding original_shape_np = SHAPES["checkerboard_extended"] original_shape = np.array(original_shape_np) + 20 original_visual_size = resolution.visual_size_from_shape_ppd(original_shape, PPD) params.update( original_shape=original_shape, original_ppd=PPD, original_visual_size=original_visual_size, original_shape_no_padding=original_shape_np, original_visual_size_no_padding=VSIZES["checkerboard_extended"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
[docs]def white_yazdanbakhsh( visual_size=VSIZES["white_yazdanbakhsh"], ppd=PPD, shape=SHAPES["white_yazdanbakhsh"], pad=PAD ): """Yazdanbakhsh variation of White stimulus, Domijan (2015) Fig 11A Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (8, 8) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (80, 80) pad : bool If True, include original padding (default: False) Returns ------- dict[str, Any] dict with the stimulus (key: "img") and target mask (key: "target_mask") and additional keys containing stimulus parameters References ---------- Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 Yazdanbakhsh, A., Arabzadeh, E., Babadi, B., and Fazl, A. (2002). Munker-White-like illusions without T-junctions. Perception 31, 711-715. https://doi.org/10.1068/p3348 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve( shape, visual_size, ppd, VSIZES["white_yazdanbakhsh"] ) ppd = ppd[0] params = { "visual_size": visual_size, "ppd": ppd, "frequency": 4.0 / visual_size[1], "target_indices_top": (3,), "target_indices_bottom": (6,), "target_center_offset": 0.0, "target_heights": visual_size[0] / 4.0, "gap_size": visual_size[0] / 10.0, "period": "even", } stim = stimupy.whites.yazdanbakhsh( **params, intensity_bars=(v3, v1), intensity_target=v2, ) if pad: padding = np.array((0.9, 1.1)) * visual_resize stim = pad_dict_by_visual_size(stim, padding, ppd=ppd, pad_value=v2) params["padding"] = padding original_shape_np = SHAPES["white_yazdanbakhsh"] original_shape = np.array(original_shape_np) + 20 original_visual_size = resolution.visual_size_from_shape_ppd(original_shape, PPD) params.update( original_shape=original_shape, original_ppd=PPD, original_visual_size=original_visual_size, original_shape_no_padding=original_shape_np, original_visual_size_no_padding=VSIZES["white_yazdanbakhsh"], original_range=(1, 9), intensity_range=(v3, v1), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
[docs]def white_anderson( visual_size=VSIZES["white_anderson"], ppd=PPD, shape=SHAPES["white_anderson"], pad=PAD ): """Anderson variation of White stimulus, Domijan (2015) Fig 11B Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (10, 10) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (100, 100) pad : bool If True, include original padding (default: False) Returns ------- dict[str, Any] 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. Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve( shape, visual_size, ppd, VSIZES["white_anderson"] ) ppd = ppd[0] params = { "visual_size": visual_size, "ppd": ppd, "frequency": 5.0 / visual_size[1], "target_indices_top": (3,), "target_indices_bottom": (8,), "target_center_offset": visual_size[0] / 10.0, "target_height": visual_size[0] / 5.0, "stripe_center_offset": visual_size[0] / 5.0, "stripe_height": visual_size[0] / 5.0, "period": "even", } stim = stimupy.whites.anderson( **params, intensity_bars=(v1, v3), intensity_target=v2, intensity_stripes=(v1, v3), ) if pad: padding = np.array((0.9, 1.1)) * visual_resize stim = pad_dict_by_visual_size(stim, padding, ppd=ppd, pad_value=v2) params["padding"] = padding original_shape_np = SHAPES["white_anderson"] original_shape = np.array(original_shape_np) + 20 original_visual_size = resolution.visual_size_from_shape_ppd(original_shape, PPD) params.update( original_shape=original_shape, original_ppd=PPD, original_visual_size=original_visual_size, original_shape_no_padding=original_shape_np, original_visual_size_no_padding=VSIZES["white_anderson"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
[docs]def white_howe(visual_size=VSIZES["white_howe"], ppd=PPD, shape=SHAPES["white_howe"], pad=PAD): """Howe variation of White stimulus, Domijan (2015) Fig 11C Parameters ---------- visual_size : Sequence[Number, Number], Number, or None visual size [height, width] in degrees, default: (10, 10) ppd : Sequence[Number, Number], Number, or None pixels per degree [vertical, horizontal], default: 10 shape : Sequence[Number, Number], Number, or None shape [height, width] in pixels, default: (100, 100) pad : bool If True, include original padding (default: False) Returns ------- dict[str, Any] 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. Domijan, D. (2015). A neurocomputational account of the role of contour facilitation in brightness perception. Frontiers in Human Neuroscience, 9, 93. https://doi.org/10.3389/fnhum.2015.00093 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 """ # Resolve resolution shape, visual_size, ppd, visual_resize = resolve(shape, visual_size, ppd, VSIZES["white_howe"]) ppd = ppd[0] params = { "visual_size": visual_size, "ppd": ppd, "frequency": 5.0 / visual_size[1], "target_indices_top": (3,), "target_indices_bottom": (8,), "target_center_offset": visual_size[0] / 5.0, "target_height": visual_size[0] / 5.0, "period": "even", } stim = stimupy.whites.howe( **params, intensity_bars=(v1, v3), intensity_target=v2, intensity_stripes=(v1, v3), ) if pad: padding = np.array((0.9, 1.1)) * visual_resize stim = pad_dict_by_visual_size(stim, padding, ppd=ppd, pad_value=v2) params["padding"] = padding original_shape_np = SHAPES["white_howe"] original_shape = np.array(original_shape_np) + 20 original_visual_size = resolution.visual_size_from_shape_ppd(original_shape, PPD) params.update( original_shape=original_shape, original_ppd=PPD, original_visual_size=original_visual_size, original_shape_no_padding=original_shape_np, original_visual_size_no_padding=VSIZES["white_howe"], original_range=(1, 9), intensity_range=(v1, v3), visual_size=resolution.visual_size_from_shape_ppd(stim["img"].shape, ppd), shape=stim["img"].shape, ) return {**stim, **params}
if __name__ == "__main__": from stimupy.utils import plot_stimuli stims = gen_all(skip=True) plot_stimuli(stims, mask=False)