SpatioTemporal_Binary_White_Noise_Stimulus.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. function SpatioTemporal_Binary_White_Noise_Stimulus(varargin)
  2. %
  3. %
  4. %===================================================================================
  5. % Parameter Default Usage
  6. %===================================================================================
  7. %
  8. % selecttextfile false To call browse prompt to select the parameters text file
  9. % stixelwidth 6 Width of each pixel of the checkerboard defined in monitor pixels unit
  10. % stixelheight 6 Height of each pixel of the checkerboard defined in monitor pixels unit
  11. % blackwhite true Option to switch between Binary and Gaussian white-noise (Not available)
  12. % contrast 1 Contrast of black & white stimulus. 1 is 100 contrast.
  13. % meanintensity 0.5 Mean intensity value used to define contrast
  14. % seed -1000 Starting value for random number generator (should be always negative)
  15. % secondseed -10000 Same as seed but for green color (only used if color is true).
  16. % thirdseed -2000 Same as seed but for blue color (only used if color is true).
  17. % nblinks 2 Number of frames to hold the stimulus on screen (2 is 30 Hz stimulus)
  18. % color false Option to switch between black & white and chromatic white-noise
  19. % redmeanintensity 0 Mean intensity for red gun of the screen (only used if color is true).
  20. % greenmeanintensity 0.5 Mean intensity for green gun of the screen (only used if color is true).
  21. % bluemeanintensity 0.5 Mean intensity for blue gun of the screen (only used if color is true).
  22. % redcontrast 0 Contrast of red stimulus (only used if color is true).
  23. % greencontrast 0.75 Contrast of green stimulus (only used if color is true).
  24. % bluecontrast 0.75 Contrast of blue stimulus (only used if color is true).
  25. % screensize 864 x 480 Screen resolution, default value is the resolution of the lightcrafter projector
  26. % refreshrate 60 Screen refresh rate in Hz
  27. % fullscreen false Option to display the stimulus in full-screen mode
  28. % help false Option to check the list of available parameters
  29. % lmargin 0 Margins from left side of the screen (not available for this stimulus)
  30. % rmagin 0 Margins from right side of the screen (not available for this stimulus)
  31. % tmargin 0 Margins from top of the screen (not available for this stimulus)
  32. % bmargin 0 Margins from bottom of the screen (not available for this stimulus)
  33. % coneisolating false Option to activate opsin-isolation (excluded for simplicity)
  34. %
  35. %====================================================================================
  36. %
  37. %
  38. para = read_stimulus_parameters(varargin{:});
  39. if para.help, return; end
  40. % xax = (para.lmargin+1):para.stixelwidth:(para.screensize(1)-(para.rmargin));
  41. % yax = (para.bmargin+1):para.stixelheight:(para.screensize(2)-(para.tmargin));
  42. xax = linspace(para.lmargin,para.screensize(1)-(para.rmargin),para.Nx)+para.stixelwidth/2;
  43. yax = linspace(para.tmargin,para.screensize(2)-(para.bmargin),para.Ny)+para.stixelheight/2;
  44. % The darwing of the screen goes here
  45. monitorsize = get(0,'ScreenSize');
  46. scpos = [monitorsize(3)/2-(para.screensize(1)/2), ...
  47. monitorsize(4)/2-(para.screensize(2)/2), para.screensize];
  48. % make an screen like figure
  49. fh = figure('Menu','none','ToolBar','none','Position',scpos,'Color',0.5*[1 1 1]);
  50. fh.Name = 'Example of Spatio-temporal White Noise Stimulus, from Khani and Gollisch (2021)';
  51. fh.Colormap = gray;
  52. ah = axes('Units','Normalize','Position',[0 0 1 1],'Color',0.5*[1 1 1]);
  53. axis(ah,[0, para.screensize(1),0, para.screensize(2)]);
  54. axis(ah,'off');
  55. framecounter = 0;
  56. if para.color
  57. seed1 = para.seed;
  58. seed2 = para.secondseed;
  59. seed3 = para.thirdseed;
  60. redWeberContrastHigh = para.redmeanintensity + (para.redContrast * para.redmeanintensity);
  61. redWeberContrastLow = para.redmeanintensity - (para.redContrast * para.redmeanintensity);
  62. greenWeberContrastHigh = para.greenmeanintensity + (para.greenContrast * para.greenmeanintensity);
  63. greenWeberContrastLow = para.greenmeanintensity - (para.greenContrast * para.greenmeanintensity);
  64. blueWeberContrastHigh = para.bluemeanintensity + (para.blueContrast * para.bluemeanintensity);
  65. blueWeberContrastLow = para.bluemeanintensity - (para.blueContrast * para.bluemeanintensity);
  66. else
  67. seed = para.seed;
  68. whiteWeberContrastHigh = para.meanintensity + (para.contrast * para.meanintensity);
  69. whiteWeberContrastLow = para.meanintensity - (para.contrast * para.meanintensity);
  70. end
  71. while ishandle(fh)
  72. if para.color
  73. % red
  74. [checkerred, seed1] = ran1(seed1,para.Nx*para.Ny);
  75. checkerred = single((checkerred > para.redmeanintensity) .* redWeberContrastHigh);
  76. checkerred(checkerred == 0) = redWeberContrastLow;
  77. checkerred = reshape(checkerred,para.Ny,para.Nx);
  78. % green
  79. [checkergreen, seed2] = ran1(seed2,para.Nx*para.Ny);
  80. checkergreen = single((checkergreen > para.greenmeanintensity) .* greenWeberContrastHigh);
  81. checkergreen(checkergreen == 0) = greenWeberContrastLow;
  82. checkergreen = reshape(checkergreen,para.Ny,para.Nx);
  83. % blue
  84. [checkerblue, seed3] = ran1(seed3,para.Nx*para.Ny);
  85. checkerblue = single((checkerblue > para.bluemeanintensity) .* blueWeberContrastHigh);
  86. checkerblue(checkerblue == 0) = blueWeberContrastLow;
  87. checkerblue = reshape(checkerblue,para.Ny,para.Nx);
  88. % put all colors together
  89. checker = cat(3,checkerred,checkergreen,checkerblue);
  90. else
  91. % black & white checker
  92. [checker, seed] = ran1(seed,para.Nx*para.Ny);
  93. checker = single((checker > para.meanintensity) .* whiteWeberContrastHigh);
  94. checker(checker == 0) = whiteWeberContrastLow;
  95. checker = reshape(checker,para.Ny,para.Nx);
  96. checker = repmat(checker,1,1,3);
  97. end
  98. if framecounter == 0
  99. rf = imagesc(xax,yax, checker);
  100. axis(ah,[0, para.screensize(1),0, para.screensize(2)]);
  101. set(ah,'Color',0.5*[1 1 1]); % this is to have gray background with margins
  102. else
  103. rf.CData = checker;
  104. end
  105. % this is to draw the frames relatively accurately.
  106. drawnow;
  107. java.lang.Thread.sleep(para.nblinks/para.refreshrate*1e3);
  108. %pause(1/para.refreshrate);
  109. framecounter = framecounter+1;
  110. end
  111. end
  112. %--------------------------------------------------------------------------------------------------%
  113. %---------- sub-functions ----------%
  114. %--------------------------------------------------------------------------------------------------%
  115. function paraout = read_stimulus_parameters(varargin)
  116. % first parse the user inputs
  117. p = inputParser(); % check the user options.
  118. validtruefalse = @(x) islogical(x) || (isnumeric(x) && ismember(x,[0,1]));
  119. p.addParameter('selecttextfile', false, validtruefalse);
  120. p.addParameter('stixelwidth', 6, @isnumeric);
  121. p.addParameter('stixelheight', 6, @isnumeric);
  122. p.addParameter('blackwhite', true, validtruefalse);
  123. p.addParameter('contrast',1, @isnumeric);
  124. p.addParameter('meanintensity', 0.5, @isnumeric);
  125. p.addParameter('seed', -1000, @isnumeric);
  126. p.addParameter('secondseed', -10000, @isnumeric);
  127. p.addParameter('thirdseed', -2000, @isnumeric);
  128. p.addParameter('nblinks', 2, @isnumeric);
  129. p.addParameter('lmargin',0, @isnumeric);
  130. p.addParameter('rmargin', 0, @isnumeric);
  131. p.addParameter('bmargin', 0, @isnumeric);
  132. p.addParameter('tmargin', 0, @isnumeric);
  133. p.addParameter('color', false, validtruefalse);
  134. p.addParameter('coneisolating', true, validtruefalse);
  135. p.addParameter('redmeanintensity', 0, @isnumeric);
  136. p.addParameter('greenmeanintensity', 0.5, @isnumeric);
  137. p.addParameter('bluemeanintensity', 0.5, @isnumeric);
  138. p.addParameter('redContrast', 0, @isnumeric);
  139. p.addParameter('greenContrast', 0.75, @isnumeric);
  140. p.addParameter('blueContrast', 0.75, @isnumeric);
  141. p.addParameter('screensize', [864 480], @isnumeric);
  142. p.addParameter('refreshrate', 60, @isnumeric);
  143. p.addParameter('fullscreen', false, validtruefalse);
  144. p.addParameter('help', false, validtruefalse);
  145. p.parse(varargin{:});
  146. % defualt parameters
  147. defpara = p.Results;
  148. if defpara.help
  149. help_info_for_parameters(defpara);
  150. paraout = defpara;
  151. return;
  152. end
  153. if defpara.selecttextfile
  154. % now read the text files
  155. [stimfile, stimpath] = uigetfile('*.txt','Select a chromatic integration stimulus parameter file','chromatic_integration.txt');
  156. fid = fopen([stimpath,filesep,stimfile]);
  157. tline = fgetl(fid);
  158. while ischar(tline)
  159. tline = fgetl(fid);
  160. if tline == -1, break; end
  161. fn = extractBefore(tline,' = ');
  162. if isempty(fn), continue; end
  163. val = extractAfter(tline,' = ');
  164. % to convert to double
  165. if ~isnan(str2double(val))
  166. val = str2double(val);
  167. end
  168. % to convert to logical
  169. if strcmp(val,'true'), val = true; end
  170. if strcmp(val,'false'), val = false; end
  171. % store the values in a structure
  172. stimpara.(fn) = val;
  173. end
  174. fclose(fid);
  175. % compare the text file to the defualt values and fill the missing parameters
  176. fn = fieldnames(defpara);
  177. for ii = 1:numel(fn)
  178. if isfield(stimpara,fn{ii})
  179. paraout.(fn{ii}) = stimpara.(fn{ii});
  180. else
  181. paraout.(fn{ii}) = defpara.(fn{ii});
  182. end
  183. end
  184. else
  185. paraout = defpara;
  186. end
  187. % stimsize = [0+para.bmargin, 0+para.lmargin, para.screensize(1)-para.rmargin,...
  188. % para.screensize(2)-para.tmargin];
  189. xpixels = paraout.screensize(1) - (paraout.lmargin + paraout.rmargin);
  190. ypixels = paraout.screensize(2) - (paraout.tmargin + paraout.bmargin);
  191. paraout.Nx = ceil(xpixels / paraout.stixelwidth);
  192. paraout.Ny = ceil(ypixels / paraout.stixelheight);
  193. if paraout.stixelwidth > xpixels, paraout.stixelwidth = xpixels-1; end
  194. if paraout.stixelheight > ypixels, paraout.stixelheight = ypixels-1; end
  195. if paraout.fullscreen
  196. monitorsize = get(0,'ScreenSize');
  197. paraout.screensize = monitorsize(3:4) ;
  198. end
  199. end
  200. %--------------------------------------------------------------------------------------------------%
  201. function help_info_for_parameters(defpara)
  202. fn = fieldnames(defpara);
  203. fprintf(['\n\n',repmat('==',1,50),'\r\n']);
  204. fprintf([repmat(' ',1,35),'List of Stimulus Parameters\r\n']);
  205. fprintf([repmat('==',1,50),'\r\n']);
  206. maxtxtlen = max(cellfun(@numel,fn))+10;
  207. for ii = 1:numel(fn)
  208. g = repmat(' ',1,maxtxtlen - numel(fn{ii}));
  209. fprintf(['\t-- \t%s',g,':',repmat(' ',1,10),'%s\n'],fn{ii},num2str(defpara.(fn{ii})));
  210. end
  211. fprintf(['\n',repmat('==',1,50),'\r\n']);
  212. end