From f1808793cef59be185504c05bd4a5762d63a2998 Mon Sep 17 00:00:00 2001 From: lynnschmittwilken Date: Tue, 20 Dec 2022 23:53:12 +0100 Subject: [PATCH] closes #76, closes #79; created utils-contrat-conversions and added contrast changing functions including transparancy --- stimuli/components/shapes.py | 22 ---- stimuli/illusions/checkerboards.py | 9 +- stimuli/utils/contrast_conversions.py | 147 ++++++++++++++++++++++++++ stimuli/utils/utils.py | 8 -- 4 files changed, 149 insertions(+), 37 deletions(-) create mode 100644 stimuli/utils/contrast_conversions.py diff --git a/stimuli/components/shapes.py b/stimuli/components/shapes.py index 2a2f6e00..37280e54 100644 --- a/stimuli/components/shapes.py +++ b/stimuli/components/shapes.py @@ -327,25 +327,3 @@ def parallelogram( "intensity_background": intensity_background, "intensity_parallelogram": intensity_parallelogram, } - - -def transparency(img, mask, alpha=0.5, tau=0.2): - """Applies a transparency layer to given image at specified (mask) location - - Parameters - ---------- - img : numpy.ndarray - 2D image array that transparency should be applied to - mask : numpy.ndarray - 2D binary array indicating which pixels to apply transparency to - tau : Number - tau of transparency (i.e. value of transparent medium), default 0.5 - alpha : Number - alpha of transparency (i.e. how transparant the medium is), default 0.2 - - Returns - ------- - numpy.ndarray - img, with the transparency applied to the masked region - """ - return np.where(mask, alpha * img + (1 - alpha) * tau, img) diff --git a/stimuli/illusions/checkerboards.py b/stimuli/illusions/checkerboards.py index aa0c0d70..ce905125 100644 --- a/stimuli/illusions/checkerboards.py +++ b/stimuli/illusions/checkerboards.py @@ -1,7 +1,7 @@ import numpy as np from stimuli.components.checkerboard import checkerboard as board -from stimuli.components.shapes import transparency +from stimuli.utils.contrast_conversions import transparency from stimuli.utils import resolution __all__ = [ @@ -297,14 +297,9 @@ def contrast_contrast( mask[target_idx] = 1 # Apply transparency to target locations - img = transparency(img, mask, alpha, tau) - - # Update stim dict stim["img"] = img stim["mask"] = mask.astype(int) - stim["alpha"] = alpha - stim["tau"] = tau - + stim = transparency(stim, alpha, tau) return stim diff --git a/stimuli/utils/contrast_conversions.py b/stimuli/utils/contrast_conversions.py new file mode 100644 index 00000000..1bea0f87 --- /dev/null +++ b/stimuli/utils/contrast_conversions.py @@ -0,0 +1,147 @@ +import numpy as np + + +def transparency(stim, alpha=0.5, tau=0.2): + """Applies a transparency layer to given image at specified (mask) location + + Parameters + ---------- + stim : dict + stimulus dictionary containing at least keys "img" and "mask" + tau : Number + tau of transparency (i.e. value of transparent medium), default 0.5 + alpha : Number + alpha of transparency (i.e. how transparant the medium is), default 0.2 + + Returns + ------- + Updated stimulus dict with keys "img", "tau" and "alpha"; + img, with the transparency applied to the masked region + """ + img = np.where(stim["mask"], alpha * stim["img"] + (1 - alpha) * tau, stim["img"]) + + stim["img"] = img + stim["tau"] = tau + stim["alpha"] = alpha + return stim + + +def adapt_michelson_contrast(stim, michelson_contrast, mean_luminance=None): + """ + Adapt Michelson contrast of image + + Parameters + ---------- + stim : dict + stimulus dictionary containing at least keys "img" and "mask" + michelson_contrast : float + desired Michelson contrast + mean_luminance : float + desired mean luminance; if None (default), dont change mean luminance + + Returns + ------- + Updated stimulus dict with keys "img", "michelson_contrast" and "mean_luminance" + + """ + if mean_luminance is None: + mean_luminance = stim["img"].mean() + + # Adapt Michelson contrast + img = (stim["img"] - stim["img"].min()) / (stim["img"].max() - stim["img"].min()) + img = (img * michelson_contrast * 2.0 * mean_luminance) + img += mean_luminance - michelson_contrast * mean_luminance + + stim["img"] = img + stim["michelson_contrast"] = michelson_contrast + stim["mean_luminance"] = mean_luminance + return stim + + +def adapt_rms_contrast(stim, rms_contrast, mean_luminance=None): + """ + Adapt rms contrast of image (std) + + Parameters + ---------- + stim : dict + stimulus dictionary containing at least keys "img" and "mask" + rms_contrast : float + desired rms contrast (std divided by mean intensity) + mean_luminance : float + desired mean luminance; if None (default), dont change mean luminance + + Returns + ------- + Updated stimulus dict with keys "img", "rms_contrast" and "mean_luminance" + + """ + if mean_luminance is None: + mean_luminance = stim["img"].mean() + + img = stim["img"] - stim["img"].mean() + img = img / img.std() * rms_contrast + mean_luminance + + stim["img"] = img + stim["rms_contrast"] = rms_contrast + stim["mean_luminance"] = mean_luminance + return stim + + +def adapt_normalized_rms_contrast(stim, rms_contrast, mean_luminance=None): + """ + Adapt normalized rms contrast of image (std divided by mean) + + Parameters + ---------- + stim : dict + stimulus dictionary containing at least keys "img" + rms_contrast : float + desired rms contrast (std divided by mean intensity) + mean_luminance : float + desired mean luminance; if None (default), dont change mean luminance + + Returns + ------- + Updated stimulus dict with keys "img", "rms_contrast" and "mean_luminance" + + """ + if mean_luminance is None: + mean_luminance = stim["img"].mean() + + img = stim["img"] - stim["img"].mean() + img = img / img.std() * rms_contrast*mean_luminance + mean_luminance + + stim["img"] = img + stim["rms_contrast"] = rms_contrast + stim["mean_luminance"] = mean_luminance + return stim + + +def adapt_intensity_range(stim, intensity_min=0., intensity_max=1.): + """ + Adapt intensity range of image + + Parameters + ---------- + stim : dict + stimulus dictionary containing at least keys "img" + intensity_min : float + new minimal intensity value + intensity_max : float + new maximal intensity value + + Returns + ------- + Updated stimulus dict with keys "img", "intensity_min" and "intensity_max" + + """ + + img = (stim["img"] - stim["img"].min()) / (stim["img"].max() - stim["img"].min()) + img = img * (intensity_max - intensity_min) + intensity_min + + stim["img"] = img + stim["intensity_min"] = intensity_min + stim["intensity_max"] = intensity_max + return stim + diff --git a/stimuli/utils/utils.py b/stimuli/utils/utils.py index 17cf6fa0..1e889ce9 100644 --- a/stimuli/utils/utils.py +++ b/stimuli/utils/utils.py @@ -4,7 +4,6 @@ """ import warnings - import numpy as np @@ -25,13 +24,6 @@ def shift_pixels(img, shift): return np.roll(img, shift, (1, 0)) -def adapt_mc(stimulus, mc=1.0, mean_lum=0.5): - # Adapt Michelson contrast - stimulus = (stimulus - stimulus.min()) / (stimulus.max() - stimulus.min()) - stimulus = (stimulus * mc * 2.0 * mean_lum) + (mean_lum - mc * mean_lum) - return stimulus - - def round_to_vals(input_arr, vals): n_val = len(vals) input_arr = np.repeat(np.expand_dims(input_arr, -1), n_val, axis=2)