MATLAB code to generate CFS (Mondrian)

There are plenty of ways to generate Continuous Flash Suppression (CFS) in the research of consciousness, for newbies, some example code might be extremely handy, here I share some codes I wrote or collected in the past. Hope this is useful.

METHOD 1

The basic thought behind this method is to continuously present multiple pre-made Mondrian images.


example1


example 2

The code to generate Mondrian figures is shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

%% code to make mondrian figures

path = '/Users/JIANCHEN/Desktop/Mondrian/method1';

cd(path);

fignum = 10; % number of figs to generate
Msize = [500,500]; % figure dimensions
psize = [40,30]; % size of patches
marg = max(psize); % maximum size of patches
pnum = 4000; % number of patches in the given area


for i = 1 : fignum
pcenter = ceil(rand(pnum,2)*Msize(1));
p = round(rand(1,pnum)*(psize(2)-psize(1)+psize(1))/2);
color = round(rand(pnum*1.2,3));
ind = find(sum(color,2)==0);
color(ind,:) = [];
a = zeros(Msize(1)+marg,Msize(2)+marg);
for n = 1:pnum
c = pcenter(n,:);
for m = 1:3
a(c(1)-p(n)+marg/2:c(1)+p(n)+marg/2,c(2)-p(n)+marg/2:c(2)+p(n)+marg/2,m) = color(n,m);
end
end
center0 = size(a)/2;
center0(3) = [];
lu = center0-Msize/2;
rd = center0+Msize/2;
b = a(lu(1):rd(1),lu(2):rd(2),:);
imwrite(b,[num2str(i),'.bmp']); % save figures
end
~~

After generating these Mondrian figures, you just need to present them briefly to get the effect of a CFS.


METHOD 2

The second method is from Dr. Bryan Paton, his code demonstrates an elegant way to generate CFS in the MATLAB.


Effect of code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
% CFS
% Date: 30/12/2014
% Author: Bryan Paton
% History:

%%
% Start Experiment

fprintf('\nContinuous Flash Suppression\n');

Screen('Preference', 'SkipSyncTests', 2); %Skip screen test on LCD monitor


% % Collect participant number
% fprintf('\n');
% partNum = input('Participant Number: ', 's');
% fprintf('\n');

%%
% Set up experiment parameters

fprintf('Initialise experiment...');

% Seed random number generator stream with a fixed seed and use the
% Mersenne Twister algorithm, note this only works in 2011a onwards
randSeed = 100;
rng(randSeed, 'twister');

%%
% Set up Mondrian Parameters

% List of Mondrian colours
mondColours = {[255, 255, 255], [255, 64, 0], [0, 255, 0], [0, 0, 255], [255, 255, 0], [255, 0, 255], [0, 255, 255]};
alphaRange = [100, 200];

% Mondrian pattern settings
mondrianRadiusMinorRange = [15 35]; % 1/2 Height of Mondrian element in pixels
mondrianRadiusMajorRange = [15 35]; % 1/2 Width of Mondrian element in pixels
xOffsetRange = [-185, 185]; % Range of pixel eccentricities that serve as the origin of the Mondrian elements
yOffsetRange = [-185, 185]; % Range of pixel eccentricities that serve as the origin of the Mondrian elements
numElements = 500; % Number of Mondrian elements to draw
rightOffset = 350; % Drawing offset for the right side
leftOffset = -rightOffset; % Drawing offset for the left side
mondRefresh = 0.1; % Mondrian refresh period in seconds, frequency = 1/period
borderWidth = 30; % Width of the fusion surround in pixels
stimQuadCoords = [-97, -97; 97, -97; 97, 97; -97, 97]; % Q1, Q2, Q3, Q4 clockwise
gaborDim = 128; % Dimensions, x & y of gabor patch, also the same size of the face texture (pow 2)

fprintf('\nDone.\n');

%%
% Set up Screen and bailout if there is a problem

fprintf('Set up Screen...');

try
% Find relevant screen number, min for Windows in multiple monitor
% setups gives you the first or primary screen
screenList = Screen('Screens');
if length(screenList) > 1
screenNumber = min(Screen('Screens')) + 1;
else
screenNumber = min(Screen('Screens'));
end;

% Screen dimensions
rect = Screen('Rect', screenNumber);

