Skip to content

Commit

Permalink
added white_zigzag
Browse files Browse the repository at this point in the history
  • Loading branch information
LynnSchmittwilken committed Jun 19, 2022
1 parent b2b0f0e commit ea0375b
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 6 deletions.
133 changes: 130 additions & 3 deletions stimuli/illusions/whites.py
@@ -1,5 +1,3 @@
import math

import matplotlib.pyplot as plt
import numpy as np
from stimuli.illusions.square_wave import square_wave
Expand Down Expand Up @@ -556,8 +554,137 @@ def white_yazdanbakhsh(
return {"img": img, "mask": mask}


def white_zigzag(ppd=10,
L_size=(8., 6., 2.),
L_distance=2.,
L_repeats=6,
target_height=4.,
target_idx1=((2, 1), (2, 0), (2, -1)),
target_idx2=None,
v1=0.,
v2=1.,
vtarget=0.5,
):
"""
White zigzag stimulus (also wedding cake stimulus)
Parameters
----------
ppd : int
pixels per degree (visual angle)
L_size : (float, float, float)
size of individual jags (height, width, thickness) in degree visual angle
L_distance : float
distance between parallel jags in degree visual angle
L_repeats : float
number of repeats of jags
target_height : float
height of targets in degree visual angle
target_idx1 : nested tuples
target indices with v1-value; as many tuples as there are targets each with (y, x) indices;
y indicates index from top to bottom with zero being the top;
x indicates index from center to periphery with zero being the center
target_idx2 : nested tuples
target indices with v2-value; as many tuples as there are targets each with (y, x) indices;
y indicates index from top to bottom with zero being the top;
x indicates index from center to periphery with zero being the center
v1 : float
first value for grating
v2 : float
second value for grating
vtarget : float
value for target(s)
Returns
-------
A stimulus dictionary with the stimulus ['img'] and target mask ['mask']
"""

Ly, Lx, Lw = degrees_to_pixels(L_size, ppd)
Ld = degrees_to_pixels(L_distance, ppd)
nL = L_repeats
theight = degrees_to_pixels(target_height, ppd)

mval2 = 2
if target_idx1 is None:
target_idx1 = ()
mval2 = 1
if target_idx2 is None:
target_idx2 = ()

if len(L_size) != 3:
raise Exception("L_size needs to have a length of 3")
if nL < 2:
raise Exception("L_repeats should be larger than 1")

# Create grid patch
L_patch = np.zeros([Ly, Lx])
L_patch[0:Lw, 0:Lx] = v2 - v1
L_patch[0:Ly, Lx-Lw::] = v2 - v1
L_patch[0:Lw, 0:Lw] = (v2 - v1) / 2.
L_patch[Ly-Lw::, Lx-Lw::] = (v2 - v1) / 2.

# Create target and mask patch 1
tpatch1 = np.zeros([Ly, Lx])
tpatch1[int(Ly/2 - theight/2):int(Ly/2 + theight/2), Lx-Lw::] = vtarget - v2
mpatch1 = np.zeros([Ly, Lx])
mpatch1[int(Ly/2 - theight/2):int(Ly/2 + theight/2), Lx-Lw::] = 1

# Create target and mask patch 2
tpatch2 = np.zeros([Ly, Lx])
tpatch2[int(Ly/2 - theight/2):int(Ly/2 + theight/2), Lx-Lw-Ld:Lx-Lw] = vtarget - v1
mpatch2 = np.zeros([Ly, Lx])
mpatch2[int(Ly/2 - theight/2):int(Ly/2 + theight/2), Lx-Lw-Ld:Lx-Lw] = mval2

# Create image slightly larger than needed
img = np.ones([int(Ly*(nL+2)), int(Lx*(nL+2))]) * v1
height, width = img.shape
mask = np.zeros([height, width])

# Create indices to place grid
idx_y = np.arange(0, height-Ly, Ly-Lw)
idx_x = np.arange(0, width-Lx, Lx-Lw)

for j in range(int(nL**2)):
# Calculate starting coordinates in grid
ny, nx = j*(Ly + Ld) - (Ly-Lw)*j, j*(Lx + Ld) - (Lx-Lw)*j
my, mx = j*(Ly - Ld - Lw*2) - (Ly-Lw)*j, j*(Lx - Ld - Lw*2) - (Lx-Lw)*j
for i in range(np.minimum(len(idx_x), len(idx_y))):
if idx_y[i]+ny >= 0 and idx_x[i]+mx >= 0:
# Add grid in lower left half
if idx_y[i]+ny < height-Ly and idx_x[i]+mx < width-Lx:
img[idx_y[i]+ny:idx_y[i]+ny+Ly, idx_x[i]+mx:idx_x[i]+mx+Lx] += L_patch

# Add targets in lower left half
if (i-1, j) == target_idx1 or (i-1, j) in target_idx1:
img[idx_y[i]+ny:idx_y[i]+ny+Ly, idx_x[i]+mx:idx_x[i]+mx+Lx] += tpatch1
mask[idx_y[i]+ny:idx_y[i]+ny+Ly, idx_x[i]+mx:idx_x[i]+mx+Lx] += mpatch1
if (i-1, j) == target_idx2 or (i-1, j) in target_idx2:
img[idx_y[i]+ny+Lw:idx_y[i]+ny+Ly+Lw, idx_x[i]+mx:idx_x[i]+mx+Lx] += tpatch2
mask[idx_y[i]+ny+Lw:idx_y[i]+ny+Ly+Lw, idx_x[i]+mx:idx_x[i]+mx+Lx] += mpatch2

if idx_y[i]+my >= 0 and idx_x[i]+nx >= 0 and j > 0:
# Add grid in upper right half
if idx_y[i]+my < height-Ly and idx_x[i]+nx < width-Lx:
img[idx_y[i]+my:idx_y[i]+my+Ly, idx_x[i]+nx:idx_x[i]+nx+Lx] += L_patch

# Add targets in upper right half
if (i-1, -j) == target_idx1 or (i-1, -j) in target_idx1:
img[idx_y[i]+my:idx_y[i]+my+Ly, idx_x[i]+nx:idx_x[i]+nx+Lx] += tpatch1
mask[idx_y[i]+my:idx_y[i]+my+Ly, idx_x[i]+nx:idx_x[i]+nx+Lx] += mpatch1
if (i-1, -j) == target_idx2 or (i-1, -j) in target_idx2:
img[idx_y[i]+my+Lw:idx_y[i]+my+Ly+Lw, idx_x[i]+nx:idx_x[i]+nx+Lx] += tpatch2
mask[idx_y[i]+my+Lw:idx_y[i]+my+Ly+Lw, idx_x[i]+nx:idx_x[i]+nx+Lx] += mpatch2

# Crop to relevant size
img = img[Ly:height-Ly*2, Lx:width-Lx*2]
mask = mask[Ly:height-Ly*2, Lx:width-Lx*2]
return {"img": img, "mask": mask}


if __name__ == "__main__":
stim = white()
plt.figure(figsize=(8, 20))
plt.subplot(4, 2, 1)
plt.imshow(stim["img"], cmap="gray")
plt.subplot(4, 2, 2)
Expand All @@ -575,7 +702,7 @@ def white_yazdanbakhsh(
plt.subplot(4, 2, 6)
plt.imshow(stim["mask"], cmap="gray")

stim = white_yazdanbakhsh()
stim = white_zigzag()
plt.subplot(4, 2, 7)
plt.imshow(stim["img"], cmap="gray")
plt.subplot(4, 2, 8)
Expand Down
20 changes: 17 additions & 3 deletions stimuli/papers/RHS2007.py
Expand Up @@ -172,9 +172,23 @@ def WE_howe(ppd=PPD):
return stim


def WE_zigzag():
# TODO: not available atm
raise NotImplementedError
def WE_zigzag(ppd=PPD):
stim = stimuli.illusions.whites.white_zigzag(
ppd=PPD,
L_size=(4.4, 4.8, 1.),
L_distance=1.,
L_repeats=4.4,
target_height=2.,
target_idx1=((2, 2), (2, 1), (2, 0), (2, -1)),
target_idx2=((1, 1), (1, 0), (1, -1), (1, 2)),
v1=0.,
v2=1.,
vtarget=0.5,
)
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


def WE_radial_thick_small(ppd=PPD):
Expand Down

0 comments on commit ea0375b

Please sign in to comment.