pyllusion 1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. pyllusion/Autostereogram/Autostereogram.py +109 -0
  2. pyllusion/Autostereogram/__init__.py +5 -0
  3. pyllusion/Contrast/Contrast.py +159 -0
  4. pyllusion/Contrast/__init__.py +5 -0
  5. pyllusion/Contrast/contrast_image.py +45 -0
  6. pyllusion/Contrast/contrast_parameters.py +73 -0
  7. pyllusion/Contrast/contrast_psychopy.py +24 -0
  8. pyllusion/Delboeuf/Delboeuf.py +211 -0
  9. pyllusion/Delboeuf/__init__.py +5 -0
  10. pyllusion/Delboeuf/delboeuf_image.py +51 -0
  11. pyllusion/Delboeuf/delboeuf_parameters.py +118 -0
  12. pyllusion/Delboeuf/delboeuf_psychopy.py +44 -0
  13. pyllusion/Ebbinghaus/Ebbinghaus.py +194 -0
  14. pyllusion/Ebbinghaus/__init__.py +5 -0
  15. pyllusion/Ebbinghaus/ebbinghaus_image.py +64 -0
  16. pyllusion/Ebbinghaus/ebbinghaus_parameters.py +127 -0
  17. pyllusion/Ebbinghaus/ebbinghaus_psychopy.py +58 -0
  18. pyllusion/MullerLyer/MullerLyer.py +193 -0
  19. pyllusion/MullerLyer/__init__.py +5 -0
  20. pyllusion/MullerLyer/mullerlyer_image.py +56 -0
  21. pyllusion/MullerLyer/mullerlyer_parameters.py +42 -0
  22. pyllusion/MullerLyer/mullerlyer_psychopy.py +38 -0
  23. pyllusion/Pareidolia/Pareidolia.py +86 -0
  24. pyllusion/Pareidolia/__init__.py +5 -0
  25. pyllusion/Poggendorff/Poggendorff.py +160 -0
  26. pyllusion/Poggendorff/__init__.py +5 -0
  27. pyllusion/Poggendorff/poggendorff_image.py +43 -0
  28. pyllusion/Poggendorff/poggendorff_parameters.py +46 -0
  29. pyllusion/Poggendorff/poggendorff_psychopy.py +27 -0
  30. pyllusion/Ponzo/Ponzo.py +199 -0
  31. pyllusion/Ponzo/__init__.py +5 -0
  32. pyllusion/Ponzo/ponzo_image.py +54 -0
  33. pyllusion/Ponzo/ponzo_parameters.py +139 -0
  34. pyllusion/Ponzo/ponzo_psychopy.py +36 -0
  35. pyllusion/RodFrame/RodFrame.py +156 -0
  36. pyllusion/RodFrame/__init__.py +5 -0
  37. pyllusion/RodFrame/rodframe_image.py +59 -0
  38. pyllusion/RodFrame/rodframe_parameters.py +25 -0
  39. pyllusion/RodFrame/rodframe_psychopy.py +39 -0
  40. pyllusion/VerticalHorizontal/VerticalHorizontal.py +167 -0
  41. pyllusion/VerticalHorizontal/__init__.py +5 -0
  42. pyllusion/VerticalHorizontal/verticalhorizontal_image.py +34 -0
  43. pyllusion/VerticalHorizontal/verticalhorizontal_parameters.py +64 -0
  44. pyllusion/VerticalHorizontal/verticalhorizontal_psychopy.py +22 -0
  45. pyllusion/White/White.py +166 -0
  46. pyllusion/White/__init__.py +5 -0
  47. pyllusion/White/white_image.py +50 -0
  48. pyllusion/White/white_parameters.py +36 -0
  49. pyllusion/White/white_psychopy.py +27 -0
  50. pyllusion/Zollner/Zollner.py +178 -0
  51. pyllusion/Zollner/__init__.py +5 -0
  52. pyllusion/Zollner/zollner_image.py +51 -0
  53. pyllusion/Zollner/zollner_parameters.py +88 -0
  54. pyllusion/Zollner/zollner_psychopy.py +39 -0
  55. pyllusion/__init__.py +36 -0
  56. pyllusion/image/__init__.py +27 -0
  57. pyllusion/image/image_blob.py +152 -0
  58. pyllusion/image/image_circle.py +218 -0
  59. pyllusion/image/image_line.py +134 -0
  60. pyllusion/image/image_mosaic.py +53 -0
  61. pyllusion/image/image_noise.py +67 -0
  62. pyllusion/image/image_rectangle.py +136 -0
  63. pyllusion/image/image_scramble.py +112 -0
  64. pyllusion/image/image_text.py +95 -0
  65. pyllusion/image/rescale.py +52 -0
  66. pyllusion/image/utilities.py +226 -0
  67. pyllusion/movement/__init__.py +18 -0
  68. pyllusion/movement/motiontransparency.py +87 -0
  69. pyllusion/movement/movement_circles.py +24 -0
  70. pyllusion/movement/movement_matrix.py +63 -0
  71. pyllusion/movement/utilities.py +18 -0
  72. pyllusion/psychopy/__init__.py +12 -0
  73. pyllusion/psychopy/psychopy_circle.py +124 -0
  74. pyllusion/psychopy/psychopy_line.py +105 -0
  75. pyllusion/psychopy/psychopy_rectangle.py +139 -0
  76. pyllusion/utilities/__init__.py +13 -0
  77. pyllusion/utilities/analyze_color.py +90 -0
  78. pyllusion/utilities/analyze_image.py +73 -0
  79. pyllusion/utilities/analyze_luminance.py +73 -0
  80. pyllusion-1.4.dist-info/METADATA +553 -0
  81. pyllusion-1.4.dist-info/RECORD +85 -0
  82. pyllusion-1.4.dist-info/WHEEL +5 -0
  83. pyllusion-1.4.dist-info/licenses/LICENSE +21 -0
  84. pyllusion-1.4.dist-info/top_level.txt +2 -0
  85. tests/__init__.py +500 -0
