spm_imcalc.m 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. function Vo = spm_imcalc(Vi,Vo,f,flags,varargin)
  2. % Perform algebraic functions on images
  3. % FORMAT Vo = spm_imcalc(Vi, Vo, f [,flags [,extra_vars...]])
  4. % Vi - struct array (from spm_vol) of images to work on
  5. % or a char array of input image filenames
  6. % Vo (input) - struct array (from spm_vol) containing information on
  7. % output image
  8. % ( pinfo field is computed for the resultant image data, )
  9. % ( and can be omitted from Vo on input. See spm_vol )
  10. % or output image filename
  11. % f - MATLAB expression to be evaluated
  12. % flags - cell array of flags: {dmtx,mask,interp,dtype,descrip}
  13. % or structure with these fieldnames
  14. % dmtx - read images into data matrix?
  15. % [defaults (missing or empty) to 0 - no]
  16. % mask - implicit zero mask?
  17. % [defaults (missing or empty) to 0 - no]
  18. % ( negative value implies NaNs should be zeroed )
  19. % interp - interpolation hold (see spm_slice_vol)
  20. % [defaults (missing or empty) to 0 - nearest neighbour]
  21. % dtype - data type for output image (see spm_type)
  22. % [defaults (missing or empty) to 4 - 16 bit signed shorts]
  23. % descrip - content of the 'descrip' field of the NIfTI header
  24. % [defaults (missing or empty) to 'spm - algebra']
  25. % extra_vars... - additional variables which can be used in expression
  26. %
  27. % Vo (output) - spm_vol structure of output image volume after
  28. % modifications for writing
  29. %__________________________________________________________________________
  30. %
  31. % spm_imcalc performs user-specified algebraic manipulations on a set of
  32. % images, with the result being written out as an image.
  33. % The images specified in Vi, are referred to as i1, i2, i3,... in the
  34. % expression to be evaluated, unless the dmtx flag is setm in which
  35. % case the images are read into a data matrix X, with images in rows.
  36. %
  37. % Computation is plane by plane, so in data-matrix mode, X is a NxK
  38. % matrix, where N is the number of input images [prod(size(Vi))], and K
  39. % is the number of voxels per plane [prod(Vi(1).dim(1:2))].
  40. %
  41. % For data types without a representation of NaN, implicit zero masking
  42. % assumes that all zero voxels are to be treated as missing, and treats
  43. % them as NaN. NaN's are written as zero, for data types without a
  44. % representation of NaN.
  45. %
  46. % With images of different sizes and orientations, the size and orientation
  47. % of the reference image is used. Reference is the first image, if
  48. % Vo (input) is a filename, otherwise reference is Vo (input). A
  49. % warning is given in this situation. Images are sampled into this
  50. % orientation using the interpolation specified by the interp parameter.
  51. %__________________________________________________________________________
  52. %
  53. % Example expressions (f):
  54. %
  55. % i) Mean of six images (select six images)
  56. % f = '(i1+i2+i3+i4+i5+i6)/6'
  57. % ii) Make a binary mask image at threshold of 100
  58. % f = 'i1>100'
  59. % iii) Make a mask from one image and apply to another
  60. % f = '(i1>100).*i2'
  61. % (here the first image is used to make the mask, which is applied
  62. % to the second image - note the '.*' operator)
  63. % iv) Sum of n images
  64. % f = 'i1 + i2 + i3 + i4 + i5 + ...'
  65. % v) Sum of n images (when reading data into data-matrix)
  66. % f = 'sum(X)'
  67. % vi) Mean of n images (when reading data into data-matrix)
  68. % f = 'mean(X)'
  69. %__________________________________________________________________________
  70. %
  71. % Furthermore, additional variables for use in the computation can be
  72. % passed at the end of the argument list. These should be referred to by
  73. % the names of the arguments passed in the expression to be evaluated.
  74. % E.g. if c is a 1xn vector of weights, then for n images, using the (dmtx)
  75. % data-matrix version, the weighted sum can be computed using:
  76. % Vi = spm_vol(spm_select(inf,'image'));
  77. % Vo = 'output.img'
  78. % Q = spm_imcalc(Vi,Vo,'c*X',{1},c)
  79. % Here we've pre-specified the expression and passed the vector c as an
  80. % additional variable (you'll be prompted to select the n images).
  81. %__________________________________________________________________________
  82. % Copyright (C) 1998-2016 Wellcome Trust Centre for Neuroimaging
  83. % John Ashburner & Andrew Holmes
  84. % $Id: spm_imcalc.m 6961 2016-12-05 17:36:44Z guillaume $
  85. SVNid = '$Rev: 6961 $';
  86. %-Parameters & arguments
  87. %==========================================================================
  88. if nargin < 3
  89. spm_jobman('interactive','','spm.util.imcalc');
  90. return;
  91. end
  92. spm('FnBanner',mfilename,SVNid);
  93. %-Input images
  94. %--------------------------------------------------------------------------
  95. if ~isstruct(Vi), Vi = spm_vol(char(Vi)); end
  96. if isempty(Vi), error('no input images specified.'), end
  97. if isstruct(Vo)
  98. Vchk = spm_cat_struct(Vo,Vi);
  99. refstr = 'output';
  100. else
  101. Vchk = Vi(:);
  102. refstr = '1st';
  103. end
  104. [sts, str] = spm_check_orientations(Vchk, false);
  105. if ~sts
  106. for i=1:size(str,1)
  107. fprintf('Warning: %s - using %s image.\n',strtrim(str(i,:)),refstr);
  108. end
  109. end
  110. %-Flags
  111. %--------------------------------------------------------------------------
  112. if nargin < 4, flags = {}; end
  113. if iscell(flags)
  114. if numel(flags) < 5, descrip = []; else descrip = flags{5}; end
  115. if numel(flags) < 4, dtype = []; else dtype = flags{4}; end
  116. if numel(flags) < 3, interp = []; else interp = flags{3}; end
  117. if numel(flags) < 2, mask = []; else mask = flags{2}; end
  118. if numel(flags) < 1, dmtx = []; else dmtx = flags{1}; end
  119. else
  120. if isfield(flags,'dmtx'), dmtx = flags.dmtx; else dmtx = []; end
  121. if isfield(flags,'mask'), mask = flags.mask; else mask = []; end
  122. if isfield(flags,'interp'), interp = flags.interp; else interp = []; end
  123. if isfield(flags,'dtype'), dtype = flags.dtype; else dtype = []; end
  124. if isfield(flags,'descrip'), descrip = flags.descrip; else descrip = ''; end
  125. end
  126. if ischar(dtype), dtype = spm_type(dtype); end
  127. if isempty(interp), interp = 0; end
  128. if isempty(mask), mask = 0; end
  129. if isempty(dmtx), dmtx = 0; end
  130. if isempty(dtype), dtype = spm_type('int16'); end
  131. if isempty(descrip), descrip = 'spm - algebra'; end
  132. %-Output image
  133. %--------------------------------------------------------------------------
  134. if ischar(Vo)
  135. [p, n, e] = spm_fileparts(Vo);
  136. Vo = struct('fname', fullfile(p, [n, e]),...
  137. 'dim', Vi(1).dim(1:3),...
  138. 'dt', [dtype spm_platform('bigend')],...
  139. 'pinfo', [Inf Inf 0]',...
  140. 'mat', Vi(1).mat,...
  141. 'n', 1,...
  142. 'descrip', descrip);
  143. end
  144. %-Process any additional variables
  145. %--------------------------------------------------------------------------
  146. if nargin > 4
  147. reserved = {'Vi','Vo','f','flags','interp','mask','dmtx','varargin',...
  148. 'dtype','reserved','e','n','Y','p','B','X','i','j','M','d'};
  149. for i=5:nargin
  150. if isstruct(varargin{i-4}) && ...
  151. isempty(setxor(fieldnames(varargin{i-4}),{'name','value'}))
  152. for j=1:numel(varargin{i-4})
  153. if any(strcmp(varargin{i-4}(j).name,reserved))
  154. error(['additional parameter (',varargin{i-4}(j).name,...
  155. ') clashes with internal variable.'])
  156. end
  157. eval([varargin{i-4}(j).name,'=varargin{i-4}(j).value;']);
  158. end
  159. else
  160. if any(strcmp(inputname(i),reserved))
  161. error(['additional parameter (',inputname(i),...
  162. ') clashes with internal variable.'])
  163. end
  164. eval([inputname(i),' = varargin{i-4};']);
  165. end
  166. end
  167. end
  168. %-Computation
  169. %==========================================================================
  170. n = numel(Vi);
  171. Y = zeros(Vo.dim(1:3));
  172. %-Start progress plot
  173. %--------------------------------------------------------------------------
  174. spm_progress_bar('Init',Vo.dim(3),f,'planes completed');
  175. %-Loop over planes computing result Y
  176. %--------------------------------------------------------------------------
  177. for p = 1:Vo.dim(3)
  178. B = spm_matrix([0 0 -p 0 0 0 1 1 1]);
  179. if dmtx, X = zeros(n,prod(Vo.dim(1:2))); end
  180. for i = 1:n
  181. M = inv(B * inv(Vo.mat) * Vi(i).mat);
  182. d = spm_slice_vol(Vi(i), M, Vo.dim(1:2), [interp,NaN]);
  183. if (mask < 0), d(isnan(d)) = 0; end
  184. if (mask > 0) && ~spm_type(Vi(i).dt(1),'nanrep'), d(d==0)=NaN; end
  185. if dmtx, X(i,:) = d(:)'; else eval(['i',num2str(i),'=d;']); end
  186. end
  187. try
  188. eval(['Yp = ' f ';']);
  189. catch
  190. l = lasterror;
  191. error('%s\nCan''t evaluate "%s".',l.message,f);
  192. end
  193. if prod(Vo.dim(1:2)) ~= numel(Yp)
  194. error(['"',f,'" produced incompatible image.']); end
  195. if (mask < 0), Yp(isnan(Yp)) = 0; end
  196. Y(:,:,p) = reshape(Yp,Vo.dim(1:2));
  197. spm_progress_bar('Set',p);
  198. end
  199. %-Write output image
  200. %--------------------------------------------------------------------------
  201. Vo = spm_write_vol(Vo,Y);
  202. %-End
  203. %--------------------------------------------------------------------------
  204. spm_progress_bar('Clear')