spm_eeg_convert2images.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. function [images, outroot] = spm_eeg_convert2images(S)
  2. % Convert M/EEG data to images for statistical analysis
  3. % FORMAT [images, outroot] = spm_eeg_convert2images(S)
  4. %
  5. % S - input structure (optional)
  6. % fields of S:
  7. % D - MEEG object or filename of M/EEG mat-file with
  8. % epoched data
  9. %
  10. % mode - type of images to generate one of:
  11. % 'scalp x time'
  12. % 'scalp x frequency' (average over time)
  13. % 'scalp' (average over time and frequency)
  14. % 'source' (average over time and frequency)
  15. % 'time x frequency' (average over channels)
  16. % 'time' (1D average over channels, frequency)
  17. % 'frequency' (1D average over channels, time)
  18. % 'average' (average over all dimensions to get a single
  19. % number)
  20. %
  21. % conditions - cell array of condition labels (default: convert all
  22. % conditions)
  23. % timewin - time window to retain (in PST ms)
  24. % freqwin - frequency window to retain (for TF datasets)
  25. % channels - cell array of channel labels, modality or 'all'.
  26. %
  27. % prefix - prefix for the folder containing the images (default: none)
  28. %
  29. % output:
  30. % images - list of generated image files or objects
  31. %__________________________________________________________________________
  32. % Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging
  33. % Vladimir Litvak, James Kilner, Stefan Kiebel
  34. % $Id: spm_eeg_convert2images.m 7125 2017-06-23 09:49:29Z guillaume $
  35. SVNrev = '$Rev: 7125 $';
  36. %-Startup
  37. %--------------------------------------------------------------------------
  38. spm('FnBanner', mfilename, SVNrev);
  39. spm('FigName','M/EEG conversion setup'); spm('Pointer','Watch');
  40. if ~isfield(S, 'timewin'), S.timewin = [-Inf Inf]; end
  41. if ~isfield(S, 'freqwin'), S.freqwin = [-Inf Inf]; end
  42. if ~isfield(S, 'channels'), S.channels = 'all'; end
  43. if ~isfield(S, 'prefix'), S.prefix = ''; end
  44. D = spm_eeg_load(S.D);
  45. if ~isfield(S, 'conditions') || isempty(S.conditions), S.conditions = D.condlist; end
  46. if ~iscell(S.conditions), S.conditions = {S.conditions}; end
  47. if strcmp(D.type, 'continuous')
  48. error('Continuous data are not supported');
  49. end
  50. isTF = strncmpi(D.transformtype,'TF',2);
  51. timeind = D.indsample(1e-3*(min(S.timewin))):D.indsample(1e-3*(max(S.timewin)));
  52. if isempty(timeind) || any(isnan(timeind))
  53. error('Selected time window is invalid.');
  54. end
  55. if isTF
  56. freqind = D.indfrequency(min(S.freqwin)):D.indfrequency(max(S.freqwin));
  57. if isempty(freqind) || any(isnan(freqind))
  58. error('Selected frequency window is invalid.');
  59. end
  60. freqonset = D.frequencies(freqind(1));
  61. df = unique(diff(D.frequencies(freqind)));
  62. if length(df)> 1
  63. if (max(diff(df))/mean(df))>0.1
  64. df = unique(diff(log(D.frequencies(freqind))));
  65. if (max(diff(df))/mean(df))>0.1
  66. error('Irregular frequency spacing');
  67. else
  68. freqonset = log(D.frequencies(freqind(1)));
  69. end
  70. end
  71. end
  72. df = mean(df);
  73. else
  74. df = 0;
  75. end
  76. isscalp = strncmpi('scalp', S.mode, 5);
  77. ismesh = false;
  78. chanind = setdiff(D.selectchannels(S.channels), D.badchannels);
  79. if isempty(chanind)
  80. error('No channels were selected');
  81. end
  82. modality = unique(D.chantype(chanind));
  83. if length(modality)>1
  84. error('All channels should be of the same type. Process each modality separately.');
  85. end
  86. if isequal(modality, 'MEGPLANAR') && isscalp
  87. error('Planar channels should be combined before creating scalp maps');
  88. end
  89. N = nifti;
  90. N.mat = eye(4);
  91. N.mat_intent = 'Aligned';
  92. C = [68 100]; % origin
  93. n = 32; % dimension (make the default from SPM8 constant here)
  94. V = [136 172]/n; % voxel size
  95. switch S.mode
  96. case 'scalp x time'
  97. avflag = [0 1 0];
  98. N.mat = [...
  99. V(1) 0 0 -C(1);...
  100. 0 V(2) 0 -C(2);...
  101. 0 0 1e3/D.fsample time(D, timeind(1), 'ms');...
  102. 0 0 0 1];
  103. N.mat(3,4) = N.mat(3,4) - N.mat(3,3);
  104. dat = file_array('', [n n length(timeind)], 'FLOAT32-LE');
  105. case 'scalp x frequency'
  106. if ~isTF
  107. error('This mode is only supported for TF datasets.');
  108. end
  109. avflag = [0 0 1];
  110. N.mat = [...
  111. V(1) 0 0 -C(1);...
  112. 0 V(2) 0 -C(2);...
  113. 0 0 df freqonset;...
  114. 0 0 0 1];
  115. N.mat(3,4) = N.mat(3,4) - N.mat(3,3);
  116. dat = file_array('', [n n length(freqind)], 'FLOAT32-LE');
  117. case 'scalp'
  118. avflag = [0 1 1];
  119. N.mat = [...
  120. V(1) 0 0 -C(1);...
  121. 0 V(2) 0 -C(2);...
  122. 0 0 1 1;...
  123. 0 0 0 1];
  124. N.mat(3,4) = N.mat(3,4) - N.mat(3,3);
  125. dat = file_array('', [n n], 'FLOAT32-LE');
  126. case 'source'
  127. avflag = [0 1 1];
  128. g = D.sensors('SRC');
  129. if ~isempty(g)
  130. g = gifti(g);
  131. ismesh = true;
  132. end
  133. if isempty(g) || size(g.vertices, 1) ~= length(chanind)
  134. error('The number of source channels should match the number of mesh vertices.');
  135. end
  136. case 'time x frequency'
  137. if ~isTF
  138. error('This mode is only supported for TF datasets.');
  139. end
  140. avflag = [1 0 0];
  141. N.mat = [...
  142. df 0 0 freqonset;...
  143. 0 1e3/D.fsample 0 time(D, timeind(1), 'ms');...
  144. 0 0 1 0;...
  145. 0 0 0 1];
  146. N.mat(1,4) = N.mat(1,4) - N.mat(1,1);
  147. N.mat(2,4) = N.mat(2,4) - N.mat(2,2);
  148. dat = file_array('', [length(freqind) length(timeind)], 'FLOAT32-LE');
  149. case 'time'
  150. avflag = [1 1 0];
  151. N.mat(1, 1) = 1e3/D.fsample;
  152. N.mat(1, 4) = time(D, timeind(1), 'ms') - N.mat(1, 1);
  153. dat = file_array('', [length(timeind) 1], 'FLOAT32-LE');
  154. case 'frequency'
  155. if ~isTF
  156. error('This mode is only supported for TF datasets.');
  157. end
  158. avflag = [1 0 1];
  159. N.mat(1, 1) = df;
  160. N.mat(1, 4) = freqonset - N.mat(1, 1);
  161. dat = file_array('', [length(freqind) 1], 'FLOAT32-LE');
  162. case 'average'
  163. avflag = [1 1 1];
  164. N.mat(1, 4) = time(D, timeind(1), 'ms');
  165. if isTF
  166. N.mat(2, 4) = freqonset;
  167. end
  168. dat = file_array('', [1 1], 'FLOAT32-LE');
  169. otherwise
  170. error('Unsupported mode.');
  171. end
  172. avflag = logical(avflag);
  173. if isTF
  174. dataind = {chanind, freqind, timeind};
  175. else
  176. avflag = avflag([1 3]);
  177. dataind = {chanind, timeind};
  178. end
  179. %-Create the output folder
  180. %--------------------------------------------------------------------------
  181. outroot = [S.prefix spm_file(D.fname, 'basename')];
  182. [sts, msg] = mkdir(D.path, outroot);
  183. if ~sts, error(msg); end
  184. outroot = fullfile(D.path, outroot);
  185. if isscalp
  186. [Cel, x, y] = spm_eeg_locate_channels(D, n, chanind);
  187. end
  188. images = {};
  189. ind = 1;
  190. for c = 1:numel(S.conditions)
  191. trialind = D.indtrial(S.conditions{c}, 'GOOD');
  192. if isempty(trialind)
  193. warning(['No good trials found for condition ' S.conditions{c}]);
  194. continue;
  195. end
  196. %-Make subdirectory for each condition
  197. %--------------------------------------------------------------------------
  198. condlabel = S.conditions{c};
  199. condlabel = condlabel(isstrprop(condlabel, 'alphanum') | ismember(condlabel, '_-'));
  200. if isempty(condlabel)
  201. condlabel = sprintf('condition%04d', c);
  202. end
  203. if ismesh
  204. res = mkdir(outroot, ['condition_' condlabel]);
  205. save(g, fullfile(outroot, ['condition_' condlabel], [spm_file(D.fname, 'basename'), '.surf.gii']));
  206. G = gifti;
  207. G.private.metadata(1).name = 'SurfaceID';
  208. G.private.metadata(1).value = fullfile(outroot, ['condition_' condlabel], [spm_file(D.fname, 'basename'), '.surf.gii']);
  209. else
  210. fname = fullfile(outroot, ['condition_' condlabel '.nii']);
  211. cdat = dat;
  212. cdat.fname = fname;
  213. cdat.dim = [dat.dim ones(1, 3-length(dat.dim)) length(trialind)];
  214. N.dat = cdat;
  215. create(N);
  216. end
  217. spm_progress_bar('Init', length(trialind),['Converting condition ',S.conditions{c}],'Trial');
  218. if length(trialind) > 100, Ibar = floor(linspace(1, length(trialind), 100)); else Ibar = 1:length(trialind); end
  219. for i = 1:length(trialind)
  220. Y = subsref(D, struct('type', '()', 'subs', {[dataind, {trialind(i)}]}));
  221. for m = sort(find(avflag), 1, 'descend')
  222. Y = mean(Y, m);
  223. end
  224. Y = squeeze(Y);
  225. if isscalp
  226. for j = 1:size(Y, 2)
  227. YY = NaN(n,n);
  228. YY(sub2ind([n n], x, y)) = griddata(Cel(:,1),Cel(:,2),...
  229. double(Y(:, j)), x, y,'linear');
  230. switch length(N.dat.dim)
  231. case 2
  232. N.dat(:,:) = YY;
  233. case 3
  234. N.dat(:,:, j) = YY;
  235. case 4
  236. N.dat(:,:,j,i) = YY;
  237. otherwise
  238. error('Invalid output file');
  239. end
  240. end
  241. images{ind} = [fname ',' num2str(i)];
  242. elseif ismesh
  243. fname = fullfile(outroot, ['condition_' condlabel], ['condition_' condlabel '_' sprintf('_%04d',trialind(i)) '.gii']);
  244. G.cdata = Y(:);
  245. save(G, fname, 'ExternalFileBinary');
  246. images{ind} = fname;
  247. else
  248. if size(Y, 1) == 1
  249. Y = Y';
  250. end
  251. N.dat(:, :, 1, i) = Y;
  252. images{ind} = [fname ',' num2str(i)];
  253. end
  254. ind = ind + 1;
  255. if ismember(i, Ibar), spm_progress_bar('Set', i); end
  256. end
  257. end
  258. images = images(:);
  259. %-Cleanup
  260. %--------------------------------------------------------------------------
  261. spm_progress_bar('Clear');
  262. fprintf('%-40s: %30s\n','Completed',spm('time')); %-#
  263. spm('FigName','M/EEG conversion: done'); spm('Pointer','Arrow');