@@ -0,0 +1,109 @@
1
+ import numpy as np
2
+ import PIL.Image, PIL.ImageDraw, PIL.ImageFilter, PIL.ImageFont, PIL.ImageOps
3
+
4
+ from ..image import image_noise, image_text
5
+
6
+
7
+ class Autostereogram:
8
+ """
9
+ A class to generate Autostereograms based on a given depth map.
10
+
11
+ Autostereograms are images made of a pattern that is horizontally repeated (with slight variations)
12
+ which, when watched with the appropriate focus, will generate an illusion of depth.
13
+ """
14
+ def __init__(
15
+ self, stimulus="Hello", pattern=None, n_repetitions=14, depth=1, invert=False, **kwargs
16
+ ):
17
+
18
+ self.stimulus = stimulus
19
+ self.pattern = pattern
20
+ self.n_repetitions = n_repetitions
21
+ self.depth = depth
22
+ self.invert = invert
23
+
24
+ # If '/' and '.' in string, we assume it's a path
25
+ if "/" in self.stimulus and "." in self.stimulus:
26
+ depth_map = PIL.Image.open(self.stimulus)
27
+ else: # Else a text
28
+ depth_map = image_text(text=self.stimulus, **kwargs)
29
+
30
+ # Convert to black and white
31
+ depth_map = depth_map.convert('L')
32
+ depth_map = PIL.ImageOps.autocontrast(depth_map)
33
+
34
+ if invert is False:
35
+ self.depth_map = PIL.ImageOps.invert(depth_map)
36
+ else:
37
+ self.depth_map = depth_map
38
+
39
+ # Get size of depth map
40
+ self.width, self.height = self.depth_map.size
41
+
42
+ # We want the strip width to be a multiple of the tile
43
+ # width so it repeats cleanly.
44
+ self.strip_width = int(self.width / self.n_repetitions)
45
+
46
+ # Fix conflicting arguments
47
+ conflicting_args = ["width", "height", "font"]
48
+ kwargs = {key: kwargs[key] for key in kwargs if key not in conflicting_args}
49
+
50
+ # Create strip of pattern
51
+ if pattern is None:
52
+ strip = image_noise(width=self.strip_width, height=self.height, **kwargs)
53
+ else:
54
+ strip = self.pattern(width=self.strip_width, height=self.height, **kwargs)
55
+ self.strip_pixels = strip.load()
56
+
57
+
58
+ def draw(self, guide=True):
59
+ """Create a PIL image of Autostereograms.
60
+
61
+ Parameters
62
+ ----------
63
+ guide : bool
64
+ Defaults to 'True' to activate two red dots as guidance, and 'False' to disable the guide.
65
+
66
+ Returns
67
+ -------
68
+ Image
69
+ Image of the Autostereograms illusion, defaults to 800 x 600 pixels.
70
+ Can be resized
71
+ (`resize()`, See https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.resize)
72
+ and saved in different file formats
73
+ (`save()` See https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html).
74
+
75
+ Examples
76
+ ---------
77
+ >>> import pyllusion
78
+ >>>
79
+ >>> autostereograms = pyllusion.Autostereogram(stimulus="3D", width=1000, height=500, font="arialbd.ttf")
80
+ >>> autostereograms.draw(guide=True)
81
+ """
82
+
83
+ image = PIL.Image.new("RGB", (self.width, self.height))
84
+
85
+ # Load pixels for easy replacement
86
+ depth_pixels = self.depth_map.load()
87
+ image_pixels = image.load()
88
+
89
+ for x in range(self.width):
90
+ for y in range(self.height):
91
+ # Need one full strip's worth to borrow from.
92
+ if x < self.strip_width:
93
+ image_pixels[x, y] = self.strip_pixels[x, y]
94
+ else:
95
+ shift_amplitude = self.depth * (depth_pixels[x, y] / self.n_repetitions)
96
+ # Clip to stay within the image (can happen for narrow strips)
97
+ source_x = int(x - self.strip_width + shift_amplitude)
98
+ source_x = min(max(source_x, 0), self.width - 1)
99
+ image_pixels[x, y] = image_pixels[source_x, y]
100
+
101
+ # Add guide
102
+ if guide is True:
103
+ draw = PIL.ImageDraw.Draw(image)
104
+ for i in [-2, 0]:
105
+ diameter = 0.005 * self.width
106
+ center_x = (self.width / 2) + (i * self.strip_width / 2)
107
+ center_y = 0.5 * self.height
108
+ draw.ellipse([center_x-diameter, center_y-diameter, center_x+diameter, center_y+diameter], fill=(255, 0, 0))
109
+ return image
@@ -0,0 +1,5 @@
1
+ """
2
+ Pyllusion submodule.
3
+ """
4
+
5
+ from .Autostereogram import Autostereogram
@@ -0,0 +1,159 @@
1
+ from .contrast_image import _contrast_image
2
+ from .contrast_parameters import _contrast_parameters
3
+ from .contrast_psychopy import _contrast_psychopy
4
+
5
+
6
+ class Contrast:
7
+ """
8
+ A class to generate the Simultaneous Contrast illusion.
9
+
10
+ Simultaneous contrast, identified by Michel Eugène Chevreul, refers to the
11
+ manner in which the colors of two different objects affect each other.
12
+ Specifically, when comparing two targets with the same shade of grey, the one that is
13
+ embedded against a darker background appears lighter than the other target embedded against a lighter background.
14
+
15
+ Each instance of **Contrast** contains attributes corresponding to the parameters of the illusion.
16
+
17
+ Parameters
18
+ ----------
19
+ illusion_strength : float
20
+ The strength of the background, i.e., contrasting colours, in biasing the perception of inner rectangles of different grey shades.
21
+ Specifically, the difference in background colours, where large values create greater contrast in the two
22
+ grey backgrounds.
23
+ A positive sign means that the illusion will enhance the perception of the actual **difference** in brightness contrast
24
+ of the two inner rectangles, whereas a negative sign reduces this perception.
25
+ difference : float
26
+ The objective difference of the grey shades of the two inner rectangles.
27
+ Large positive signs reflect a darker lower rectangle relative to the upper rectangle, and negative signs reflect a darker upper
28
+ rectangle relative to the lower rectangle.
29
+ """
30
+
31
+ def __init__(
32
+ self, illusion_strength=0, difference=0
33
+ ):
34
+ """
35
+ Compute parameters for the Simultaneous Contrast illusion.
36
+
37
+ Parameters
38
+ ----------
39
+ illusion_strength : float
40
+ The strength of the background, i.e., contrasting colours, in biasing the perception of inner rectangles of different grey shades.
41
+ Specifically, the difference in background colours, where large values create greater contrast in the two
42
+ grey backgrounds.
43
+ A positive sign means that the illusion will enhance the perception of the actual **difference** in brightness contrast
44
+ of the two inner rectangles, whereas a negative sign reduces this perception.
45
+ difference : float
46
+ The objective difference of the grey shades of the two inner rectangles.
47
+ Large positive signs reflect a darker lower rectangle relative to the upper rectangle, and negative signs reflect a darker upper
48
+ rectangle relative to the lower rectangle.
49
+ """
50
+ self.parameters = _contrast_parameters(
51
+ illusion_strength=illusion_strength,
52
+ difference=difference,
53
+ )
54
+
55
+ def get_parameters(self):
56
+ """
57
+ Returns a dictionary of parameters passed into the Simultaneous Contrast illusion.
58
+
59
+ Returns
60
+ -------
61
+ dict
62
+ Dictionary of parameters of the Simultaneous Contrast illusion, including:
63
+
64
+ - **Difference** : Objective difference in the target features, by modifying `difference` of contrast_parameters().
65
+ - **Illusion** : Name of the illusion, Contrast.
66
+ - **Illusion_Strength** : The strength of the surrounding context in biasing illusion, by modifying `illusion_strength` of contrast_parameters().
67
+ - **Illusion_Type** : `Congruent` if the illusion enhances the perception of the objective difference in the illusion, and `Incongruent` if it reduces the perceived difference.
68
+ - **Rectangle_Top** : Luminance of the top inner rectangle.
69
+ - **Rectangle_Bottom** : Luminance of the bottom inner rectangle.
70
+ - **Background_Top** : Luminance of the top half of the background.
71
+ - **Background_Bottom** : Luminance of the bottom half of the background.
72
+ - **Rectangle_Top_RGB** : RGB value of the top inner rectangle.
73
+ - **Rectangle_Bottom_RGB** : RGB value of the bottom inner rectangle.
74
+ - **Background_Top_RGB** : RGB value of the top half of the background.
75
+ - **Background_Bottom_RGB** : RGB value of the bottom half of the background.
76
+ """
77
+ return self.parameters
78
+
79
+ def to_dict(self):
80
+ """
81
+ Alias for `get_parameters()`.
82
+ """
83
+ return self.get_parameters()
84
+
85
+ def to_image(self, width=800, height=600, **kwargs):
86
+ """Create a PIL image of the Simultaneous Contrast illusion.
87
+
88
+ Parameters
89
+ ----------
90
+ width : int
91
+ Width of the returned image.
92
+ height : int
93
+ Height of the returned image.
94
+ **kwargs
95
+ Additional arguments passed into `contrast_parameters()`.
96
+
97
+ Returns
98
+ -------
99
+ Image
100
+ Image of the Simultaneous Contrast illusion, defaults to 800 x 600 pixels.
101
+ Can be resized
102
+ (`resize()`, See https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.resize)
103
+ and saved in different file formats
104
+ (`save()` See https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html).
105
+
106
+ Examples
107
+ ---------
108
+ >>> import pyllusion
109
+ >>>
110
+ >>> contrast = pyllusion.Contrast(illusion_strength=-50, difference=0)
111
+ >>> contrast.to_image()
112
+ """
113
+
114
+ img = _contrast_image(
115
+ parameters=self.parameters,
116
+ width=width,
117
+ height=height,
118
+ **kwargs
119
+ )
120
+ return img
121
+
122
+ def to_psychopy(self, window, **kwargs):
123
+ """Create a PsychoPy stimulus of the Simultaneous Contrast illusion.
124
+
125
+ Parameters
126
+ ----------
127
+ window : object
128
+ The window object in which the stimulus will be rendered.
129
+ **kwargs
130
+ Additional arguments passed into `contrast_parameters()`.
131
+
132
+ Returns
133
+ -------
134
+ In-place modification of the PsychoPy window (No explicit return).
135
+
136
+ Examples
137
+ ---------
138
+ >>> import pyllusion
139
+ >>> from psychopy import visual, event
140
+
141
+ >>> # Create parameters
142
+ >>> contrast = pyllusion.Contrast(difference=0, illusion_strength=-50)
143
+ >>> parameters = contrast.get_parameters()
144
+
145
+ >>> # Initiate Window
146
+ >>> window = visual.Window(size=[800, 600], winType='pygame',
147
+ color=parameters["Background_Top_RGB"],
148
+ colorSpace='rgb255')
149
+
150
+ >>> # Display illusion
151
+ >>> contrast.to_psychopy(window)
152
+
153
+ >>> # Refresh and close window
154
+ >>> window.flip()
155
+ >>> event.waitKeys() # Press any key to close
156
+ >>> window.close()
157
+
158
+ """
159
+ _contrast_psychopy(window, self.parameters, **kwargs)
@@ -0,0 +1,5 @@
1
+ """
2
+ Pyllusion submodule.
3
+ """
4
+
5
+ from .Contrast import Contrast
@@ -0,0 +1,45 @@
1
+ import numpy as np
2
+ import PIL.Image, PIL.ImageDraw, PIL.ImageFilter, PIL.ImageFont, PIL.ImageOps
3
+
4
+ from ..image import image_rectangle
5
+ from .contrast_parameters import _contrast_parameters
6
+
7
+
8
+ def _contrast_image(parameters=None, width=800, height=600, **kwargs):
9
+
10
+ # Create white canvas and get drawing context
11
+ if parameters is None:
12
+ parameters = _contrast_parameters(**kwargs)
13
+
14
+ # Background upper
15
+ image = PIL.Image.new(
16
+ "RGB", (width, height), color=parameters["Background_Top_RGB"]
17
+ )
18
+ # Background lower
19
+ image = image_rectangle(
20
+ image=image,
21
+ y=-0.5,
22
+ size_height=1,
23
+ size_width=2,
24
+ color=parameters["Background_Bottom_RGB"],
25
+ antialias=False,
26
+ )
27
+
28
+ image = image_rectangle(
29
+ image=image,
30
+ y=0.5,
31
+ size_height=0.5,
32
+ size_width=1,
33
+ color=parameters["Rectangle_Top_RGB"],
34
+ antialias=False,
35
+ )
36
+ image = image_rectangle(
37
+ image=image,
38
+ y=-0.5,
39
+ size_height=0.5,
40
+ size_width=1,
41
+ color=parameters["Rectangle_Bottom_RGB"],
42
+ antialias=False,
43
+ )
44
+
45
+ return image
@@ -0,0 +1,73 @@
1
+ import numpy as np
2
+
3
+ from ..image import rescale
4
+
5
+
6
+ def _contrast_parameters(illusion_strength=0, difference=0):
7
+
8
+ colors, rgb = _contrast_parameters_internal(
9
+ difference=difference, illusion_strength=illusion_strength
10
+ )
11
+
12
+ parameters = {
13
+ "Illusion": "Contrast",
14
+ "Illusion_Strength": illusion_strength,
15
+ "Difference": difference,
16
+ "Illusion_Type": "Congruent" if illusion_strength > 0 else "Incongruent",
17
+ "Rectangle_Top": colors[0],
18
+ "Rectangle_Bottom": colors[1],
19
+ "Background_Top": colors[2],
20
+ "Background_Bottom": colors[3],
21
+ "Rectangle_Top_RGB": rgb[0],
22
+ "Rectangle_Bottom_RGB": rgb[1],
23
+ "Background_Top_RGB": rgb[2],
24
+ "Background_Bottom_RGB": rgb[3],
25
+ }
26
+
27
+ return parameters
28
+
29
+
30
+ def _contrast_parameters_internal(difference=0, illusion_strength=0):
31
+ # Targets
32
+ # A difference of 1 means a difference of 1%
33
+ up = 0.5 + difference / 200
34
+ low = 0.5 - difference / 200
35
+
36
+ # Backgrounds
37
+ # A illusion_strength of 1 means a difference of 1%
38
+ mod = np.sign(difference) if difference != 0 else 1
39
+ background_up = 0.5 + mod * illusion_strength / 200
40
+ background_low = 0.5 - mod * illusion_strength / 200
41
+
42
+ # Adjustments in case of same contrast between rectangle and background
43
+ if background_up == up:
44
+ if background_up > background_low:
45
+ background_up += 0.01
46
+ elif background_up < background_low:
47
+ background_up -= 0.01
48
+ else:
49
+ background_up -= 0.01
50
+ background_low -= 0.01
51
+ if background_low == low:
52
+ if background_low > background_up:
53
+ background_low += 0.01
54
+ elif background_low < background_up:
55
+ background_low -= 0.01
56
+ else:
57
+ background_low -= 0.01
58
+ background_up -= 0.01
59
+
60
+ # Transform to RGB tuples
61
+ background_up_rgb = tuple(
62
+ np.rint(rescale([background_up] * 3, scale=[0, 1], to=[0, 255])).astype(int)
63
+ )
64
+ background_low_rgb = tuple(
65
+ np.rint(rescale([background_low] * 3, scale=[0, 1], to=[0, 255])).astype(int)
66
+ )
67
+ up_rgb = tuple(np.rint(rescale([up] * 3, scale=[0, 1], to=[0, 255])).astype(int))
68
+ low_rgb = tuple(np.rint(rescale([low] * 3, scale=[0, 1], to=[0, 255])).astype(int))
69
+
70
+ return (
71
+ (up, low, background_up, background_low),
72
+ (up_rgb, low_rgb, background_up_rgb, background_low_rgb),
73
+ )
@@ -0,0 +1,24 @@
1
+ import numpy as np
2
+
3
+ from ..psychopy.psychopy_rectangle import psychopy_rectangle
4
+ from .contrast_parameters import _contrast_parameters
5
+
6
+
7
+ def _contrast_psychopy(window, parameters=None, **kwargs):
8
+
9
+ # Create white canvas and get drawing context
10
+ if parameters is None:
11
+ parameters = _contrast_parameters(**kwargs)
12
+
13
+ # Background lower
14
+ psychopy_rectangle(window, x=0, y=-0.5, size_height=1, size_width=2, color=parameters["Background_Bottom_RGB"],
15
+ outline_color=parameters["Background_Bottom_RGB"],
16
+ fillColorSpace='rgb255', lineColorSpace='rgb255')
17
+
18
+ psychopy_rectangle(window, x=0, y=0.5, size_height=0.5, size_width=1, color=parameters["Rectangle_Top_RGB"],
19
+ outline_color=parameters["Rectangle_Top_RGB"],
20
+ fillColorSpace='rgb255', lineColorSpace='rgb255')
21
+
22
+ psychopy_rectangle(window, x=0, y=-0.5, size_height=0.5, size_width=1, color=parameters["Rectangle_Bottom_RGB"],
23
+ outline_color=parameters["Rectangle_Bottom_RGB"],
24
+ fillColorSpace='rgb255', lineColorSpace='rgb255')
@@ -0,0 +1,211 @@
1
+ from .delboeuf_image import _delboeuf_image
2
+ from .delboeuf_parameters import _delboeuf_parameters
3
+ from .delboeuf_psychopy import _delboeuf_psychopy
4
+
5
+
6
+ class Delboeuf:
7
+ """
8
+ A class to generate the Delboeuf Illusion.
9
+
10
+ The Delboeuf illusion is an optical illusion of relative size perception,
11
+ where circles of identical size appear as different because of their surrounding context.
12
+ Specifically, the circle that is closely surrounded by a ring appears larger than the circle surrounded by a distant ring.
13
+
14
+ Each instance of Delboeuf contains attributes corresponding to the parameters of the illusion.
15
+
16
+ Parameters
17
+ ----------
18
+ illusion_strength : float
19
+ The strength of the surrounding context, i.e. outer circles, in biasing perception of unequally sized inner circles.
20
+ Specifically, the size of the outer circle relative to the inner circle (in percentage, e.g, if illusion_strength=1,
21
+ it means that the outer circle will be 100% bigger, i.e., 2 times bigger than the inner circle).
22
+ A negative sign means that the illusion will enhance the perception of the actual difference in circle sizes
23
+ whereas a positive sign reduces this perception.
24
+ difference : float
25
+ The objective size difference of the inner circles. Specifically, the size of left inner
26
+ circle relative to the right (in percentage, e.g., if difference=1, it means that the left
27
+ inner circle will be 100% bigger, i.e., 2 times bigger than the right). A negative sign
28
+ would make the left inner circle smaller than the right inner circle.
29
+ size_min : float
30
+ Size of smaller inner circle. Defaults to 0.25.
31
+ distance : float
32
+ Distance between circles. Defaults to 1.
33
+ distance_auto : bool
34
+ If true, distance is between edges (fixed spacing), if false (default), between centers (fixed location).
35
+ """
36
+
37
+ def __init__(
38
+ self,
39
+ illusion_strength=0,
40
+ difference=0,
41
+ size_min=0.25,
42
+ distance=1,
43
+ distance_auto=False,
44
+ ):
45
+ """
46
+ Compute attributes for the Delboeuf Illusion.
47
+
48
+ Parameters
49
+ ----------
50
+ illusion_strength : float
51
+ The strength of the surrounding context, i.e. outer circles, in biasing perception of unequally sized inner circles.
52
+ Specifically, the size of the outer circle relative to the inner circle (in percentage, e.g, if illusion_strength=1,
53
+ it means that the outer circle will be 100% bigger, i.e., 2 times bigger than the inner circle).
54
+ A negative sign means that the illusion will enhance the perception of the actual difference in circle sizes
55
+ whereas a positive sign reduces this perception.
56
+ difference : float
57
+ The objective size difference of the inner circles.
58
+ Specifically, the size of left inner circle relative to the right (in percentage, e.g., if difference=1,
59
+ it means that the left inner circle will be 100% bigger, i.e., 2 times bigger than the right).
60
+ A negative sign would make the left inner circle smaller than the right inner circle.
61
+ size_min : float
62
+ Size of smaller inner circle. Defaults to 0.25.
63
+ distance : float
64
+ Distance between circles. Defaults to 1.
65
+ distance_auto : bool
66
+ If true, distance is between edges (fixed spacing), if false (default), between centers (fixed location).
67
+ """
68
+ self.parameters = _delboeuf_parameters(
69
+ illusion_strength=illusion_strength,
70
+ difference=difference,
71
+ size_min=size_min,
72
+ distance=distance,
73
+ distance_auto=distance_auto,
74
+ )
75
+
76
+ def get_parameters(self):
77
+ """
78
+ Returns a dictionary of parameters passed into the Delboeuf illusion.
79
+
80
+ Returns
81
+ --------
82
+ dict
83
+ A dictionary of all parameters passed into the Delboeuf illusion, including:
84
+
85
+ - **Difference** : Objective difference in the target features, by modifying `difference` of delboeuf_parameters()
86
+ - **Illusion** : Name of the illusion, Delboeuf.
87
+ - **Illusion_Strength** : The strength of the surrounding context in biasing illusion, by modifying `illusion_strength` of delboeuf_parameters().
88
+ - **Illusion_Type** : `Congruent` if the illusion enhances the perception of the objective difference in the illusion, and `Incongruent` if it reduces the perceived difference.
89
+ - **Size_Inner_Left** : Size of the inner left circle.
90
+ - **Size_Inner_Right** : Size of the inner right circle.
91
+ - **Sine_Inner_Difference** : Difference in areas of the left and right inner circles.
92
+ - **Size_Outer_Left** : Size of the outer left rim.
93
+ - **Size_Outer_Right** : Size of the outer right rim.
94
+ - **Distance** : Distance between the circles, by modifying `distance` of delboeuf_parameters().
95
+ - **Distance_Reference** : Distance between circles is computed 'Between Edges' or `Between Centers`, by modifying distance_auto of delboeuf_parameters().
96
+ - **Distance_Edges_Inner** : Distance between the edges of the inner left and right circles.
97
+ - **Distance_Edges_Outer** : Distance between the edges of the outer left and right rims.
98
+ - **Size_Inner_Smaller** : Size of the smaller inner circle, equates to size_min of delboeuf_parameters().
99
+ - **Size_Inner_Larger** : Size of the larger inner circle.
100
+ - **Size_Outer_Smaller** : Size of the smaller outer rim.
101
+ - **Size_Outer_Larger** : Size of the larger outer rim.
102
+ - **Position_Left** : Position of the left circle.
103
+ - **Position_Right** : Position of the right circle.
104
+ """
105
+ return self.parameters
106
+
107
+ def to_dict(self):
108
+ """
109
+ Alias for `get_parameters()`.
110
+ """
111
+ return self.get_parameters()
112
+
113
+ def to_image(
114
+ self, width=800, height=600, outline=10, background="white", target_only=False, **kwargs
115
+ ):
116
+ """Create a PIL image of the Delboeuf illusion.
117
+
118
+ Parameters
119
+ ----------
120
+ width : int
121
+ Width of the returned image.
122
+ height : int
123
+ Height of the returned image.
124
+ outline : float
125
+ The width of the outline of the circles in the illusion, passed into `image_circle()`.
126
+ background : str
127
+ Color of the background.
128
+ distractor_fill : str or tuple
129
+ Color of the outer distractor circles. Set to ``(0, 0, 0, 0)`` (transparent) by
130
+ default.
131
+ target_only : bool
132
+ If true, only draw the red circle.
133
+ **kwargs
134
+ Additional arguments passed into `delboeuf_parameters()`.
135
+
136
+ Returns
137
+ -------
138
+ Image
139
+ Image of the Delboeuf illusion, defaults to 800 x 600 pixels.
140
+ Can be resized
141
+ (`resize()`, See https://pillow.readthedocs.io/en/stable/reference/Image.html#PIL.Image.Image.resize)
142
+ and saved in different file formats
143
+ (`save()` See https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html).
144
+
145
+ Examples
146
+ ---------
147
+ >>> import pyllusion
148
+ >>>
149
+ >>> delboeuf = pyllusion.Delboeuf(illusion_strength=3)
150
+ >>> delboeuf.to_image()
151
+ >>> delboeuf.get_parameters()
152
+ >>>
153
+ >>> # Display only the target (no illusion)
154
+ >>> delboeuf = pyllusion.Delboeuf(difference=2)
155
+ >>> delboeuf.to_image(target_only=True)
156
+ >>>
157
+ >>> # Alternative version
158
+ >>> delboeuf = pyllusion.Delboeuf(illusion_strength=3)
159
+ >>> delboeuf.to_image(background="grey", distractor_fill="white", outline=0)
160
+ >>>
161
+
162
+ """
163
+ img = _delboeuf_image(
164
+ parameters=self.parameters,
165
+ width=width,
166
+ height=height,
167
+ outline=outline,
168
+ background=background,
169
+ target_only=target_only,
170
+ **kwargs
171
+ )
172
+ return img
173
+
174
+ def to_psychopy(self, window, target_only=False, **kwargs):
175
+ """Create a PsychoPy stimulus of the Delboeuf illusion.
176
+
177
+ Parameters
178
+ ----------
179
+ window : object
180
+ The window object initiated by `psychopy.visual.Window` in which the stimulus will be
181
+ rendered.
182
+ target_only : bool
183
+ If true, only draw the red circle.
184
+ **kwargs
185
+ Additional arguments passed into `delboeuf_parameters()`.
186
+
187
+ Returns
188
+ -------
189
+ In-place modification of the PsychoPy window (No explicit return).
190
+
191
+ Examples
192
+ ---------
193
+ >>> import pyllusion
194
+ >>> from psychopy import visual, event
195
+
196
+ >>> # Create parameters
197
+ >>> delboeuf = pyllusion.Delboeuf(difference=2, illusion_strength=3)
198
+
199
+ >>> # Initiate Window
200
+ >>> window = visual.Window(size=[800, 600], winType='pygame', color='white')
201
+
202
+ >>> # Display illusion
203
+ >>> delboeuf.to_psychopy(window)
204
+
205
+ >>> # Refresh and close window
206
+ >>> window.flip()
207
+ >>> event.waitKeys() # Press any key to close
208
+ >>> window.close()
209
+
210
+ """
211
+ _delboeuf_psychopy(window, self.parameters, target_only=target_only, **kwargs)
@@ -0,0 +1,5 @@
1
+ """
2
+ Pyllusion submodule.
3
+ """
4
+
5
+ from .Delboeuf import Delboeuf