% Screen parameters
xMax = rect(1, 3);
yMax = rect(1, 4);

oldVisualDebugLevel = Screen('Preference', 'VisualDebugLevel', 3);
oldSupressAllWarnings = Screen('Preference', 'SuppressAllWarnings', 1);

% Open window with 50% grey and set up for Alpha channel blending
drawWindow = Screen('OpenWindow', screenNumber, 127);


% Determine max priority level for later drawing
priorityLvl = MaxPriority(drawWindow);

HideCursor;

catch

ShowCursor;
Screen('CloseAll');
Screen('Preference', 'VisualDebugLevel', oldVisualDebugLevel);
Screen('Preference', 'SuppressAllWarnings', oldSupressAllWarnings);
psychrethrow(psychlasterror);

end;

fprintf('Done.\n');

%%

fprintf('Set up remaining parameters...');

% Set up stimuli

% Load face texture
faceData = imread('faceLarge.png');
stimTextures(1) = Screen('MakeTexture', drawWindow, faceData, 1); % optimise for power of 2 texture
faceSize(1) = size(faceData, 1);
faceSize(2) = size(faceData, 2);

% Create procedural (GSL shader) gabor texture
stimTextures(2) = CreateProceduralGabor(drawWindow, gaborDim, gaborDim, [], [0.5 0.5 0.5 0.0], 1, 0.5);
stimTextures(3) = 0; % Dummy, as stimulus 3 is blank

%%
% Set up onscreen text options
Screen('TextSize', drawWindow, 14);
Screen('TextFont', drawWindow, 'Helvetica');
Screen('TextColor', drawWindow, [255, 255, 255]);

fprintf('Done.\n');

%%

trialRunning = 1;
mondSide = 1;
stimType = 1;
stimQuad = 2;

% Get first timestamp for screen flip in seconds
timeStamp = Screen('Flip', drawWindow);

% Mondrian loop
while trialRunning == 1

% Set max priority for drawing
Priority(priorityLvl);

if mondSide == 1
% Draw stimulus on left, Mondrian on right
DrawMondrian(drawWindow, numElements, (xMax / 2) + rightOffset + xOffsetRange, (yMax / 2) + yOffsetRange, ...
mondrianRadiusMinorRange, mondrianRadiusMajorRange, mondColours, alphaRange);

DrawStimulus(drawWindow, stimType, stimTextures(stimType), (xMax / 2) + leftOffset + stimQuadCoords(stimQuad, 1) - (faceSize(1) ./ 2), ...
(yMax / 2) + stimQuadCoords(stimQuad, 2) - (faceSize(2) ./ 2), faceSize(1), faceSize(2));

else

% Draw stimulus on right, Mondrian on left
DrawMondrian(drawWindow, numElements, (xMax / 2) + leftOffset + xOffsetRange, (yMax / 2) + yOffsetRange, ...
mondrianRadiusMinorRange, mondrianRadiusMajorRange, mondColours, alphaRange);

DrawStimulus(drawWindow, stimType, stimTextures(stimType), (xMax / 2) + leftOffset + stimQuadCoords(stimQuad, 1) - (faceSize(1) ./ 2), ...
(yMax / 2) + stimQuadCoords(stimQuad, 2) - (faceSize(2) ./ 2), faceSize(1), faceSize(2));

end;

% Draw fusion surround for each eye and fixation cross
DrawSurround(drawWindow, (xMax / 2) + leftOffset, (yMax / 2), borderWidth);
DrawSurround(drawWindow, (xMax / 2) + rightOffset, (yMax / 2), borderWidth);

Screen('DrawingFinished', drawWindow);

timeStamp = Screen('Flip', drawWindow, timeStamp + mondRefresh);

%WaitSecs(mondRefresh);

% Reset priority to default
Priority(0);

if KbCheck
trialRunning = 0;
end;



end;

%%
% Tidy up and quit

fprintf('Clean up...');

ShowCursor;

% Close window
Screen('CloseAll');

% Restore preferences
Screen('Preference', 'VisualDebugLevel', oldVisualDebugLevel);
Screen('Preference', 'SuppressAllWarnings', oldSupressAllWarnings);

fprintf('Done.\n');
fprintf('All finished.\nThank You.\n');