spm_transverse.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. function spm_transverse(varargin)
  2. % Rendering of regional effects [SPM{T/F}] on transverse sections
  3. % FORMAT spm_transverse('set',SPM,hReg)
  4. % FORMAT spm_transverse('setcoords',xyzmm)
  5. % FORMAT spm_transverse('clear')
  6. %
  7. % SPM - structure containing SPM, distribution & filtering details
  8. % about the excursion set (xSPM)
  9. % - required fields are:
  10. % .Z - minimum of n Statistics {filtered on u and k}
  11. % .STAT - distribution {Z, T, X or F}
  12. % .u - height threshold
  13. % .XYZ - location of voxels {voxel coords}
  14. % .iM - mm -> voxels matrix
  15. % .VOX - voxel dimensions {mm}
  16. % .DIM - image dimensions {voxels}
  17. %
  18. % hReg - handle of MIP XYZ registry object (see spm_XYZreg for details)
  19. %
  20. % spm_transverse automatically updates its co-ordinates from the
  21. % registry, but clicking on the slices has no effect on the registry.
  22. % i.e., the updating is one way only.
  23. %
  24. % See also: spm_getSPM
  25. %__________________________________________________________________________
  26. %
  27. % spm_transverse is called by the SPM results section and uses
  28. % variables in SPM and SPM to create three transverse sections though a
  29. % background image. Regional foci from the selected SPM{T/F} are
  30. % rendered on this image.
  31. %
  32. % Although the SPM{.} adopts the neurological convention (left = left)
  33. % the rendered images follow the same convention as the original data.
  34. %__________________________________________________________________________
  35. % Copyright (C) 1994-2018 Wellcome Trust Centre for Neuroimaging
  36. % Karl Friston & John Ashburner
  37. % $Id: spm_transverse.m 7376 2018-07-20 10:30:59Z guillaume $
  38. switch lower(varargin{1})
  39. case 'set'
  40. % draw slices
  41. %----------------------------------------------------------------------
  42. init(varargin{2},varargin{3});
  43. case 'setcoords'
  44. % reposition
  45. %----------------------------------------------------------------------
  46. disp('Reposition');
  47. case 'clear'
  48. % clear
  49. %----------------------------------------------------------------------
  50. clear_global;
  51. end
  52. return;
  53. %==========================================================================
  54. % function init(SPM,hReg)
  55. %==========================================================================
  56. function init(SPM,hReg)
  57. %-Get figure handles
  58. %--------------------------------------------------------------------------
  59. Fgraph = spm_figure('GetWin','Graphics');
  60. %-Get the image on which to render
  61. %--------------------------------------------------------------------------
  62. [spms, sts] = spm_select(1,'image','Select image for rendering on');
  63. if ~sts, return; end
  64. spm('Pointer','Watch');
  65. %-Delete previous axis and their pagination controls (if any)
  66. %--------------------------------------------------------------------------
  67. spm_results_ui('Clear',Fgraph);
  68. global transv
  69. transv = struct('blob',[],'V',spm_vol(spms),'h',[],'hReg',hReg,'fig',Fgraph);
  70. transv.blob = struct('xyz', round(SPM.XYZ), 't',SPM.Z, 'dim',SPM.DIM(1:3),...
  71. 'iM',SPM.iM,...
  72. 'vox', sqrt(sum(SPM.M(1:3,1:3).^2)), 'u', SPM.u);
  73. %-Get current location and convert to pixel co-ordinates
  74. %--------------------------------------------------------------------------
  75. xyzmm = spm_XYZreg('GetCoords',transv.hReg);
  76. xyz = round(transv.blob.iM(1:3,:)*[xyzmm; 1]);
  77. try
  78. units = SPM.units;
  79. catch
  80. units = {'mm' 'mm' 'mm'};
  81. end
  82. %-Extract data from SPM [at one plane separation] and get background slices
  83. %--------------------------------------------------------------------------
  84. dim = ceil(transv.blob.dim(1:3)'.*transv.blob.vox);
  85. A = transv.blob.iM*transv.V.mat;
  86. hld = 0;
  87. zoomM = inv(spm_matrix([0 0 -1 0 0 0 transv.blob.vox([1 2]) 1]));
  88. zoomM1 = spm_matrix([0 0 0 0 0 0 transv.blob.vox([1 2]) 1]);
  89. Q = find(abs(transv.blob.xyz(3,:) - xyz(3)) < 0.5);
  90. T2 = full(sparse(transv.blob.xyz(1,Q),transv.blob.xyz(2,Q),transv.blob.t(Q),transv.blob.dim(1),transv.blob.dim(2)));
  91. T2 = spm_slice_vol(T2,zoomM,dim([1 2]),[hld NaN]);
  92. Q = find(T2==0) ; T2(Q) = NaN;
  93. D = zoomM1*[1 0 0 0;0 1 0 0;0 0 1 -xyz(3);0 0 0 1]*A;
  94. D2 = spm_slice_vol(transv.V,inv(D),dim([1 2]),1);
  95. maxD = max([max(D2(:)) eps]);
  96. minD = min([min(D2(:)) eps]);
  97. if transv.blob.dim(3) > 1
  98. Q = find(abs(transv.blob.xyz(3,:) - xyz(3)+1) < 0.5);
  99. T1 = full(sparse(transv.blob.xyz(1,Q),...
  100. transv.blob.xyz(2,Q),transv.blob.t(Q),transv.blob.dim(1),transv.blob.dim(2)));
  101. T1 = spm_slice_vol(T1,zoomM,dim([1 2]),[hld NaN]);
  102. Q = find(T1==0) ; T1(Q) = NaN;
  103. D = zoomM1*[1 0 0 0;0 1 0 0;0 0 1 -xyz(3)+1;0 0 0 1]*A;
  104. D1 = spm_slice_vol(transv.V,inv(D),dim([1 2]),1);
  105. maxD = max([maxD ; D1(:)]);
  106. minD = min([minD ; D1(:)]);
  107. Q = find(abs(transv.blob.xyz(3,:) - xyz(3)-1) < 0.5);
  108. T3 = full(sparse(transv.blob.xyz(1,Q),...
  109. transv.blob.xyz(2,Q),transv.blob.t(Q),transv.blob.dim(1),transv.blob.dim(2)));
  110. T3 = spm_slice_vol(T3,zoomM,dim([1 2]),[hld NaN]);
  111. Q = find(T3==0) ; T3(Q) = NaN;
  112. D = zoomM1*[1 0 0 0;0 1 0 0;0 0 1 -xyz(3)-1;0 0 0 1]*A;
  113. D3 = spm_slice_vol(transv.V,inv(D),dim([1 2]),1);
  114. maxD = max([maxD ; D3(:)]);
  115. minD = min([minD ; D3(:)]);
  116. end
  117. mx = max([max(T2(:)) eps]);
  118. mn = min([min(T2(:)) 0]);
  119. D2 = (D2-minD)/(maxD-minD);
  120. if transv.blob.dim(3) > 1,
  121. D1 = (D1-minD)/(maxD-minD);
  122. D3 = (D3-minD)/(maxD-minD);
  123. mx = max([mx ; T1(:) ; T3(:) ; eps]);
  124. mn = min([mn ; T1(:) ; T3(:) ; 0]);
  125. end;
  126. %-Configure {128 level} colormap
  127. %--------------------------------------------------------------------------
  128. cmap = get(Fgraph,'Colormap');
  129. if size(cmap,1) ~= 128
  130. figure(Fgraph);
  131. spm_colourmap('gray-hot');
  132. cmap = get(Fgraph,'Colormap');
  133. end
  134. D = length(cmap)/2;
  135. Q = find(T2(:) > transv.blob.u); T2 = (T2(Q)-mn)/(mx-mn); D2(Q) = 1+1.51/D + T2; T2 = D*D2;
  136. if transv.blob.dim(3) > 1
  137. Q = find(T1(:) > transv.blob.u); T1 = (T1(Q)-mn)/(mx-mn); D1(Q) = 1+1.51/D + T1; T1 = D*D1;
  138. Q = find(T3(:) > transv.blob.u); T3 = (T3(Q)-mn)/(mx-mn); D3(Q) = 1+1.51/D + T3; T3 = D*D3;
  139. end
  140. set(Fgraph,'Units','pixels')
  141. siz = get(Fgraph,'Position');
  142. siz = siz(3:4);
  143. P = xyz.*transv.blob.vox';
  144. %-Render activation foci on background images
  145. %--------------------------------------------------------------------------
  146. if transv.blob.dim(3) > 1
  147. zm = min([(siz(1) - 120)/(dim(1)*3),(siz(2)/2 - 60)/dim(2)]);
  148. xo = (siz(1)-(dim(1)*zm*3)-120)/2;
  149. yo = (siz(2)/2 - dim(2)*zm - 60)/2;
  150. transv.h(1) = axes('Units','pixels','Parent',Fgraph,'Position',[20+xo 20+yo dim(1)*zm dim(2)*zm]);
  151. transv.h(2) = image(rot90(spm_grid(T1)),'Parent',transv.h(1));
  152. axis image; axis off;
  153. tmp = SPM.iM\[xyz(1:2)' (xyz(3)-1) 1]';
  154. ax=transv.h(1);tpoint=get(ax,'title');
  155. str=sprintf('z = %0.0f%s',tmp(3),units{3});
  156. set(tpoint,'string',str);
  157. transv.h(3) = line([1 1]*P(1),[0 dim(2)],'Color','w','Parent',transv.h(1));
  158. transv.h(4) = line([0 dim(1)],[1 1]*(dim(2)-P(2)+1),'Color','w','Parent',transv.h(1));
  159. transv.h(5) = axes('Units','pixels','Parent',Fgraph,'Position',[40+dim(1)*zm+xo 20+yo dim(1)*zm dim(2)*zm]);
  160. transv.h(6) = image(rot90(spm_grid(T2)),'Parent',transv.h(5));
  161. axis image; axis off;
  162. tmp = SPM.iM\[xyz(1:2)' xyz(3) 1]';
  163. ax=transv.h(5);tpoint=get(ax,'title');
  164. str=sprintf('z = %0.0f%s',tmp(3),units{3});
  165. set(tpoint,'string',str);
  166. transv.h(7) = line([1 1]*P(1),[0 dim(2)],'Color','w','Parent',transv.h(5));
  167. transv.h(8) = line([0 dim(1)],[1 1]*(dim(2)-P(2)+1),'Color','w','Parent',transv.h(5));
  168. transv.h(9) = axes('Units','pixels','Parent',Fgraph,'Position',[60+dim(1)*zm*2+xo 20+yo dim(1)*zm dim(2)*zm]);
  169. transv.h(10) = image(rot90(spm_grid(T3)),'Parent',transv.h(9));
  170. axis image; axis off;
  171. tmp = SPM.iM\[xyz(1:2)' (xyz(3)+1) 1]';
  172. ax=transv.h(9);tpoint=get(ax,'title');
  173. str=sprintf('z = %0.0f%s',tmp(3),units{3});
  174. set(tpoint,'string',str);
  175. transv.h(11) = line([1 1]*P(1),[0 dim(2)],'Color','w','Parent',transv.h(9));
  176. transv.h(12) = line([0 dim(1)],[1 1]*(dim(2)-P(2)+1),'Color','w','Parent',transv.h(9));
  177. % colorbar
  178. %----------------------------------------------------------------------
  179. q = [80+dim(1)*zm*3+xo 20+yo 20 dim(2)*zm];
  180. if SPM.STAT=='P'
  181. str='Effect size';
  182. else
  183. str=[SPM.STAT ' value'];
  184. end
  185. transv.h(13) = axes('Units','pixels','Parent',Fgraph,'Position',q,'Visible','off');
  186. transv.h(14) = image([0 mx/32],[mn mx],(1:D)' + D,'Parent',transv.h(13));
  187. ax=transv.h(13);
  188. tpoint=get(ax,'title');
  189. set(tpoint,'string',str);
  190. set(tpoint,'FontSize',9);
  191. %title(ax,str,'FontSize',9);
  192. set(ax,'XTickLabel',[]);
  193. axis(ax,'xy');
  194. else
  195. zm = min([(siz(1) - 80)/dim(1),(siz(2)/2 - 60)/dim(2)]);
  196. xo = (siz(1)-(dim(1)*zm)-80)/2;
  197. yo = (siz(2)/2 - dim(2)*zm - 60)/2;
  198. transv.h(1) = axes('Units','pixels','Parent',Fgraph,'Position',[20+xo 20+yo dim(1)*zm dim(2)*zm]);
  199. transv.h(2) = image(rot90(spm_grid(T2)),'Parent',transv.h(1));
  200. axis image; axis off;
  201. title(sprintf('z = %0.0f%s',xyzmm(3),units{3}));
  202. transv.h(3) = line([1 1]*P(1),[0 dim(2)],'Color','w','Parent',transv.h(1));
  203. transv.h(4) = line([0 dim(1)],[1 1]*(dim(2)-P(2)+1),'Color','w','Parent',transv.h(1));
  204. % colorbar
  205. %----------------------------------------------------------------------
  206. q = [40+dim(1)*zm+xo 20+yo 20 dim(2)*zm];
  207. transv.h(5) = axes('Units','pixels','Parent',Fgraph,'Position',q,'Visible','off');
  208. transv.h(6) = image([0 mx/32],[mn mx],(1:D)' + D,'Parent',transv.h(5));
  209. if SPM.STAT=='P'
  210. str='Effect size';
  211. else
  212. str=[SPM.STAT ' value'];
  213. end
  214. title(str,'FontSize',9);
  215. set(gca,'XTickLabel',[]);
  216. axis xy;
  217. end
  218. spm_XYZreg('Add2Reg',transv.hReg,transv.h(1), 'spm_transverse');
  219. for h=transv.h,
  220. set(h,'DeleteFcn',@clear_global);
  221. end
  222. %-Reset pointer
  223. %--------------------------------------------------------------------------
  224. spm('Pointer','Arrow')
  225. return;
  226. %==========================================================================
  227. % function reposition(xyzmm)
  228. %==========================================================================
  229. function reposition(xyzmm)
  230. global transv
  231. if ~isstruct(transv), return; end;
  232. spm('Pointer','Watch');
  233. %-Get current location and convert to pixel co-ordinates
  234. %--------------------------------------------------------------------------
  235. % xyzmm = spm_XYZreg('GetCoords',transv.hReg)
  236. xyz = round(transv.blob.iM(1:3,:)*[xyzmm; 1]);
  237. % extract data from SPM [at one plane separation]
  238. % and get background slices
  239. %--------------------------------------------------------------------------
  240. dim = ceil(transv.blob.dim(1:3)'.*transv.blob.vox);
  241. A = transv.blob.iM*transv.V.mat;
  242. hld = 0;
  243. zoomM = inv(spm_matrix([0 0 -1 0 0 0 transv.blob.vox([1 2]) 1]));
  244. zoomM1 = spm_matrix([0 0 0 0 0 0 transv.blob.vox([1 2]) 1]);
  245. Q = find(abs(transv.blob.xyz(3,:) - xyz(3)) < 0.5);
  246. T2 = full(sparse(transv.blob.xyz(1,Q),transv.blob.xyz(2,Q),transv.blob.t(Q),transv.blob.dim(1),transv.blob.dim(2)));
  247. T2 = spm_slice_vol(T2,zoomM,dim([1 2]),[hld NaN]);
  248. Q = find(T2==0) ; T2(Q) = NaN;
  249. D = zoomM1*[1 0 0 0;0 1 0 0;0 0 1 -xyz(3);0 0 0 1]*A;
  250. D2 = spm_slice_vol(transv.V,inv(D),dim([1 2]),1);
  251. maxD = max([max(D2(:)) eps]);
  252. minD = min([min(D2(:)) 0]);
  253. if transv.blob.dim(3) > 1
  254. Q = find(abs(transv.blob.xyz(3,:) - xyz(3)+1) < 0.5);
  255. T1 = full(sparse(transv.blob.xyz(1,Q),...
  256. transv.blob.xyz(2,Q),transv.blob.t(Q),transv.blob.dim(1),transv.blob.dim(2)));
  257. T1 = spm_slice_vol(T1,zoomM,dim([1 2]),[hld NaN]);
  258. Q = find(T1==0) ; T1(Q) = NaN;
  259. D = zoomM1*[1 0 0 0;0 1 0 0;0 0 1 -xyz(3)+1;0 0 0 1]*A;
  260. D1 = spm_slice_vol(transv.V,inv(D),dim([1 2]),1);
  261. maxD = max([maxD ; D1(:)]);
  262. minD = min([minD ; D1(:)]);
  263. Q = find(abs(transv.blob.xyz(3,:) - xyz(3)-1) < 0.5);
  264. T3 = full(sparse(transv.blob.xyz(1,Q),...
  265. transv.blob.xyz(2,Q),transv.blob.t(Q),transv.blob.dim(1),transv.blob.dim(2)));
  266. T3 = spm_slice_vol(T3,zoomM,dim([1 2]),[hld NaN]);
  267. Q = find(T3==0) ; T3(Q) = NaN;
  268. D = zoomM1*[1 0 0 0;0 1 0 0;0 0 1 -xyz(3)-1;0 0 0 1]*A;
  269. D3 = spm_slice_vol(transv.V,inv(D),dim([1 2]),1);
  270. maxD = max([maxD ; D3(:)]);
  271. minD = min([minD ; D3(:)]);
  272. end
  273. mx = max([max(T2(:)) eps]);
  274. mn = min([min(T2(:)) 0]);
  275. D2 = (D2-minD)/(maxD-minD);
  276. if transv.blob.dim(3) > 1,
  277. D1 = (D1-minD)/(maxD-minD);
  278. D3 = (D3-minD)/(maxD-minD);
  279. mx = max([mx ; T1(:) ; T3(:) ; eps]);
  280. mn = min([mn ; T1(:) ; T3(:) ; 0]);
  281. end;
  282. %-Configure {128 level} colormap
  283. %--------------------------------------------------------------------------
  284. cmap = get(transv.fig,'Colormap');
  285. if size(cmap,1) ~= 128
  286. figure(transv.fig);
  287. spm_colourmap('gray-hot');
  288. cmap = get(transv.fig,'Colormap');
  289. end
  290. D = length(cmap)/2;
  291. Q = find(T2(:) > transv.blob.u); T2 = (T2(Q)-mn)/(mx-mn); D2(Q) = 1+1.51/D + T2; T2 = D*D2;
  292. if transv.blob.dim(3) > 1
  293. Q = find(T1(:) > transv.blob.u); T1 = (T1(Q)-mn)/(mx-mn); D1(Q) = 1+1.51/D + T1; T1 = D*D1;
  294. Q = find(T3(:) > transv.blob.u); T3 = (T3(Q)-mn)/(mx-mn); D3(Q) = 1+1.51/D + T3; T3 = D*D3;
  295. end
  296. P = xyz.*transv.blob.vox';
  297. %-Render activation foci on background images
  298. %--------------------------------------------------------------------------
  299. if transv.blob.dim(3) > 1
  300. set(transv.h(2),'Cdata',rot90(spm_grid(T1)));
  301. tmp = transv.blob.iM\[xyz(1:2)' (xyz(3)-1) 1]';
  302. set(get(transv.h(1),'Title'),'String',sprintf('z = %0.0fmm',tmp(3)));
  303. set(transv.h(3),'Xdata',[1 1]*P(1),'Ydata',[0 dim(2)]);
  304. set(transv.h(4),'Xdata',[0 dim(1)],'Ydata',[1 1]*(dim(2)-P(2)+1));
  305. set(transv.h(6),'Cdata',rot90(spm_grid(T2)));
  306. set(get(transv.h(5),'Title'),'String',sprintf('z = %0.0fmm',xyzmm(3)));
  307. set(transv.h(7),'Xdata',[1 1]*P(1),'Ydata',[0 dim(2)]);
  308. set(transv.h(8),'Xdata',[0 dim(1)],'Ydata',[1 1]*(dim(2)-P(2)+1));
  309. set(transv.h(10),'Cdata',rot90(spm_grid(T3)));
  310. tmp = transv.blob.iM\[xyz(1:2)' (xyz(3)+1) 1]';
  311. set(get(transv.h(9),'Title'),'String',sprintf('z = %0.0fmm',tmp(3)));
  312. set(transv.h(11),'Xdata',[1 1]*P(1),'Ydata',[0 dim(2)]);
  313. set(transv.h(12),'Xdata',[0 dim(1)],'Ydata',[1 1]*(dim(2)-P(2)+1));
  314. % colorbar
  315. %----------------------------------------------------------------------
  316. set(transv.h(14), 'Ydata',[mn mx], 'Cdata',(1:D)' + D);
  317. set(transv.h(13),'XTickLabel',[],'Ylim',[mn mx]);
  318. else
  319. set(transv.h(2),'Cdata',rot90(spm_grid(T2)));
  320. set(get(transv.h(1),'Title'),'String',sprintf('z = %0.0fmm',xyzmm(3)));
  321. set(transv.h(3),'Xdata',[1 1]*P(1),'Ydata',[0 dim(2)]);
  322. set(transv.h(4),'Xdata',[0 dim(1)],'Ydata',[1 1]*(dim(2)-P(2)+1));
  323. % colorbar
  324. %----------------------------------------------------------------------
  325. set(transv.h(6), 'Ydata',[0 d], 'Cdata',(1:D)' + D);
  326. set(transv.h(5),'XTickLabel',[],'Ylim',[0 d]);
  327. end
  328. %-Reset pointer
  329. %--------------------------------------------------------------------------
  330. spm('Pointer','Arrow')
  331. return;
  332. %==========================================================================
  333. % function clear_global(varargin)
  334. %==========================================================================
  335. function clear_global(varargin)
  336. global transv
  337. if isstruct(transv),
  338. for h = transv.h,
  339. if ishandle(h), set(h,'DeleteFcn',''); end;
  340. end
  341. for h = transv.h,
  342. if ishandle(h), delete(h); end;
  343. end
  344. transv = [];
  345. clear global transv;
  346. end
  347. return;