spm_deformations.m 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. function out = spm_deformations(job)
  2. % Various deformation field utilities
  3. % FORMAT out = spm_deformations(job)
  4. % job - a job created via spm_cfg_deformations.m
  5. % out - a struct with fields
  6. % .def - file name of created deformation field
  7. % .warped - file names of warped images
  8. %
  9. % See spm_cfg_deformations.m for more information.
  10. %__________________________________________________________________________
  11. % Copyright (C) 2005-2015 Wellcome Trust Centre for Neuroimaging
  12. % John Ashburner
  13. % $Id: spm_deformations.m 6577 2015-10-15 15:22:11Z volkmar $
  14. [Def,mat] = get_comp(job.comp);
  15. out = struct('def',{{}},'warped',{{}},'surf',{{}},'jac',{{}});
  16. for i=1:numel(job.out)
  17. fn = fieldnames(job.out{i});
  18. fn = fn{1};
  19. switch fn
  20. case 'savedef'
  21. out.def = [out.def; save_def(Def,mat,job.out{i}.(fn))];
  22. case 'pull'
  23. out.warped = [out.warped; pull_def(Def,mat,job.out{i}.(fn))];
  24. case 'push'
  25. out.warped = [out.warped; push_def(Def,mat,job.out{i}.(fn))];
  26. case 'surf'
  27. out.surf = [out.surf; surf_def(Def,mat,job.out{i}.(fn))];
  28. case 'savejac'
  29. out.jac = [out.jac; jac_def(Def,mat,job.out{i}.(fn))];
  30. otherwise
  31. error('Unknown option');
  32. end
  33. end
  34. %==========================================================================
  35. % function [Def,mat] = get_comp(job)
  36. %==========================================================================
  37. function [Def,mat] = get_comp(job)
  38. % Return the composition of a number of deformation fields.
  39. if isempty(job)
  40. error('Empty list of jobs in composition');
  41. end
  42. [Def,mat] = get_job(job{1});
  43. for i=2:numel(job)
  44. Def1 = Def;
  45. mat1 = mat;
  46. [Def,mat] = get_job(job{i});
  47. M = inv(mat1);
  48. tmp = zeros(size(Def),'single');
  49. tmp(:,:,:,1) = M(1,1)*Def(:,:,:,1)+M(1,2)*Def(:,:,:,2)+M(1,3)*Def(:,:,:,3)+M(1,4);
  50. tmp(:,:,:,2) = M(2,1)*Def(:,:,:,1)+M(2,2)*Def(:,:,:,2)+M(2,3)*Def(:,:,:,3)+M(2,4);
  51. tmp(:,:,:,3) = M(3,1)*Def(:,:,:,1)+M(3,2)*Def(:,:,:,2)+M(3,3)*Def(:,:,:,3)+M(3,4);
  52. Def(:,:,:,1) = single(spm_diffeo('bsplins',Def1(:,:,:,1),tmp,[1,1,1,0,0,0]));
  53. Def(:,:,:,2) = single(spm_diffeo('bsplins',Def1(:,:,:,2),tmp,[1,1,1,0,0,0]));
  54. Def(:,:,:,3) = single(spm_diffeo('bsplins',Def1(:,:,:,3),tmp,[1,1,1,0,0,0]));
  55. clear tmp
  56. end
  57. %==========================================================================
  58. % function [Def,mat] = get_job(job)
  59. %==========================================================================
  60. function [Def,mat] = get_job(job)
  61. % Determine what is required, and pass the relevant bit of the
  62. % job out to the appropriate function.
  63. fn = fieldnames(job);
  64. fn = fn{1};
  65. switch fn
  66. case {'comp'}
  67. [Def,mat] = get_comp(job.(fn));
  68. case {'def'}
  69. [Def,mat] = get_def(job.(fn));
  70. case {'dartel'}
  71. [Def,mat] = get_dartel(job.(fn));
  72. case {'sn2def'}
  73. [Def,mat] = get_sn2def(job.(fn));
  74. case {'inv'}
  75. [Def,mat] = get_inv(job.(fn));
  76. case {'id'}
  77. [Def,mat] = get_id(job.(fn));
  78. case {'idbbvox'}
  79. [Def,mat] = get_idbbvox(job.(fn));
  80. otherwise
  81. error('Unrecognised job type');
  82. end
  83. %==========================================================================
  84. % function [Def,mat] = get_sn2def(job)
  85. %==========================================================================
  86. function [Def,mat] = get_sn2def(job)
  87. % Convert a SPM _sn.mat file into a deformation field, and return it.
  88. vox = job.vox;
  89. bb = job.bb;
  90. sn = load(job.matname{1});
  91. if any(isfinite(bb(:))) || any(isfinite(vox))
  92. [bb0, vox0] = spm_get_bbox(sn.VG(1));
  93. if any(~isfinite(vox)), vox = vox0; end
  94. if any(~isfinite(bb)), bb = bb0; end
  95. bb = sort(bb);
  96. vox = abs(vox);
  97. % Adjust bounding box slightly - so it rounds to closest voxel.
  98. bb(:,1) = round(bb(:,1)/vox(1))*vox(1);
  99. bb(:,2) = round(bb(:,2)/vox(2))*vox(2);
  100. bb(:,3) = round(bb(:,3)/vox(3))*vox(3);
  101. M = sn.VG(1).mat;
  102. vxg = sqrt(sum(M(1:3,1:3).^2));
  103. ogn = M\[0 0 0 1]';
  104. ogn = ogn(1:3)';
  105. % Convert range into range of voxels within template image
  106. x = (bb(1,1):vox(1):bb(2,1))/vxg(1) + ogn(1);
  107. y = (bb(1,2):vox(2):bb(2,2))/vxg(2) + ogn(2);
  108. z = (bb(1,3):vox(3):bb(2,3))/vxg(3) + ogn(3);
  109. og = -vxg.*ogn;
  110. of = -vox.*(round(-bb(1,:)./vox)+1);
  111. M1 = [vxg(1) 0 0 og(1) ; 0 vxg(2) 0 og(2) ; 0 0 vxg(3) og(3) ; 0 0 0 1];
  112. M2 = [vox(1) 0 0 of(1) ; 0 vox(2) 0 of(2) ; 0 0 vox(3) of(3) ; 0 0 0 1];
  113. mat = sn.VG(1).mat*(M1\M2);
  114. % dim = [length(x) length(y) length(z)];
  115. else
  116. dim = sn.VG(1).dim;
  117. x = 1:dim(1);
  118. y = 1:dim(2);
  119. z = 1:dim(3);
  120. mat = sn.VG(1).mat;
  121. end
  122. [X,Y] = ndgrid(x,y);
  123. st = size(sn.Tr);
  124. if (prod(st) == 0)
  125. affine_only = true;
  126. basX = 0;
  127. basY = 0;
  128. basZ = 0;
  129. else
  130. affine_only = false;
  131. basX = spm_dctmtx(sn.VG(1).dim(1),st(1),x-1);
  132. basY = spm_dctmtx(sn.VG(1).dim(2),st(2),y-1);
  133. basZ = spm_dctmtx(sn.VG(1).dim(3),st(3),z-1);
  134. end
  135. Def = zeros([numel(x),numel(y),numel(z),3],'single');
  136. for j=1:length(z)
  137. if (~affine_only)
  138. tx = reshape( reshape(sn.Tr(:,:,:,1),st(1)*st(2),st(3)) *basZ(j,:)', st(1), st(2) );
  139. ty = reshape( reshape(sn.Tr(:,:,:,2),st(1)*st(2),st(3)) *basZ(j,:)', st(1), st(2) );
  140. tz = reshape( reshape(sn.Tr(:,:,:,3),st(1)*st(2),st(3)) *basZ(j,:)', st(1), st(2) );
  141. X1 = X + basX*tx*basY';
  142. Y1 = Y + basX*ty*basY';
  143. Z1 = z(j) + basX*tz*basY';
  144. end
  145. Mult = sn.VF.mat*sn.Affine;
  146. if (~affine_only)
  147. X2= Mult(1,1)*X1 + Mult(1,2)*Y1 + Mult(1,3)*Z1 + Mult(1,4);
  148. Y2= Mult(2,1)*X1 + Mult(2,2)*Y1 + Mult(2,3)*Z1 + Mult(2,4);
  149. Z2= Mult(3,1)*X1 + Mult(3,2)*Y1 + Mult(3,3)*Z1 + Mult(3,4);
  150. else
  151. X2= Mult(1,1)*X + Mult(1,2)*Y + (Mult(1,3)*z(j) + Mult(1,4));
  152. Y2= Mult(2,1)*X + Mult(2,2)*Y + (Mult(2,3)*z(j) + Mult(2,4));
  153. Z2= Mult(3,1)*X + Mult(3,2)*Y + (Mult(3,3)*z(j) + Mult(3,4));
  154. end
  155. Def(:,:,j,1) = single(X2);
  156. Def(:,:,j,2) = single(Y2);
  157. Def(:,:,j,3) = single(Z2);
  158. end
  159. %==========================================================================
  160. % function [Def,mat] = get_def(job)
  161. %==========================================================================
  162. function [Def,mat] = get_def(job)
  163. % Load a deformation field saved as an image
  164. Nii = nifti(job{1});
  165. Def = single(Nii.dat(:,:,:,1,:));
  166. d = size(Def);
  167. if d(4)~=1 || d(5)~=3, error('Deformation field is wrong!'); end
  168. Def = reshape(Def,[d(1:3) d(5)]);
  169. mat = Nii.mat;
  170. %==========================================================================
  171. % function [Def,mat] = get_dartel(job)
  172. %==========================================================================
  173. function [Def,mat] = get_dartel(job)
  174. Nii = nifti(job.flowfield{1});
  175. if ~isempty(job.template{1})
  176. %Nt = nifti(job.template{1});
  177. [pth,nam] = fileparts(job.template{1});
  178. if exist(fullfile(pth,[nam '_2mni.mat']),'file')
  179. load(fullfile(pth,[nam '_2mni.mat']),'mni');
  180. else
  181. % Affine registration of Dartel Template with MNI space.
  182. %------------------------------------------------------------------
  183. fprintf('** Affine registering "%s" with MNI space **\n', nam);
  184. tpm = fullfile(spm('Dir'),'tpm','TPM.nii');
  185. Mmni = spm_get_space(tpm);
  186. Nt = nifti(job.template{1});
  187. mni.affine = Mmni/spm_klaff(Nt,tpm);
  188. mni.code = 'MNI152';
  189. save(fullfile(pth,[nam '_2mni.mat']),'mni', spm_get_defaults('mat.format'));
  190. end
  191. Mat = mni.affine;
  192. %do_aff = true;
  193. else
  194. Mat = Nii.mat;
  195. %do_aff = false;
  196. end
  197. % Integrate a Dartel flow field
  198. y0 = spm_dartel_integrate(Nii.dat,job.times,job.K);
  199. if all(job.times == [0 1]),
  200. mat = Nii.mat0;
  201. Def = affine(y0,single(Mat));
  202. else
  203. mat = Mat;
  204. Def = affine(y0,single(Nii.mat0));
  205. end
  206. %==========================================================================
  207. % function [Def,mat] = get_id(job)
  208. %==========================================================================
  209. function [Def,mat] = get_id(job)
  210. % Get an identity transform based on an image volume
  211. [mat, dim] = spm_get_matdim(job.space{1});
  212. Def = identity(dim, mat);
  213. %==========================================================================
  214. % function [Def,mat] = get_idbbvox(job)
  215. %==========================================================================
  216. function [Def,mat] = get_idbbvox(job)
  217. % Get an identity transform based on bounding box and voxel size.
  218. % This will produce a transversal image.
  219. [mat, dim] = spm_get_matdim('', job.vox, job.bb);
  220. Def = identity(dim, mat);
  221. %==========================================================================
  222. % function [Def,mat] = get_inv(job)
  223. %==========================================================================
  224. function [Def,mat] = get_inv(job)
  225. % Invert a deformation field (derived from a composition of deformations)
  226. NT = nifti(job.space{:});
  227. [Def0,mat0] = get_comp(job.comp);
  228. M0 = mat0;
  229. M1 = inv(NT.mat);
  230. M0(4,:) = [0 0 0 1];
  231. M1(4,:) = [0 0 0 1];
  232. Def = spm_diffeo('invdef',Def0,NT.dat.dim(1:3),M1,M0);
  233. mat = NT.mat;
  234. Def = spm_extrapolate_def(Def,mat);
  235. %==========================================================================
  236. % function fname = save_def(Def,mat,job)
  237. %==========================================================================
  238. function fname = save_def(Def,mat,job)
  239. % Save a deformation field as an image
  240. ofname = job.ofname;
  241. if isempty(ofname), fname = {}; return; end;
  242. [pth,nam] = fileparts(ofname);
  243. if isfield(job.savedir,'savepwd')
  244. wd = pwd;
  245. elseif isfield(job.savedir,'saveusr')
  246. wd = job.savedir.saveusr{1};
  247. else
  248. wd = pwd;
  249. end
  250. fname = {fullfile(wd,['y_' nam '.nii'])};
  251. dim = [size(Def,1) size(Def,2) size(Def,3) 1 3];
  252. dtype = 'FLOAT32-LE';
  253. off = 0;
  254. scale = 1;
  255. inter = 0;
  256. dat = file_array(fname{1},dim,dtype,off,scale,inter);
  257. N = nifti;
  258. N.dat = dat;
  259. N.mat = mat;
  260. N.mat0 = mat;
  261. N.mat_intent = 'Aligned';
  262. N.mat0_intent = 'Aligned';
  263. N.intent.code = 'VECTOR';
  264. N.intent.name = 'Mapping';
  265. N.descrip = 'Deformation field';
  266. create(N);
  267. N.dat(:,:,:,1,1) = Def(:,:,:,1);
  268. N.dat(:,:,:,1,2) = Def(:,:,:,2);
  269. N.dat(:,:,:,1,3) = Def(:,:,:,3);
  270. %==========================================================================
  271. % function fname = jac_def(Def,mat,job)
  272. %==========================================================================
  273. function fname = jac_def(Def,mat,job)
  274. % Save Jacobian determinants of deformation field
  275. ofname = job.ofname;
  276. if isempty(ofname), fname = {}; return; end;
  277. [pth,nam] = fileparts(ofname);
  278. if isfield(job.savedir,'savepwd')
  279. wd = pwd;
  280. elseif isfield(job.savedir,'saveusr')
  281. wd = job.savedir.saveusr{1};
  282. else
  283. wd = pwd;
  284. end
  285. Dets = spm_diffeo('def2det',Def)/det(mat(1:3,1:3));
  286. Dets(:,:,[1 end]) = NaN;
  287. Dets(:,[1 end],:) = NaN;
  288. Dets([1 end],:,:) = NaN;
  289. fname = {fullfile(wd,['j_' nam '.nii'])};
  290. dim = [size(Def,1) size(Def,2) size(Def,3) 1 1];
  291. dtype = 'FLOAT32-LE';
  292. off = 0;
  293. scale = 1;
  294. inter = 0;
  295. dat = file_array(fname{1},dim,dtype,off,scale,inter);
  296. N = nifti;
  297. N.dat = dat;
  298. N.mat = mat;
  299. N.mat0 = mat;
  300. N.mat_intent = 'Aligned';
  301. N.mat0_intent = 'Aligned';
  302. N.intent.code = 0;
  303. N.intent.name = 'Mapping';
  304. N.descrip = 'Jacobian Determinants';
  305. create(N);
  306. N.dat(:,:,:,1,1) = Dets;
  307. %==========================================================================
  308. % function out = pull_def(Def,mat,job)
  309. %==========================================================================
  310. function out = pull_def(Def,mat,job)
  311. PI = job.fnames;
  312. intrp = job.interp;
  313. intrp = [intrp*[1 1 1], 0 0 0];
  314. out = cell(numel(PI),1);
  315. if numel(PI)==0, return; end
  316. if job.mask
  317. oM = zeros(4,4);
  318. odm = zeros(1,3);
  319. dim = size(Def);
  320. msk = true(dim);
  321. for m=1:numel(PI)
  322. [pth,nam,ext,num] = spm_fileparts(PI{m});
  323. NI = nifti(fullfile(pth,[nam ext]));
  324. dm = NI.dat.dim(1:3);
  325. if isempty(num)
  326. j_range = 1:size(NI.dat,4);
  327. else
  328. num = sscanf(num,',%d');
  329. j_range = num(1);
  330. end
  331. for j=j_range
  332. M0 = NI.mat;
  333. if ~isempty(NI.extras) && isstruct(NI.extras) && isfield(NI.extras,'mat')
  334. M1 = NI.extras.mat;
  335. if size(M1,3) >= j && sum(sum(M1(:,:,j).^2)) ~=0
  336. M0 = M1(:,:,j);
  337. end
  338. end
  339. M = inv(M0);
  340. if ~all(M(:)==oM(:)) || ~all(dm==odm)
  341. tmp = affine(Def,M);
  342. msk = tmp(:,:,:,1)>=1 & tmp(:,:,:,1)<=size(NI.dat,1) ...
  343. & tmp(:,:,:,2)>=1 & tmp(:,:,:,2)<=size(NI.dat,2) ...
  344. & tmp(:,:,:,3)>=1 & tmp(:,:,:,3)<=size(NI.dat,3);
  345. end
  346. oM = M;
  347. odm = dm;
  348. end
  349. end
  350. end
  351. oM = zeros(4,4);
  352. spm_progress_bar('Init',numel(PI),'Resampling','volumes completed');
  353. for m=1:numel(PI)
  354. % Generate headers etc for output images
  355. %----------------------------------------------------------------------
  356. [pth,nam,ext,num] = spm_fileparts(PI{m});
  357. NI = nifti(fullfile(pth,[nam ext]));
  358. j_range = 1:size(NI.dat,4);
  359. k_range = 1:size(NI.dat,5);
  360. l_range = 1:size(NI.dat,6);
  361. if ~isempty(num)
  362. num = sscanf(num,',%d');
  363. if numel(num)>=1, j_range = num(1); end
  364. if numel(num)>=2, k_range = num(2); end
  365. if numel(num)>=3, l_range = num(3); end
  366. end
  367. NO = NI;
  368. if isfield(job.savedir,'savepwd')
  369. wd = pwd;
  370. elseif isfield(job.savedir,'saveusr')
  371. wd = job.savedir.saveusr{1};
  372. elseif isfield(job.savedir,'savesrc')
  373. wd = pth;
  374. else
  375. wd = pwd;
  376. end
  377. if sum(job.fwhm.^2)==0
  378. newprefix = spm_get_defaults('normalise.write.prefix');
  379. NO.descrip = sprintf('Warped');
  380. else
  381. newprefix = [spm_get_defaults('smooth.prefix') spm_get_defaults('normalise.write.prefix')];
  382. NO.descrip = sprintf('Smoothed (%gx%gx%g subopt) warped',job.fwhm);
  383. end
  384. if isfield(job,'prefix') && ~isempty(job.prefix)
  385. NO.dat.fname = fullfile(wd,[job.prefix nam ext]);
  386. else
  387. NO.dat.fname = fullfile(wd,[newprefix nam ext]);
  388. end
  389. dim = size(Def);
  390. dim = dim(1:3);
  391. NO.dat.dim = [dim NI.dat.dim(4:end)];
  392. NO.dat.offset = 0; % For situations where input .nii images have an extension.
  393. NO.mat = mat;
  394. NO.mat0 = mat;
  395. NO.mat_intent = 'Aligned';
  396. NO.mat0_intent = 'Aligned';
  397. if isempty(num)
  398. out{m} = NO.dat.fname;
  399. else
  400. out{m} = [NO.dat.fname, ',', num2str(num(1))];
  401. end
  402. NO.extras = [];
  403. create(NO);
  404. % Smoothing settings
  405. vx = sqrt(sum(mat(1:3,1:3).^2));
  406. krn = max(job.fwhm./vx,0.25);
  407. % Loop over volumes within the file
  408. %----------------------------------------------------------------------
  409. %fprintf('%s',nam);
  410. for j=j_range
  411. M0 = NI.mat;
  412. if ~isempty(NI.extras) && isstruct(NI.extras) && isfield(NI.extras,'mat')
  413. M1 = NI.extras.mat;
  414. if size(M1,3) >= j && sum(sum(M1(:,:,j).^2)) ~=0
  415. M0 = M1(:,:,j);
  416. end
  417. end
  418. M = inv(M0);
  419. if ~all(M(:)==oM(:))
  420. % Generate new deformation (if needed)
  421. Y = affine(Def,M);
  422. end
  423. oM = M;
  424. % Write the warped data for this time point
  425. %------------------------------------------------------------------
  426. for k=k_range
  427. for l=l_range
  428. C = spm_diffeo('bsplinc',single(NI.dat(:,:,:,j,k,l)),intrp);
  429. dat = spm_diffeo('bsplins',C,Y,intrp);
  430. if job.mask
  431. dat(~msk) = NaN;
  432. end
  433. if sum(job.fwhm.^2)~=0
  434. spm_smooth(dat,dat,krn); % Side effects
  435. end
  436. NO.dat(:,:,:,j,k,l) = dat;
  437. %fprintf('\t%d,%d,%d', j,k,l);
  438. end
  439. end
  440. end
  441. %fprintf('\n');
  442. spm_progress_bar('Set',m);
  443. end
  444. spm_progress_bar('Clear');
  445. %==========================================================================
  446. % function out = push_def(Def,mat,job)
  447. %==========================================================================
  448. function out = push_def(Def,mat,job)
  449. % Generate deformation, which is the inverse of the usual one (it is for "pushing"
  450. % rather than the usual "pulling"). This deformation is affine transformed to
  451. % allow for different voxel sizes and bounding boxes, and also to incorporate
  452. % the affine mapping between MNI space and the population average shape.
  453. %--------------------------------------------------------------------------
  454. % Deal with desired bounding box and voxel sizes.
  455. %--------------------------------------------------------------------------
  456. if isfield(job.fov,'file')
  457. N1 = nifti(job.fov.file);
  458. mat0 = N1.mat;
  459. dim = N1.dat.dim(1:3);
  460. else
  461. bb = job.fov.bbvox.bb;
  462. vox = job.fov.bbvox.vox;
  463. [mat0, dim] = spm_get_matdim('', vox, bb);
  464. end
  465. M = inv(mat0);
  466. y0 = affine(Def,M);
  467. if isfield(job,'weight') && ~isempty(job.weight) && ~isempty(job.weight{1})
  468. wfile = job.weight{1};
  469. Nw = nifti(wfile);
  470. Mw = Nw.mat;
  471. wt = Nw.dat(:,:,:,1,1,1);
  472. else
  473. wt = [];
  474. end
  475. odm = zeros(1,3);
  476. oM = zeros(4,4);
  477. PI = job.fnames;
  478. out = cell(numel(PI),1);
  479. for m=1:numel(PI)
  480. % Generate headers etc for output images
  481. %----------------------------------------------------------------------
  482. [pth,nam,ext,num] = spm_fileparts(PI{m});
  483. NI = nifti(fullfile(pth,[nam ext]));
  484. j_range = 1:size(NI.dat,4);
  485. k_range = 1:size(NI.dat,5);
  486. l_range = 1:size(NI.dat,6);
  487. if ~isempty(num)
  488. num = sscanf(num,',%d');
  489. if numel(num)>=1, j_range = num(1); end
  490. if numel(num)>=2, k_range = num(2); end
  491. if numel(num)>=3, l_range = num(3); end
  492. end
  493. if isfield(job.savedir,'savepwd')
  494. wd = pwd;
  495. elseif isfield(job.savedir,'saveusr')
  496. wd = job.savedir.saveusr{1};
  497. elseif isfield(job.savedir,'savesrc')
  498. wd = pth;
  499. else
  500. wd = pwd;
  501. end
  502. NO = NI;
  503. if job.preserve
  504. NO.dat.scl_slope = 1.0;
  505. NO.dat.scl_inter = 0.0;
  506. NO.dat.dtype = 'float32-le';
  507. if sum(job.fwhm.^2)==0
  508. newprefix = [spm_get_defaults('deformations.modulate.prefix') spm_get_defaults('normalise.write.prefix')];
  509. NO.descrip = sprintf('Warped & Jac scaled');
  510. else
  511. newprefix = [spm_get_defaults('smooth.prefix') spm_get_defaults('deformations.modulate.prefix') spm_get_defaults('normalise.write.prefix')];
  512. NO.descrip = sprintf('Smoothed (%gx%gx%g) warped Jac scaled',job.fwhm);
  513. end
  514. else
  515. if sum(job.fwhm.^2)==0
  516. newprefix = spm_get_defaults('normalise.write.prefix');
  517. NO.descrip = sprintf('Warped');
  518. else
  519. newprefix = [spm_get_defaults('smooth.prefix') spm_get_defaults('normalise.write.prefix')];
  520. NO.descrip = sprintf('Smoothed (%gx%gx%g opt) warped',job.fwhm);
  521. end
  522. end
  523. if isfield(job,'prefix') && ~isempty(job.prefix)
  524. NO.dat.fname = fullfile(wd,[job.prefix nam ext]);
  525. else
  526. NO.dat.fname = fullfile(wd,[newprefix nam ext]);
  527. end
  528. NO.dat.dim = [dim NI.dat.dim(4:end)];
  529. NO.dat.offset = 0; % For situations where input .nii images have an extension.
  530. NO.mat = mat0;
  531. NO.mat0 = mat0;
  532. NO.mat_intent = 'Aligned';
  533. NO.mat0_intent = 'Aligned';
  534. if isempty(num)
  535. out{m} = NO.dat.fname;
  536. else
  537. out{m} = [NO.dat.fname, ',', num2str(num(1))];
  538. end
  539. NO.extras = [];
  540. create(NO);
  541. % Smoothing settings
  542. vx = sqrt(sum(mat0(1:3,1:3).^2));
  543. krn = max(job.fwhm./vx,0.25);
  544. % Loop over volumes within the file
  545. %----------------------------------------------------------------------
  546. fprintf('%s',nam); drawnow;
  547. for j=j_range
  548. % Need to resample the mapping by an affine transform
  549. % so that it maps from voxels in the native space image
  550. % to voxels in the spatially normalised image.
  551. %------------------------------------------------------------------
  552. M0 = NI.mat;
  553. if ~isempty(NI.extras) && isstruct(NI.extras) && isfield(NI.extras,'mat')
  554. M1 = NI.extras.mat;
  555. if size(M1,3) >= j && sum(sum(M1(:,:,j).^2)) ~=0
  556. M0 = M1(:,:,j);
  557. end
  558. end
  559. M = mat\M0;
  560. dm = [size(NI.dat),1,1,1,1];
  561. if ~all(dm(1:3)==odm) || ~all(M(:)==oM(:))
  562. % Generate new deformation (if needed)
  563. y = zeros([dm(1:3),3],'single');
  564. for d=1:3
  565. yd = y0(:,:,:,d);
  566. for x3=1:size(y,3)
  567. y(:,:,x3,d) = single(spm_slice_vol(yd,M*spm_matrix([0 0 x3]),dm(1:2),[1 NaN]));
  568. end
  569. end
  570. end
  571. odm = dm(1:3);
  572. oM = M;
  573. % Write the warped data for this time point.
  574. %------------------------------------------------------------------
  575. for k=k_range
  576. for l=l_range
  577. f = single(NI.dat(:,:,:,j,k,l));
  578. if isempty(wt)
  579. if ~job.preserve
  580. % Unmodulated - note the slightly novel procedure
  581. [f,c] = spm_diffeo('push',f,y,dim);
  582. spm_smooth(f,f,krn); % Side effects
  583. spm_smooth(c,c,krn); % Side effects
  584. f = f./(c+0.001);
  585. else
  586. % Modulated, by pushing
  587. scal = abs(det(NI.mat(1:3,1:3))/det(NO.mat(1:3,1:3))); % Account for vox sizes
  588. f = spm_diffeo('push',f,y,dim)*scal;
  589. spm_smooth(f,f,krn); % Side effects
  590. end
  591. else
  592. if isequal(size(wt),size(f)) && sum((Mw(:)-M0(:)).^2)<1e-6
  593. wtw = single(wt);
  594. f = single(f.*wt);
  595. else
  596. wtw = zeros(size(f),'single');
  597. for z=1:size(wt,3)
  598. Mz = Mw\M0*[1 0 0 0; 0 1 0 0; 0 0 1 z; 0 0 0 1];
  599. wtw(:,:,z) = single(spm_slice_vol(wt,Mz,[size(f,1),size(f,2)],1));
  600. end
  601. end
  602. if ~job.preserve
  603. % Unmodulated - note the slightly novel procedure
  604. f = spm_diffeo('push',f.*wtw,y,dim);
  605. c = spm_diffeo('push',wtw,y,dim);
  606. spm_smooth(f,f,krn); % Side effects
  607. spm_smooth(c,c,krn); % Side effects
  608. f = f./(c+0.001);
  609. else
  610. % Modulated, by pushing
  611. scal = abs(det(NI.mat(1:3,1:3))/det(NO.mat(1:3,1:3))); % Account for vox sizes
  612. f = spm_diffeo('push',f.*wtw,y,dim)*scal;
  613. spm_smooth(f,f,krn); % Side effects
  614. end
  615. clear wtw
  616. end
  617. NO.dat(:,:,:,j,k,l) = f;
  618. fprintf('\t%d,%d,%d', j,k,l); drawnow;
  619. end
  620. end
  621. end
  622. fprintf('\n'); drawnow;
  623. end
  624. %==========================================================================
  625. % function out = surf_def(Def,mat,job)
  626. %==========================================================================
  627. function out = surf_def(Def,mat,job)
  628. filenames = job.surface;
  629. out = cell(numel(filenames),1);
  630. for i=1:numel(filenames)
  631. fname = deblank(job.surface{i});
  632. [pth,nam] = fileparts(fname);
  633. fprintf('%s\n', nam);
  634. d = size(Def);
  635. tmp = double(reshape(Def,[d(1:3) 1 d(4)]));
  636. Tmesh = spm_swarp(fname, tmp,mat);
  637. if isfield(job.savedir,'savepwd')
  638. wd = pwd;
  639. elseif isfield(job.savedir,'saveusr')
  640. wd = job.savedir.saveusr{1};
  641. elseif isfield(job.savedir,'savesrc')
  642. wd = pth;
  643. else
  644. wd = pwd;
  645. end
  646. filename = fullfile(wd,[nam,'_warped', '.gii']);
  647. save(gifti(Tmesh), filename);
  648. out{i} = filename;
  649. end
  650. %==========================================================================
  651. % function Def = affine(y,M)
  652. %==========================================================================
  653. function Def = affine(y,M)
  654. Def = zeros(size(y),'single');
  655. Def(:,:,:,1) = y(:,:,:,1)*M(1,1) + y(:,:,:,2)*M(1,2) + y(:,:,:,3)*M(1,3) + M(1,4);
  656. Def(:,:,:,2) = y(:,:,:,1)*M(2,1) + y(:,:,:,2)*M(2,2) + y(:,:,:,3)*M(2,3) + M(2,4);
  657. Def(:,:,:,3) = y(:,:,:,1)*M(3,1) + y(:,:,:,2)*M(3,2) + y(:,:,:,3)*M(3,3) + M(3,4);
  658. %==========================================================================
  659. % function Def = identity(d,M)
  660. %==========================================================================
  661. function Def = identity(d,M)
  662. [y1,y2] = ndgrid(single(1:d(1)),single(1:d(2)));
  663. Def = zeros([d 3],'single');
  664. for y3=1:d(3)
  665. Def(:,:,y3,1) = y1*M(1,1) + y2*M(1,2) + (y3*M(1,3) + M(1,4));
  666. Def(:,:,y3,2) = y1*M(2,1) + y2*M(2,2) + (y3*M(2,3) + M(2,4));
  667. Def(:,:,y3,3) = y1*M(3,1) + y2*M(3,2) + (y3*M(3,3) + M(3,4));
  668. end