attachment:mb_5_slice_timing.m of CbuSliceTiming - MRC CBU Imaging Wiki
location: attachment:mb_5_slice_timing.m of CbuSliceTiming

Attachment 'mb_5_slice_timing.m'

Download

   1 function mb_5_slice_timing(P, sliceorder, refslice, timing, imethod, prefix)
   2 % function mb_5_slice_timing(P, sliceorder, refslice, timing, imethod, prefix)
   3 % INPUT:
   4 % 	P		nimages x ?	Matrix with filenames
   5 %                       can also be a cell array of the above (multiple subj).
   6 %	sliceorder	slice acquisition order, a vector of integers, each
   7 %                       integer referring the slice number in the image file
   8 %			(1=first), and the order of integers representing their
   9 %			temporal acquisition order
  10 %	refslice	slice for time 0
  11 %	timing		additional information for sequence timing
  12 %			timing(1) = time between slices
  13 %			timing(2) = time between last slices and next
  14 %			volume
  15 %       imethod          (see help interp1) one of ['sinc']
  16 %                       'sinc'    - using custom function here
  17 %                       'nearest' - nearest neighbor interpolation
  18 %                       'linear'  - linear interpolation
  19 %                       'spline'  - cubic spline interpolation
  20 %                       'cubic'   - cubic interpolation
  21 %       prefix          prefix for new file names ['a']
  22 %		      
  23 % 	If no input is specified the function serves as a GUI			
  24 %
  25 % OUTPUT:
  26 %	None
  27 %
  28 %   Slice-time corrected files are prepended with an 'a'
  29 %
  30 %   Note: The sliceorder arg that specifies slice acquisition order is
  31 %   a vector of N numbers, where N is the number of slices per volume.
  32 %   Each number refers to the position of a slice within the image file.
  33 %   The order of numbers within the vector is the temporal order in which
  34 %   those slices were acquired.
  35 %
  36 %   To check the order of slices within an image file, use the SPM Display
  37 %   option and move the crosshairs to a voxel co-ordinate of z=1.  This
  38 %   corresponds to a point in the first slice of the volume.
  39 %
  40 %   The function corrects differences in slice acquisition times.
  41 %   This routine is intended to correct for the staggered order of
  42 %   slice acquisition that is used during echoplanar scanning. The
  43 %   correction is necessary to make the data on each slice correspond
  44 %   to the same point in time. Without correction, the data on one
  45 %   slice will represent a point in time as far removed as 1/2 the TR
  46 %   from an adjacent slice (in the case of an interleaved sequence).
  47 %
  48 %   This routine "shifts" a signal in time to provide an output
  49 %   vector that represents the same (continuous) signal sampled
  50 %   starting either later or earlier. This is accomplished by a simple
  51 %   shift of the phase of the sines that make up the signal.
  52 %
  53 %   Recall that a Fourier transform allows for a representation of any
  54 %   signal as the linear combination of sinusoids of different
  55 %   frequencies and phases. Effectively, we will add a constant
  56 %   to the phase of every frequency, shifting the data in time.
  57 %
  58 %    Shifter - This is the filter by which the signal will be convolved
  59 %    to introduce the phase shift. It is constructed explicitly in
  60 %    the Fourier domain. In the time domain, it may be described as
  61 %    an impulse (delta function) that has been shifted in time the
  62 %    amount described by TimeShift.
  63 %
  64 %   The correction works by lagging (shifting forward) the time-series
  65 %     data on each slice using sinc-interpolation. This results in each
  66 %     time series having the values that would have been obtained had
  67 %     the slice been acquired at the same time as the reference slice.
  68 %
  69 %   To make this clear, consider a neural event (and ensuing hemodynamic
  70 %     response) that occurs simultaneously on two adjacent slices. Values
  71 %     from slice "A" are acquired starting at time zero, simultaneous to
  72 %     the neural event, while values from slice "B" are acquired one
  73 %     second later. Without corection, the "B" values will describe a
  74 %     hemodynamic response that will appear to have began one second
  75 %     EARLIER on the "B" slice than on slice "A". To correct for this,
  76 %     the "B" values need to be shifted towards the Right, i.e., towards
  77 %     the last value.
  78 %
  79 %   This correction assumes that the data are band-limited (i.e. there
  80 %     is no meaningful information present in the data at a frequency
  81 %     higher than that of the Nyquist). This assumption is support by
  82 %     the study of Josephs et al (1997, NeuroImage) that obtained
  83 %     event-related data at an effective TR of 166 msecs. No physio-
  84 %     logical signal change was present at frequencies higher than our
  85 %     typical Nyquist (0.25 HZ).
  86 %
  87 % Written by Darren Gitelman at Northwestern U., 1998
  88 %
  89 % Based (in large part) on ACQCORRECT.PRO from Geoff Aguirre and
  90 % Eric Zarahn at U. Penn.
  91 %
  92 % v1.0	07/04/98	DRG
  93 % v1.1  07/09/98	DRG	fixed code to reflect 1-based indices
  94 %				of matlab vs. 0-based of pvwave
  95 %
  96 % Modified by R Henson, C Buechel and J Ashburner, FIL, to
  97 % handle different reference slices and memory mapping.
  98 %
  99 % Modified by M Erb, at U. Tuebingen, 1999, to ask for non-continuous
 100 % slice timing and number of sessions.
 101 %
 102 % Modified by R Henson for more general slice order and SPM2
 103 %_______________________________________________________________________
 104 % Copyright (C) 2005 Wellcome Department of Imaging Neuroscience
 105 
 106 %
 107 % $Id: spm_slice_timing.m 671 2006-11-02 12:08:04Z john $
 108 
 109 
 110 SPMid = spm('FnBanner',mfilename,'$Rev: 671 $');
 111 [Finter,Fgraph,CmdLine] = spm('FnUIsetup','Slice timing');
 112 spm_help('!ContextHelp',mfilename);
 113 
 114 if nargin < 1,
 115         % get number of subjects
 116         nsubjects = spm_input('number of subjects/sessions',1, 'e', 1);
 117         if nsubjects < 1,
 118                 spm_figure('Clear','Interactive');
 119                 return;
 120         end
 121 
 122 	for i = 1:nsubjects,
 123 		% Choose the images
 124 		PP = [];
 125 		PP = spm_select(Inf,'image',...
 126 			['Select images to acquisition correct for subject ' num2str(i)]);
 127 		P{i} = PP;
 128 	end;
 129 end;
 130 
 131 if iscell(P),
 132 	nsubjects = length(P);
 133 else,
 134 	nsubjects = 1;
 135 	P = {P};
 136 end;
 137 
 138 Vin 	= spm_vol(P{1}(1,:));
 139 nslices	= Vin(1).dim(3);
 140 
 141 % Modified (simplified) by R. Henson	03/06/25
 142 if nargin < 2,
 143   	sliceorder=[];
 144 	while length(sliceorder)~=nslices | max(sliceorder)>nslices | ...
 145 		min(sliceorder)<1 | any(diff(sort(sliceorder))~=1),
 146 		sliceorder = spm_input(...
 147 		   'Acquisition order? (1=first slice in image)','!+0','e');
 148 	end;
 149 end;
 150 % End of modification by R. Henson
 151 
 152 if nargin < 3,
 153 	% Choose reference slice (in Analyze format, slice 1 = bottom)
 154 	% Note: no checking that 1 < refslice < no.slices (default = middle slice)
 155 	refslice = spm_input('Reference slice? (1=first slice in image)','!+0','e',floor(Vin(1).dim(3)/2));
 156 end;
 157 
 158 if nargin < 4,
 159 	TR = spm_input('Interscan interval (TR) {secs}','!+1','e',3);
 160 	TA = spm_input('Acquisition Time (TA) {secs}','!+1','e',TR-TR/nslices);
 161 	while TA > TR | TA <= 0,
 162 		TA = spm_input('Acquisition Time (TA) {secs}','!+0','e',TA);
 163 	end;
 164 	timing(2) = TR - TA;
 165 	timing(1) = TA / (nslices -1);
 166 	factor = timing(1)/TR;
 167 else,
 168 	TR 	= (nslices-1)*timing(1)+timing(2);
 169 	fprintf('Your TR is %1.1f\n',TR);
 170 	factor = timing(1)/TR;
 171 end;
 172 if nargin < 5
 173   imethod = 'sinc';
 174 end
 175 if nargin < 6
 176   prefix = 'a';
 177 end
 178 
 179 spm('Pointer','Watch')
 180 
 181 for subj = 1:nsubjects
 182 	task = ['Slice timing: working on session ' num2str(subj)];
 183 	spm('FigName',task,Finter,CmdLine);
 184 	PP      = P{subj};
 185 	Vin 	= spm_vol(PP);
 186 	nimgo	= numel(Vin);
 187 	if strcmp(imethod, 'sinc')
 188 	  nimg	= 2^(floor(log2(nimgo))+1);
 189 	else
 190 	  nimg = nimgo;
 191 	end 
 192 	nslices_t= Vin(1).dim(3);
 193 	if nslices_t ~= nslices,
 194 		fprintf('Number of slices differ! %d %\n', nimg);
 195 	else
 196 
 197 		% create new header files
 198 		Vout 	= Vin;
 199 		for k=1:nimgo,
 200 			[pth,nm,xt,vr] = fileparts(deblank(Vin(k).fname));
 201 			Vout(k).fname  = fullfile(pth,[prefix nm xt vr]);
 202 			if isfield(Vout(k),'descrip'),
 203 				desc = [Vout(k).descrip ' '];
 204 			else,
 205 				desc = '';
 206 			end;
 207 			Vout(k).descrip = [desc 'acq-fix ref-slice ' int2str(refslice)];
 208 		end;
 209 		Vout = spm_create_vol(Vout);
 210 
 211 		% Set up large matrix for holding image info
 212 		% Organization is time by voxels
 213 		slices = zeros([Vout(1).dim(1:2) nimgo]);
 214 		stack  = zeros([nimg Vout(1).dim(1)]);
 215 
 216 		spm_progress_bar('Init',nslices,'Correcting acquisition delay','planes complete');
 217 
 218 		% For loop to read data slice by slice do correction and write out
 219 		% In analzye format, the first slice in is the first one in the volume.
 220 
 221 		rslice = find(sliceorder==refslice);
 222 		for k = 1:nslices,
 223 
 224 		  % Set up time acquired within slice order
 225 		  shiftamount  = (find(sliceorder==k) - rslice) * factor;
 226 		  
 227 		  % Read in slice data
 228 		  B  = spm_matrix([0 0 k]);
 229 		  for m=1:nimgo,
 230 		    slices(:,:,m) = spm_slice_vol(Vin(m),B,Vin(1).dim(1:2),1);
 231 		  end;
 232 		  
 233 		  if strcmp(imethod, 'sinc')
 234 		    
 235 		    % set up shifting variables
 236 		    len     = size(stack,1);
 237 		    phi     = zeros(1,len);
 238 		    
 239 		    % Check if signal is odd or even -- impacts how Phi is reflected
 240 		    %  across the Nyquist frequency. Opposite to use in pvwave.
 241 		    OffSet  = 0;
 242 		    if rem(len,2) ~= 0, OffSet = 1; end;
 243 		    
 244 		    % Phi represents a range of phases up to the Nyquist frequency
 245 		    % Shifted phi 1 to right.
 246 		    for f = 1:len/2,
 247 		      phi(f+1) = -1*shiftamount*2*pi/(len/f);
 248 		    end;
 249 		    
 250 		    % Mirror phi about the center
 251 		    % 1 is added on both sides to reflect Matlab's 1 based indices
 252 		    % Offset is opposite to program in pvwave again because indices are 1 based
 253 		    phi(len/2+1+1-OffSet:len) = -fliplr(phi(1+1:len/2+OffSet));
 254 		    
 255 		    % Transform phi to the frequency domain and take the complex transpose
 256 		    shifter = [cos(phi) + sin(phi)*sqrt(-1)].';
 257 		    shifter = shifter(:,ones(size(stack,2),1)); % Tony's trick
 258 		    
 259 		  else % i.e. not sinc
 260 		    
 261 		    % interpolation vector - see help interp1
 262 		    X1 = (1:nimgo)-shiftamount;
 263 		    imeth = ['*' imethod];
 264 		  end
 265 		  % Loop over columns
 266 		  for i=1:Vout(1).dim(2),
 267 		    
 268 		    % Extract columns from slices
 269 		    stack(1:nimgo,:) = reshape(slices(:,i,:),[Vout(1).dim(1) nimgo])';
 270 		    
 271 		    if strcmp(imethod, 'sinc')
 272 		      
 273 		      % fill in continous function to avoid edge effects
 274 		      for g=1:size(stack,2),
 275 			stack(nimgo+1:end,g) = linspace(stack(nimgo,g),...
 276 							stack(1,g),nimg-nimgo)';
 277 		      end;
 278 		      
 279 		      % shift the columns
 280 		      stack = real(ifft(fft(stack,[],1).* ...
 281 					shifter,[],1));
 282 		    else
 283 		      % interpolate within columns
 284 		      stack = interp1(stack, X1, imeth);
 285 		    end
 286 		    
 287 		    % Re-insert shifted columns
 288 		    slices(:,i,:) = reshape(stack(1:nimgo,:)',[Vout(1).dim(1) 1 nimgo]);
 289 		  end;
 290 		  
 291 		  % write out the slice for all volumes
 292 		  for p = 1:nimgo,
 293 		    Vout(p) = spm_write_plane(Vout(p),slices(:,:,p),k);
 294 		  end;
 295 		  spm_progress_bar('Set',k);
 296 		end;
 297 		spm_progress_bar('Clear');
 298 	end
 299 end
 300 
 301 spm('FigName','Slice timing: done',Finter,CmdLine);
 302 spm('Pointer');
 303 return;

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2007-05-16 21:45:47, 10.4 KB) [[attachment:mb_5_slice_timing.m]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.