spm_getSPM.m
function [SPM,VOL,xX,xCon,xSDM] = spm_getSPM
% computs a specified and thresholded following parameter estimation
% FORMAT [SPM,VOL,xX,xCon,xSDM] = spm_getSPM;
%
% SPM - structure containing SPM, distribution & filtering details
% .swd - SPM working directory - directory containing current SPM.mat
% .title - title for comparison (string)
% .Z - minimum of n Statistics {filtered on u and k}
% .n - number of conjoint tests
% .STAT - distribution {Z, T, X or F}
% .df - degrees of freedom [df{interest}, df{residual}]
% .Ic - indices of contrasts (in xCon)
% .Im - indices of masking contrasts (in xCon)
% .pm - p-value for masking (uncorrected)
% .Ex - flag for exclusive or inclusive masking
% .u - height threshold
% .k - extent threshold {voxels}
% .XYZ - location of voxels {voxel coords}
% .XYZmm - location of voxels {mm}
% .QQ - indices of volxes in Y.mad file
%
%
% VOL - structure containing details of volume analysed
% .S - search Volume {voxels}
% .R - search Volume {resels}
% .FWHM - smoothness {voxels}
% .M - voxels - > mm matrix
% .iM - mm -> voxels matrix
% .VOX - voxel dimensions {mm} - column vector
% .DIM - image dimensions {voxels} - column vector
% .Vspm - Mapped statistic image(s)
% .Msk - Mask in 1 of 3 forms
% o Scalar, indicating implicit mask value in statistic image(s)
% o Vector of indicies of elements within mask
% o Mapped mask image
%
% xX - Design Matrix structure
% - (see spm_spm.m for structure)
%
% xCon - Contrast definitions structure array
% - (see also spm_FcUtil.m for structure, rules & handling)
% .name - Contrast name
% .STAT - Statistic indicator character ('T' or 'F')
% .c - Contrast weights (column vector contrasts)
% .X0 - Reduced design matrix data (spans design space under Ho)
% Stored as coordinates in the orthogonal basis of xX.X from spm_sp
% (Matrix in SPM99b) Extract using X0 = spm_FcUtil('X0',...
% .iX0 - Indicates how contrast was specified:
% If by columns for reduced design matrix then iX0 contains the
% column indices. Otherwise, it's a string containing the
% spm_FcUtil 'Set' action: Usuall one of {'c','c+','X0'}
% .X1o - Remaining design space data (X1o is orthogonal to X0)
% Stored as coordinates in the orthogonal basis of xX.X from spm_sp
% (Matrix in SPM99b) Extract using X1o = spm_FcUtil('X1o',...
% .eidf - Effective interest degrees of freedom (numerator df)
% .Vcon - Name of contrast (for 'T's) or ESS (for 'F's) image
% .Vspm - Name of SPM image
%
% xSDM - structure containing contents of SPM.mat file
% ( see spm_spm.m for contents...
% ( ...except that xX & XYZ are removed, being returned separately
% ( ...and xSDM.Vbeta & xSDM.VResMS are re-mmapped
%
% In addition, the xCon.mat file is updated. For newly evaluated
% contrasts, SPM images (spmT_????.{img,hdr}) are written, along with
% contrast (con_????.{img,hdr}) images for SPM{T}'s, or Extra
% Sum-of-Squares images (ess_????.{img,hdr}) for SPM{F}'s.
%
% The contrast images are the weighted sum of the parameter images,
% where the weights are the contrast weights, and are uniquely
% estimable since contrasts are checked for estimability by the
% contrast manager. These contrast images (for appropriate contrases)
% are suitable summary images of an effect at this level, and can be
% used as input at a higher level when effecting a random effects
% analysis. (Note that the ess_????.{img,hdr} and
% SPM{T,F}_????.{img,hdr} images are not suitable input for a higher
% level analysis.) See spm_RandFX.man for further details.
%
%_______________________________________________________________________
%
% spm_getSPM prompts for an SPM and applies thresholds {u & k}
% to a point list of voxel values (specified with their locations {XYZ})
% This allows the SPM be displayed and characterized in terms of regionally
% significant effects by subsequent routines.
%
% For general linear model Y = XB + E with data Y, desgin matrix X,
% parameter vector B, and (independent) errors E, a contrast c'B of the
% parameters (with contrast weights c) is estimated by c'b, where b are
% the parameter estimates given by b=pinv(X)*Y.
%
% Either single contrasts can be examined or conjunctions of different
% contrasts. Contrasts are estimable linear combinations of the
% parameters, and are specified using the SPM contrast manager
% interface [spm_conman.m]. SPMs are generated for the null hypotheses
% that the contrast is zero (or zero vector in the case of
% F-contrasts). See the help for the contrast manager [spm_conman.m]
% for a further details on contrasts and contrast specification.
%
% A conjunction assesses the conjoint expression of two or more
% effects. The conjunction SPM is the minimum of the component SPMs
% defined by the multiple contrasts. The distributional results used
% for minimum fileds require the SPMs to be identically distributed and
% independent. Thus, all component SPMs must be either SPM{t}'s, or
% SPM{F}'s with the same degrees of freedom. Independence is roughly
% guaranteed for large degrees of freedom (and independent data) by
% ensuring that the contrasts are "orthogonal". Note that it is *not*
% the contrast weight vectors themselves that are required to be
% orthogonal, but the subspaces of the data space implied by the null
% hypotheses defined by the contrasts (c'pinv(X)).
%
% To ensure approximate independence of the component SPMs in a
% conjunction, non-orthogonal contrasts for a conjunction are
% successively enforced to be orthogonal. If this is required, you will
% be asked to specify the orthogonalisation order (as a permutation of
% the contrast indices). The contrasts are then serially orthogonalised
% in this order, possibly generating new contrasts, such that the
% second is orthogonal to the first, the third to the first two, and so
% on.
%
% Masking simply eliminates voxels from the current contrast if they
% do not survive an uncorrected p value (based on height) in one or
% more further contrasts. No account is taken of this masking in the
% statistical inference pertaining to the masked contrast.
%
% The SPM is subject to thresholding on the basis of height (u) and the
% number of voxels comprising its clusters {k}. The height threshold is
% specified as above in terms of an [un]corrected p value or
% statistic. Clusters can also be thresholded on the basis of their
% spatial extent. If you want to see all voxels simply enter 0. In this
% instance the 'set-level' inference can be considered an 'omnibus test'
% based on the number of clusters that obtain.
%
% see spm_results_ui.m for further details of the SPM results section.
%_______________________________________________________________________
% @(#)spm_getSPM.m 2.37 Andrew Holmes, Karl Friston & Jean-Baptiste Poline 01/06/23
% @(#)spm_getSPM.m 1.8 UM Biostatistics ver, T. Nichols 01/06/26
SCCSid = '2.37';
%-GUI setup
%-----------------------------------------------------------------------
SPMid = spm('SFnBanner',mfilename,SCCSid);
spm_help('!ContextHelp',mfilename)
%-Select SPM.mat & note SPM results directory
%-----------------------------------------------------------------------
swd = spm_str_manip(spm_get(1,'SPM.mat','Select SPM.mat'),'H');
%-Preliminaries...
%=======================================================================
%-Load and check/canonicalise SPM.mat
%-----------------------------------------------------------------------
xSDM = load(fullfile(swd,'SPM.mat')); %-Contents of SPM.mat (in a struct)
if ~isfield(xSDM,'SPMid')
%-SPM.mat pre SPM99
error('Incompatible SPM.mat - old SPM results format!?')
elseif ~isfield(xSDM,'M')
%-SPM.mat from SPM99b (which saved mmapped handles) **
xSDM.M = xSDM.Vbeta(1).mat;
xSDM.DIM = xSDM.Vbeta(1).dim(1:3)';
xSDM.VM = 'mask.img';
xSDM.Vbeta = {xSDM.Vbeta.fname}';
xSDM.VResMS = xSDM.VResMS.fname;
end
%-Map beta and ResMS images, canonicalising relative pathnames
% (SPM result images stored with relative pathnames, for robustness.)
%-----------------------------------------------------------------------
xSDM.Vbeta = ...
spm_vol([repmat([swd,filesep],length(xSDM.Vbeta),1),char(xSDM.Vbeta)]);
xSDM.VResMS = spm_vol(fullfile(swd,xSDM.VResMS));
%-Get Stats data from SPM.mat
%-----------------------------------------------------------------------
xX = xSDM.xX; %-Design definition structure
XYZ = xSDM.XYZ; %-XYZ coordinates
S = xSDM.S; %-search Volume {voxels}
R = xSDM.R; %-search Volume {resels}
xSDM = rmfield(xSDM,{'xX','XYZ'}); %-Remove (large) duplicate fields
%-Get/Compute mm<->voxel matrices & image dimensions from SPM.mat
%-----------------------------------------------------------------------
M = xSDM.M;
iM = inv(M);
DIM = xSDM.DIM;
%-Build index from XYZ into corresponding Y.mad locations
%-----------------------------------------------------------------------
QQ = zeros(1,S);
if exist(fullfile(swd,'Yidx.mat'),'file') & exist(fullfile(swd,'Y.mad'),'file')
load(fullfile(swd,'Yidx.mat'))
QQ(Yidx) = 1:length(Yidx);
end
%-Contrast definitions
%=======================================================================
%-Load contrast definitions (if available)
%-----------------------------------------------------------------------
if exist(fullfile(swd,'xCon.mat'),'file')
load(fullfile(swd,'xCon.mat'))
else
xCon = [];
end
%-Canonicalise SPM99b format xCon (which saved mmapped handles) **
%-----------------------------------------------------------------------
for i=1:length(xCon)
if isstruct(xCon(i).Vcon), xCon(i).Vcon=xCon(i).Vcon.fname; end
if isstruct(xCon(i).Vspm), xCon(i).Vspm=xCon(i).Vspm.fname; end
end
%-See if can write to current directory (by trying to open for appending)
%-----------------------------------------------------------------------
wOK = 1;
fid = fopen(fullfile(swd,'xCon.mat'),'a');
if fid < 0
wOK = 0;
str = { 'Can''t write to the results directory:',...
'(problem saving xCon.mat)',...
[' ',swd],...
' ','-> results restricted to contrasts already computed'};
spm('alert!',str,mfilename,1);
else
fclose(fid);
end
%=======================================================================
% - C O N T R A S T S , S P M C O M P U T A T I O N , M A S K I N G
%=======================================================================
%-Get contrasts (if multivariate there is only one structure)
%-----------------------------------------------------------------------
nVar = size(xSDM.VY,2);
if nVar == 1
[Ic,xCon] = spm_conman(xX,xCon,'T|F',Inf,...
' Select contrasts...',' for conjunction',wOK);
else
Ic = 1;
end
%-Enforce orthogonality of multiple contrasts for conjunction
% (Orthogonality within subspace spanned by contrasts)
%-----------------------------------------------------------------------
% (Don't want to ask orthogonalisation order if not needed.)
if length(Ic) > 1 & ~spm_FcUtil('|_?',xCon(Ic), xX.xKXs)
%-Get orthogonalisation order from user
Ic = spm_input('orthogonlization order','+1','p',Ic,Ic);
%-Successively orthogonalise
%-------------------------------------------------------------------
i = 1; while(i < length(Ic)), i = i + 1;
%-NB: This loop is peculiarly controlled to account for the
% possibility that Ic may shrink if some contrasts diasppear
% on orthogonalisation (i.e. if there are colinearities)
%-Orthogonalise (subspace spanned by) contrast i wirit previous
%---------------------------------------------------------------
oxCon = spm_FcUtil('|_',xCon(Ic(i)), xX.xKXs, xCon(Ic(1:i-1)));
%-See if this orthogonalised contrast has already been entered
% or is colinear with a previous one. Define a new contrast if
% neither is the case.
%---------------------------------------------------------------
d = spm_FcUtil('In',oxCon,xX.xKXs,xCon);
if spm_FcUtil('0|[]',oxCon,xX.xKXs)
%-Contrast was colinear with a previous one - drop it
%-----------------------------------------------------------
Ic(i) = [];
i = i - 1;
elseif any(d)
%-Contrast unchanged or already defined - note index
%-----------------------------------------------------------
Ic(i) = min(d);
else
%-Define orthogonalised contrast as new contrast
%-----------------------------------------------------------
oxCon.name = [xCon(Ic(i)).name,' (orthogonalized w.r.t {',...
sprintf('%d,',Ic(1:i-2)), sprintf('%d})',Ic(i-1))];
xCon = [xCon, oxCon];
Ic(i) = length(xCon);
end
end % while...
end % if length(Ic)...
%-Get contrasts for masking
%-----------------------------------------------------------------------
if spm_input('mask with other contrast(s)','+1','y/n',[1,0],2)
[Im,xCon] = spm_conman(xX,xCon,'T&F',-Inf,...
'Select contrasts for masking...',' for masking',wOK);
%-Threshold for mask (uncorrected p-value)
%---------------------------------------------------------------
pm = spm_input('uncorrected mask p-value','+1','r',0.05,1,[0,1]);
%-Inclusive or exclusive masking
%---------------------------------------------------------------
Ex = spm_input('nature of mask','+1','b','inclusive|exclusive',[0,1]);
else
Im = [];
pm = [];
Ex = [];
end
%-Save contrast structure (if wOK) - ensures new contrasts are saved
%-----------------------------------------------------------------------
if wOK, save(fullfile(swd,'xCon.mat'),'xCon'), end
%-Create/Get title string for comparison
%-----------------------------------------------------------------------
if length(Ic)==1
str = xCon(Ic).name;
else
str = [sprintf('contrasts {%d',Ic(1)),...
sprintf(',%d',Ic(2:end)),'}'];
end
if Ex
mstr = 'masked [exclusive] by';
else
mstr = 'masked [inclusive] by';
end
if length(Im)==1
str = sprintf('%s (%s %s at p=%g)',str,mstr,xCon(Im).name,pm);
elseif ~isempty(Im)
str = [sprintf('%s (%s {%d',str,mstr,Im(1)),...
sprintf(',%d',Im(2:end)),...
sprintf('} at p=%g)',pm)];
end
titlestr = spm_input('title for comparison','+1','s',str);
%-Compute & store contrast parameters, contrast/ESS images, & SPM images
%=======================================================================
spm('Pointer','Watch')
spm_progress_bar('Init',100,'computing...') %-#
nPar = size(xX.X,2);
I = unique([Ic,Im]);
for ii = 1:length(I)
i = I(ii);
%-Canonicalise contrast structure with required fields
%-------------------------------------------------------------------
if ~isfield(xCon(i),'eidf') | isempty(xCon(i).eidf)
[trMV,trMVMV] = spm_SpUtil('trMV',...
spm_FcUtil('X1o',xCon(i),xX.xKXs),xX.V);
xCon(i).eidf = trMV^2/trMVMV;
else
trMV = []; trMVMV = [];
end
%-Write contrast/ESS images?
%-------------------------------------------------------------------
if ~isfield(xCon(i),'Vcon') | isempty(xCon(i).Vcon) | ...
~exist(fullfile(swd,xCon(i).Vcon),'file')
%-Bomb out (nicely) if can't write to results directory
%---------------------------------------------------------------
if ~wOK, spm('alert*',{ 'Can''t write to the results directory:',...
[' ',swd],' ','=> can''t compute new contrasts'},...
mfilename,sqrt(-1));
spm('Pointer','Arrow')
error('can''t write contrast image')
end
switch(xCon(i).STAT)
case 'T' %-Implement contrast as sum of scaled beta images
%---------------------------------------------------------------
fprintf('\t%-32s: %-10s%20s',sprintf('contrast image %2d',i),...
'(spm_add)','...initialising') %-#
Q = find(abs(xCon(i).c) > 0);
V = xSDM.Vbeta(Q);
for j = 1:length(Q)
V(j).pinfo(1,:) = V(j).pinfo(1,:)*xCon(i).c(Q(j));
end
%-Prepare handle for contrast image
%-----------------------------------------------------------
xCon(i).Vcon = struct(...
'fname', fullfile(swd,sprintf('con_%04d.img',i)),...
'dim', [DIM',16],...
'mat', M,...
'pinfo', [1,0,0]',...
'descrip',sprintf('SPM contrast - %d: %s',i,xCon(i).name));
%-Write image
%-----------------------------------------------------------
fprintf('%s%20s',sprintf('\b')*ones(1,20),'...computing')%-#
xCon(i).Vcon = spm_create_image(xCon(i).Vcon);
xCon(i).Vcon.pinfo(1,1) = spm_add(V,xCon(i).Vcon);
xCon(i).Vcon = spm_create_image(xCon(i).Vcon);
fprintf('%s%30s\n',sprintf('\b')*ones(1,30),sprintf(...
'...written %s',spm_str_manip(xCon(i).Vcon.fname,'t')))%-#
case 'F' %-Implement ESS as sum of squared weighted beta images
%---------------------------------------------------------------
fprintf('\t%-32s: %30s',sprintf('ESS image %2d',i),...
'...computing') %-#
%-Residual (in parameter space) forming mtx
%-----------------------------------------------------------
h = spm_FcUtil('Hsqr',xCon(i),xX.xKXs);
%-Prepare handle for ESS image
%-----------------------------------------------------------
xCon(i).Vcon = struct(...
'fname', fullfile(swd,sprintf('ess_%04d.img',i)),...
'dim', [DIM',16],...
'mat', M,...
'pinfo', [1,0,0]',...
'descrip',sprintf('SPM ESS - contrast %d: %s',i,xCon(i).name));
%-Write image
%-----------------------------------------------------------
fprintf('%s',sprintf('\b')*ones(1,30)) %-#
xCon(i).Vcon = spm_create_image(xCon(i).Vcon);
xCon(i).Vcon = spm_resss(xSDM.Vbeta,xCon(i).Vcon,h);
xCon(i).Vcon = spm_create_image(xCon(i).Vcon);
otherwise
%---------------------------------------------------------------
error(['unknown STAT "',xCon(i).STAT,'"'])
end % (switch(xCon...)
else
%-Already got contrast/ESS image - remap it w/ full pathname
%---------------------------------------------------------------
xCon(i).Vcon = spm_vol(fullfile(swd,xCon(i).Vcon));
end % (if ~isfield...)
spm_progress_bar('Set',100*(2*ii-1)/(2*length(I)+2)) %-#
%-Write statistic image(s)
%-------------------------------------------------------------------
if ~isfield(xCon(i),'Vspm') | isempty(xCon(i).Vspm) | ...
~exist(fullfile(swd,xCon(i).Vspm),'file')
%-Bomb out (nicely) if can't write to results directory
%---------------------------------------------------------------
if ~wOK, spm('alert*',{ 'Can''t write to the results directory:',...
[' ',swd],' ','=> can''t compute new contrasts'},...
mfilename,sqrt(-1));
spm('Pointer','Arrow')
error('can''t write SPM image')
end
fprintf('\t%-32s: %30s',sprintf('spm{%c} image %2d',xCon(i).STAT,i),...
'...computing') %-#
switch(xCon(i).STAT)
case 'T' %-Compute SPM{t} image
%---------------------------------------------------------------
Z = spm_sample_vol(xCon(i).Vcon, XYZ(1,:),XYZ(2,:),XYZ(3,:),0)./...
(sqrt(spm_sample_vol(xSDM.VResMS, XYZ(1,:),XYZ(2,:),XYZ(3,:),0)*...
(xCon(i).c'*xX.Bcov*xCon(i).c) ));
str = sprintf('[%.2g]',xX.erdf);
case 'F' %-Compute SPM{F} image
%---------------------------------------------------------------
if isempty(trMV)
trMV = spm_SpUtil('trMV',spm_FcUtil('X1o',xCon(i),xX.xKXs),xX.V);
end
Z =(spm_sample_vol(xCon(i).Vcon,XYZ(1,:),XYZ(2,:),XYZ(3,:),0)/trMV)./...
(spm_sample_vol(xSDM.VResMS, XYZ(1,:),XYZ(2,:),XYZ(3,:),0));
str = sprintf('[%.2g,%.2g]',xCon(i).eidf,xX.erdf);
otherwise
%---------------------------------------------------------------
error(['unknown STAT "',xCon(i).STAT,'"'])
end
%-Write full statistic image
%---------------------------------------------------------------
fprintf('%s%30s',sprintf('\b')*ones(1,30),'...writing') %-#
xCon(i).Vspm = struct(...
'fname', fullfile(swd,sprintf('spm%c_%04d.img',xCon(i).STAT,i)),...
'dim', [DIM',16],...
'mat', M,...
'pinfo', [1,0,0]',...
'descrip',sprintf('SPM{%c_%s} - contrast %d: %s',...
xCon(i).STAT,str,i,xCon(i).name));
tmp = zeros(DIM');
tmp(cumprod([1,DIM(1:2)'])*XYZ -sum(cumprod(DIM(1:2)'))) = Z;
xCon(i).Vspm = spm_write_vol(xCon(i).Vspm,tmp);
clear tmp Z
fprintf('%s%30s\n',sprintf('\b')*ones(1,30),sprintf(...
'...written %s',spm_str_manip(xCon(i).Vspm.fname,'t'))) %-#
else
%-Already got statistic image - remap it w/ full pathname
%---------------------------------------------------------------
xCon(i).Vspm = spm_vol(fullfile(swd,xCon(i).Vspm));
end % (if ~isfield...)
spm_progress_bar('Set',100*(2*ii-0)/(2*length(I)+2)) %-#
end % (for ii = 1:length(I))
%-Compute (unfiltered) SPM pointlist for requested masked conjunction
%=======================================================================
fprintf('\t%-32s: %30s','SPM computation','...initialising') %-#
%-Check conjunctions - Must be same STAT w/ same df
%-----------------------------------------------------------------------
if (length(Ic) > 1) & (any(diff(double(cat(1,xCon(Ic).STAT)))) | ...
any(abs(diff(cat(1,xCon(Ic).eidf))) > 1e-6) )
error('illegal conjunction: can only conjoin SPMs of same STAT & df')
end
%-Compute mask first
%-----------------------------------------------------------------------
if ~isempty(Im), fprintf('%s%30s',sprintf('\b')*ones(1,30),'...masking'), end %-#
for i = Im
Mask = spm_sample_vol(xCon(i).Vspm,XYZ(1,:),XYZ(2,:),XYZ(3,:),0);
um = spm_u(pm,[xCon(i).eidf,xX.erdf],xCon(i).STAT);
if Ex
Q = Mask <= um;
else
Q = Mask > um;
end
XYZ = XYZ(:,Q);
QQ = QQ(Q);
if isempty(Q), break, end
end
if ~isempty(Im) & ~isempty(Q)
Msk = XYZ(1,:)+(XYZ(2,:)-1)*DIM(1)+(XYZ(3,:)-1)*DIM(1)*DIM(2);
else
Msk = 0; %-Statistic images are zero-masked
end
spm_progress_bar('Set',100*((2*length(I)+1)/(2*length(I)+2))) %-#
%-Compute conjunction SPM (as minimum SPM) within mask...
%-----------------------------------------------------------------------
if isempty(XYZ)
fprintf('\n') %-#
warning(sprintf('No voxels survive masking at p=%4.3g',pm))
Z = [];
else
fprintf('%s%30s',sprintf('\b')*ones(1,30),'...computing') %-#
Z = Inf;
for i = Ic
Z = min(Z,spm_sample_vol(xCon(i).Vspm,XYZ(1,:),XYZ(2,:),XYZ(3,:),0));
end
end
%-Degrees of Fredom and STAT string describing marginal distribution
%-----------------------------------------------------------------------
edf = [xCon(Ic(1)).eidf xX.erdf];
if length(Ic) > 1
str = sprintf('^{%d}',length(Ic));
elseif nVar > 1
str = sprintf('^{%d-variate}',nVar);
else
str = '';
end
switch xCon(Ic(1)).STAT
case 'T'
STATstr = sprintf('%c%s_{%.4g}','T',str,edf(2));
case 'F'
STATstr = sprintf('%c%s_{[%.4g,%.4g]}','F',str,edf(1),edf(2));
end
fprintf('%s%30s\n',sprintf('\b')*ones(1,30),'...done') %-#
spm_progress_bar('Set',100) %-#
%-Save mappped statistic image(s) to put in VOL
VspmSv = cat(1,xCon(Ic).Vspm);
%-Save contrast structure (if wOK), with relative pathnames to image files
%=======================================================================
if wOK
for i = I;
if ~isempty(xCon(i).Vcon)
xCon(i).Vcon = spm_str_manip(xCon(i).Vcon.fname,'t');
end
if ~isempty(xCon(i).Vspm)
xCon(i).Vspm = spm_str_manip(xCon(i).Vspm.fname,'t');
end
end
save(fullfile(swd,'xCon.mat'),'xCon')
fprintf('\t%-32s: %30s\n','contrast structure','...saved to xCon.mat')%-#
end
%-Various parameters...
%-----------------------------------------------------------------------
STAT = xCon(Ic(1)).STAT;
n = length(Ic);
u = -Inf;
k = 0;
%-Return to previous directory & clean up interface
%-----------------------------------------------------------------------
spm_progress_bar('Clear') %-#
spm('Pointer','Arrow')
%=======================================================================
% - H E I G H T & E X T E N T T H R E S H O L D S
%=======================================================================
%-Height threshold
%-----------------------------------------------------------------------
if ~isempty(XYZ)
%-Get height threshold
%-------------------------------------------------------------------
str = 'FWE|FDR|uncorrected';
d = spm_input('corrected height threshold','+1','b',str,[],3);
if strcmp(d,'FWE')
u = spm_input('FWE-corrected p value','+0','r',0.05,1,[0,1]);
u = spm_uc(u,edf,STAT,xSDM.R,n,xSDM.S);
elseif strcmp(d,'FDR')
u = spm_input('FDR-corrected p value','+0','r',0.05,1,[0,1]);
u = spm_uc_FDR(u,edf,STAT,n,VspmSv,0);
else
%-NB: Uncorrected p for conjunctions is p of the conjunction SPM
u = spm_input(['threshold {',STAT,' or p value}'],'+0','r',0.001,1);
if u <= 1; u = spm_u(u^(1/n),edf,STAT); end
end
%-Calculate height threshold filtering
%-------------------------------------------------------------------
Q = find(Z > u);
%-Apply height threshold
%-------------------------------------------------------------------
Z = Z(:,Q);
XYZ = XYZ(:,Q);
QQ = QQ(Q);
if isempty(Q)
warning(sprintf('No voxels survive height threshold u=%0.2g',u)), end
end % (if ~isempty(XYZ))
%-Extent threshold (only for allowed cases)
%-----------------------------------------------------------------------
if ~isempty(XYZ) & length(Ic) == 1 & STAT == 'T'
%-Get extent threshold [default = 0]
%-------------------------------------------------------------------
k = spm_input('& extent threshold {voxels}','+1','r',0,1,[0,Inf]);
%-Calculate extent threshold filtering
%-------------------------------------------------------------------
A = spm_clusters(XYZ);
Q = [];
for i = 1:max(A)
j = find(A == i);
if length(j) >= k; Q = [Q j]; end
end
% ...eliminate voxels
%-------------------------------------------------------------------
Z = Z(:,Q);
XYZ = XYZ(:,Q);
QQ = QQ(Q);
if isempty(Q)
warning(sprintf('No voxels survive extent threshold k=%0.2g',k)), end
else
k = 0;
end % (if ~isempty(XYZ))
%=======================================================================
% - E N D
%=======================================================================
%-Assemble output structures of unfiltered data
%=======================================================================
SPM = struct('swd', swd,...
'title', titlestr,...
'Z', Z,...
'n', n,...
'STAT', STAT,...
'df', edf,...
'STATstr', STATstr,...
'Ic', Ic,...
'Im', Im,...
'pm', pm,...
'Ex', Ex,...
'u', u,...
'k', k,...
'XYZ', XYZ,...
'XYZmm', M(1:3,:)*[XYZ; ones(1,size(XYZ,2))],...
'QQ', QQ);
VOL = struct('S', S,...
'R', R,...
'FWHM', xSDM.FWHM,...
'M', M,...
'iM', iM,...
'VOX', sqrt(sum(M(1:3,1:3).^2))',...
'DIM', DIM,...
'Vspm', VspmSv,...
'Msk', Msk);
% RESELS per voxel (density) if it exists
%-----------------------------------------------------------------------
if isfield(xSDM,'VRVP'), VOL.VRVP = spm_vol(xSDM.VRVP); end