JiscMail Logo
Email discussion lists for the UK Education and Research communities

Help for SPM Archives


SPM Archives

SPM Archives


SPM@JISCMAIL.AC.UK


View:

Message:

[

First

|

Previous

|

Next

|

Last

]

By Topic:

[

First

|

Previous

|

Next

|

Last

]

By Author:

[

First

|

Previous

|

Next

|

Last

]

Font:

Proportional Font

LISTSERV Archives

LISTSERV Archives

SPM Home

SPM Home

SPM  2003

SPM 2003

Options

Subscribe or Unsubscribe

Subscribe or Unsubscribe

Log In

Log In

Get Password

Get Password

Subject:

Re: please help: matlab error

From:

Jesper Andersson <[log in to unmask]>

Reply-To:

Jesper Andersson <[log in to unmask]>

Date:

Wed, 10 Dec 2003 09:40:14 +0100

Content-Type:

MULTIPART/MIXED

Parts/Attachments:

Parts/Attachments

text/plain (19 lines) , spm_uw_estimate.m (895 lines)


>
>
> Jesper- did you ever fix this?
>
I did, and your explanation is correct. Attached is a new
spm_uw_estimate.m that SHOULD work. There are a few unrelated new things
in there that aren't completely tested yet, but as long as you use the
old GUI routines those bits should never be visited.

So, all you who use SPM on Windows and want to use Unwarp should put
this in your SPM_updates directory.

And to Joe, sorry for the delay. It just slipped my mind.

Good luck Jesper




function ds = spm_uw_estimate(P,par) % % Estimation of partial derivatives of EPI deformation fields. % % FORMAT [ds] = spm_uw_estimate((P),(par)) % % P - List of file names or headers. % par - Structure containing parameters governing the specifics % of how to estimate the fields. % .M - When performing multi-session realignment and Unwarp we % want to realign everything to the space of the first % image in the first time-series. M defines the space of % that. % .order - Number of basis functions to use for each dimension. % If the third dimension is left out, the order for % that dimension is calculated to yield a roughly % equal spatial cut-off in all directions. % Default: [8 8 *] % .sfield - Static field supplied by the user. It could be either % an nx1 vector (where n is the number of voxels in % the image volume) or it could be a prod(order)x1 vector % with weights for a DCT basis set. % .sf_acq - Static field acquired 'Before' or 'After' time series. % Default: 'Before' % .regorder - Regularisation of derivative fields is based on the % regorder'th (spatial) derivative of the field. % Default: 1 % .lambda - Fudge factor used to decide relative weights of % data and regularisation. % Default: 1e5 % .jm - Jacobian Modulation. If set, intensity (Jacobian) % deformations are included in the model. If zero, % intensity deformations are not considered. % .fot - List of indexes for first order terms to model % derivatives for. Order of parameters as defined % by spm_imatrix. % Default: [4 5] % .sot - List of second order terms to model second % derivatives of. Should be an nx2 matrix where % e.g. [4 4; 4 5; 5 5] means that second partial % derivatives of rotation around x- and y-axis % should be modelled. % Default: [] % .fwhm - FWHM (mm) of smoothing filter applied to images prior % to estimation of deformation fields. % Default: 6 % .rem - Re-Estimation of Movement parameters. Set to unity means % that movement-parameters should be re-estimated at each % iteration. % Default: 0 % .noi - Maximum number of Iterations. % Default: 5 % .exp_round - Point in position space to do Taylor expansion around. % 'First', 'Last' or 'Average'. % Default: 'Average'. % ds - The returned structure contains the following fields % .P - Copy of P on input. % .sfield - Copy of sfield on input (if non-empty). % .order - Copy of order on input, or default. % .regorder - Copy of regorder on input, or default. % .lambda - Copy of lambda on input, or default. % .fot - Copy of fot on input, or default. % .sot - Copy of sot on input, or default. % .fwhm - Copy of fwhm on input, or default. % .rem - Copy of rem on input, or default. % .p0 - Average position vector (three translations in mm % and three rotations in degrees) of scans in P. % .q - Deviations from mean position vector of modelled % effects. Corresponds to deviations (and deviations % squared) of a Taylor expansion of deformation fields. % .beta - Coeffeicents of DCT basis functions for partial % derivatives of deformation fields w.r.t. modelled % effects. Scaled such that resulting deformation % fields have units mm^-1 or deg^-1 (and squares % thereof). % .SS - Sum of squared errors for each iteration. % % % This is a major rewrite which uses some new ideas to speed up % the estimation of the field. The time consuming part is the % evaluation of A'*A where A is a matrix with the partial % derivatives for each scan with respect to the parameters % describing the warp-fields. If we denote the derivative % matrix for a single scan by Ai, then the estimation of A'*A % is A'*A = A1'*A1 + A2'*A2 + ... +An'*An where n is the number % of scans in the time-series. If we model the partial-derivative % fields w.r.t. two movement parameters (e.g. pitch and roll), each % by [8 8 8] basis-functions and the image dimensions are % 64x64x64 then each Ai is a 262144x1024 matrix and we need to % evaluate and add n of these 1024x1024 matrices. It takes a while. % % The new idea is based on the realisation that each of these % matrices is the kroneceker-product of the relevant movement % parameters, our basis set and a linear combination (given by % one column of the inverse of the rotation matrix) of the image % gradients in the x-, y- and z-directions. This means that % they really aren't all that unique, and that the amount of % information in these matrices doesn't really warrant all % those calculations. After a lot of head-scratching I arrived % at the following % % First some definitions % % n: no. of voxels % m: no. of scans % l: no. of effects to model % order: [xorder yorder zorder] no. of basis functions % q: mxl matrix of scaled realignment parameters for effects to model. % T{i}: inv(inv(P(i).mat)*P(1).mat); % t(i,:) = T{i}(1:3,2)'; % B: kron(Bz,By,Bx); % Ax = repmat(dx,1,prod(order)).*B; % Ay = repmat(dy,1,prod(order)).*B; % Az = repmat(dz,1,prod(order)).*B; % % Now, my hypothesis is that A'*A is given by % % AtA = kron((q.*kron(ones(1,l),t(:,1)))'*(q.*kron(ones(1,l),t(:,1))),Ax'*Ax) +... % kron((q.*kron(ones(1,l),t(:,2)))'*(q.*kron(ones(1,l),t(:,2))),Ay'*Ay) +... % kron((q.*kron(ones(1,l),t(:,3)))'*(q.*kron(ones(1,l),t(:,3))),Az'*Az) +... % 2*kron((q.*kron(ones(1,l),t(:,1)))'*(q.*kron(ones(1,l),t(:,2))),Ax'*Ay) +... % 2*kron((q.*kron(ones(1,l),t(:,1)))'*(q.*kron(ones(1,l),t(:,3))),Ax'*Az) +... % 2*kron((q.*kron(ones(1,l),t(:,2)))'*(q.*kron(ones(1,l),t(:,3))),Ay'*Az); % % Which turns out to be true. This means that regardless of how many % scans we have we will always be able to create AtA as a sum of % six individual AtAs. It has been tested against the previous % implementation and yields exactly identical results. % % I know this isn't much of a derivation, but there will be a paper soon. Sorry. % % Other things that are new for the rewrite is % 1. We have removed the possibility to try and estimate the "static" field. % There simply isn't enough information about that field, and for a % given time series the estimation is just too likely to fail. % 2. New option to pass a static field (e.g. estimated from a dual % echo-time measurement) as an input parameter. % 3. Re-estimation of the movement parameters at each iteration. % Let us say we have a nodding motion in the time series, and % at each nod the brain appear to shrink in the phase-encode % direction. The realignment will find the nods, but might in % addition mistake the "shrinks" for translations, leading to % biased estimates. We attempt to correct that by, at iteration, % updating both parameters pertaining to distortions and to % movement. In order to do so in an unbiased fashion we have % also switched from sampling of images (and deformation fields) % on a grid centered on the voxel-centers, to a grid whith a % different sampling frequency. % 4. Inclusion of a regularisation term. The speed-up has facilitated % using more basis-functions, which makes it neccessary to impose % regularisation (i.e. punisihing some order derivative of the % deformation field). % 5. Change of interpolation model from tri-linear/Sinc to % tri-linear/B-spline. % 6. Option to include the Jacobian compression/stretching effects % in the model for the estimation of the displacement fields. % Our tests have indicated that this is NOT a good idea though. % %_______________________________________________________________________ % % Definition of some of the variables in this routine. % % %_______________________________________________________________________ % @(#)spm_uw_estimate.m 1.5 Jesper Andersson 03/07/22 if nargin < 1 | isempty(P), P = spm_get(Inf,'*.img'); end if ~isstruct(P), P = spm_vol(P); end % % Default input parameters. % defpar = struct('order', [10 10],...                 'sfield', [],...                 'M', P(1).mat,...                 'sf_acq', 'First',...                 'regorder', 1,...                 'lambda', 1e5,...                 'jm', 0,...                 'fot', [4 5],...                 'sot', [],...                 'fwhm', 4,...                 'rem', 1,...                 'exp_round', 'Average',...                 'noi', 5,...                 'hold', [1 1 1 0 1 0]); defnames = fieldnames(defpar); % % Go through input parameters, chosing the default % for any parameters that are missing, warning the % user if there are "unknown" parameters (probably % reflecting a misspelling). % if nargin < 2 | isempty(par)    par = defpar; end ds = []; for i=1:length(defnames)    if isfield(par,defnames{i}) & ~isempty(getfield(par,defnames{i}))       ds = setfield(ds,defnames{i},getfield(par,defnames{i}));    else       ds = setfield(ds,defnames{i},getfield(defpar,defnames{i}));    end end parnames = fieldnames(par); for i=1:length(parnames)    if ~isfield(defpar,parnames{i})       warning(sprintf('Unknown par field %s',parnames{i}));    end end % % Resolve ambiguities. % if length(ds.order) == 2    mm = sqrt(sum(P(1).mat(1:3,1:3).^2)).*P(1).dim(1:3);    ds.order(3) = round(ds.order(1)*mm(3)/mm(1)); end if size(ds.sfield,1) == prod(ds.order)    ds.sfield = spm_get_def(P(1).dim(1:3),ds.order,ds.sfield); elseif ~isempty(ds.sfield) & size(ds.sfield,1) ~= prod(P(1).dim(1:3))    error('Incompatible size of static field'); end nscan = length(P); nof = prod(size(ds.fot)) + size(ds.sot,1); ds.P = P; % % Get matrix of 'expansion point'-corrected movement parameters % for which we seek partial derivative fields. % [ds.q,ds.ep] = make_q(P,ds.fot,ds.sot,ds.exp_round); % % Create matrix for regularisation of warps. % H = make_H(P,ds.order,ds.regorder); % % Create a temporary smooth time series to use for % the estimation. % old_P = P; if ds.fwhm ~= 0    spm_uw_show('SmoothStart',length(P));    for i=1:length(old_P)       spm_uw_show('SmoothUpdate',i);       sfname(i,:) = [tempname '.img'];       spm_smooth(old_P(i).fname,sfname(i,:),ds.fwhm);    end    P = spm_vol(sfname);    spm_uw_show('SmoothEnd'); end % % Now that we have littered the disk with smooth % temporary files we should use a try-catch % block for the rest of the function, to ensure files % get deleted in the event of an error. Hence, this % routine will work only with Matlab 5.2 and higher. % %try % Try block starts here % % Initialize some stuff. % beta0 = zeros(nof*prod(ds.order),10); beta = zeros(nof*prod(ds.order),1); old_beta = zeros(nof*prod(ds.order),1); % % Sample images on irregular grid to avoid biasing % re-estimated movement parameters with smoothing % effect from voxel-interpolation (See Andersson , % EJNM (1998), 25:575-586.). % ss = [1.1 1.1 0.9]; xs = 1:ss(1):P(1).dim(1); xs = xs + (P(1).dim(1)-xs(end)) / 2; ys = 1:ss(2):P(1).dim(2); ys = ys + (P(1).dim(2)-ys(end)) / 2; zs = 1:ss(3):P(1).dim(3); zs = zs + (P(1).dim(3)-zs(end)) / 2; M = spm_matrix([-xs(1)/ss(1)+1 -ys(1)/ss(2)+1 -zs(1)/ss(3)+1])*inv(diag([ss 1]))*eye(4); nx = length(xs); ny = length(ys); nz = length(zs); [x,y,z] = ndgrid(xs,ys,zs); Bx = spm_dctmtx(P(1).dim(1),ds.order(1),x(:,1,1)); By = spm_dctmtx(P(1).dim(2),ds.order(2),y(1,:,1)); Bz = spm_dctmtx(P(1).dim(3),ds.order(3),z(1,1,:)); dBy = spm_dctmtx(P(1).dim(2),ds.order(2),y(1,:,1),'diff'); xyz = [x(:) y(:) z(:) ones(length(x(:)),1)]; clear x y z; def = zeros(size(xyz,1),nof); ddefa = zeros(size(xyz,1),nof); % % Create file struct for use with spm_orthviews to draw % representations of the field. % dispP = P(1); dispP = rmfield(dispP,{'fname','descrip','n','private'}); dispP.dim = [nx ny nz 64]; dispP.pinfo = [1 0]'; p = spm_imatrix(dispP.mat); p = p.*[zeros(1,6) ss 0 0 0]; p(1) = -mean(1:nx)*p(7); p(2) = -mean(1:ny)*p(8); p(3) = -mean(1:nz)*p(9); dispP.mat = spm_matrix(p); clear p; % % We will need to resample the static field (if one was supplied) % on the same grid (given by xs, ys and zs) as we are going to use % for the time series. % if isfield(ds,'sfield')    ds.orig_sfield = ds.sfield;    tP = P(1); % Assuming field in same space as first image    tP.dim(4) = 64;    tP.pinfo = [1 0]';    T = tP.mat\ds.M;    txyz = xyz*T(1:3,:)';    tP.dat = reshape(ds.orig_sfield,tP.dim(1:3));    c = spm_bsplinc(tP,ds.hold);    ds.sfield = spm_bsplins(c,txyz(:,1),txyz(:,2),txyz(:,3),ds.hold);    ds.sfield = ds.sfield(:);    clear c txyz tP; end msk = get_mask(P,xyz,ds,[nx ny nz]); ssq = []; % % Here starts iterative search for deformation fields. % for iter=1:ds.noi    spm_uw_show('NewIter',iter);    [ref,dx,dy,dz,P,ds,sf,dispP] = make_ref(ds,def,ddefa,P,xyz,M,msk,beta,dispP);    AtA = build_AtA(ref,dx,dy,dz,Bx,By,Bz,dBy,ds,P);    [Aty,yty] = build_Aty(ref,dx,dy,dz,Bx,By,Bz,dBy,ds,P,xyz,beta,sf,def,ddefa,msk);    % Clean up a bit, cause inverting AtA may use a lot of memory    clear ref dx dy dz    % Check that residual error still decreases.    if iter > 1 & yty > ssq(iter-1)       %       % This means previous iteration was no good,       % and we should go back to old_beta.       %       beta = old_beta;       break;    else       ssq(iter) = yty;       spm_uw_show('StartInv',1);       % Solve for beta       Aty = Aty + AtA*beta;       AtA = AtA + ds.lambda * kron(eye(nof),diag(H)) * ssq(iter)/(nscan*sum(msk));       try % Fastest if it works          beta0(:,iter) = AtA\Aty;       catch % Sometimes necessary          beta0(:,iter) = pinv(AtA)*Aty;       end       old_beta = beta;       beta = beta0(:,iter);       for i=1:nof          def(:,i) = spm_get_def(Bx, By,Bz,beta((i-1)*prod(ds.order)+1:i*prod(ds.order)));          ddefa(:,i) = spm_get_def(Bx,dBy,Bz,beta((i-1)*prod(ds.order)+1:i*prod(ds.order)));       end       % If we are re-estimating the movement parameters, remove any DC       % components from the deformation fields, so that they end up in       % the movement-parameters instead. It shouldn't make any difference       % to the variance reduction, but might potentially lead to a better       % explanation of the variance components.       % Note that since we sub-sample the images (and the DCT basis set)       % it is NOT sufficient to reset beta(1) (and beta(prod(order)+1) etc,       % instead we explicitly subtract the DC component. Note that a DC       % component does NOT affect the Jacobian.       %       if ds.rem ~= 0          def = def - repmat(mean(def),length(def),1);       end       spm_uw_show('EndInv');       tmp = dispP.mat;       dispP.mat = P(1).mat;       spm_uw_show('FinIter',ssq,def,ds.fot,ds.sot,dispP,ds.q);       dispP.mat = tmp;    end    clear AtA end ds.P = old_P; for i=1:length(ds.P)    ds.P(i).mat = P(i).mat; % Save P with new movement parameters. end ds.beta = reshape(refit(P,dispP,ds,def),prod(ds.order),nof); ds.SS = ssq; if isfield(ds,'orig_sfield');    ds.sfield = ds.orig_sfield;    ds = rmfield(ds,'orig_sfield'); end cleanup(P,ds) spm_uw_show('FinTot'); % catch % Try block ends here    cleanup(P,ds)    spm_uw_show('FinTot');    fprintf('procedure terminated abnormally:\n%s',lasterr); % end % Catch block ends here. return %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Utility functions. % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [q,ep] = make_q(P,fot,sot,exp_round) % % P : Array of file-handles % fot : nx1 array of indicies for first order effect. % sot : nx2 matrix of indicies of second order effects. % exp_round : Point in position space to perform Taylor-expansion % around ('First','Last' or 'Average'). 'Average' should % (in principle) give the best variance reduction. If a % field-map acquired before the time-series is supplied % then expansion around the 'First' MIGHT give a slightly % better average geometric fidelity. if strcmp(lower(exp_round),'average');    %    % Get geometric mean of all transformation matrices.    % This will be used as the zero-point in the space    % of object position vectors (i.e. the point at which    % the partial derivatives are estimated). This is presumably    % a little more correct than taking the average of the    % parameter estimates.    %    mT = zeros(4);    for i=1:length(P)       mT = mT+logm(inv(P(i).mat) * P(1).mat);    end    mT = real(expm(mT/length(P))); elseif strcmp(lower(exp_round),'first');    mT = eye(4); elseif strcmp(lower(exp_round),'last');    mT = inv(P(end).mat) * P(1).mat; else    warning(sprintf('Unknown expansion point %s',exp_round)); end % % Rescaling to degrees makes translations and rotations % roughly equally scaled. Since the scaling influences % strongly the effects of regularisation, it would surely % be nice with a more principled approach. Suggestions % anyone? % ep = [1 1 1 180/pi 180/pi 180/pi zeros(1,6)] .* spm_imatrix(mT); % % Now, get a nscan-by-nof matrix containing % mean (expansion point) corrected values for each effect we % model. % q = zeros(length(P),prod(size(fot)) + size(sot,1)); for i=1:length(P)    p = [1 1 1 180/pi 180/pi 180/pi zeros(1,6)] .*...       spm_imatrix(inv(P(i).mat) * P(1).mat);    for j=1:prod(size(fot))       q(i,j) = p(fot(j)) - ep(fot(j));    end    for j=1:size(sot,1)       q(i,prod(size(fot))+j) = (p(sot(j,1)) - ep(sot(j,1))) * (p(sot(j,2)) - ep(sot(j,2)));    end end return %_______________________________________________________________________ %_______________________________________________________________________ function H = make_H(P,order,regorder) % Utility Function to create Regularisation term of AtA. mm = sqrt(sum(P(1).mat(1:3,1:3).^2)).*P(1).dim(1:3); kx=(pi*((1:order(1))'-1)/mm(1)).^2; ky=(pi*((1:order(2))'-1)/mm(2)).^2; kz=(pi*((1:order(3))'-1)/mm(3)).^2; if regorder == 0    %    % Cost function based on sum of squares    %    H = (1*kron(kz.^0,kron(ky.^0,kx.^0)) +...         1*kron(kz.^0,kron(ky.^0,kx.^0)) +...         1*kron(kz.^0,kron(ky.^0,kx.^0)) ); elseif regorder == 1    %    % Cost function based on sum of squared 1st derivatives    %    H = (1*kron(kz.^1,kron(ky.^0,kx.^0)) +...          1*kron(kz.^0,kron(ky.^1,kx.^0)) +...          1*kron(kz.^0,kron(ky.^0,kx.^1)) ); elseif regorder == 2    %    % Cost function based on sum of squared 2nd derivatives    %    H = (1*kron(kz.^2,kron(ky.^0,kx.^0)) +...         1*kron(kz.^0,kron(ky.^2,kx.^0)) +...         1*kron(kz.^0,kron(ky.^0,kx.^2)) +...         3*kron(kz.^1,kron(ky.^1,kx.^0)) +...         3*kron(kz.^1,kron(ky.^0,kx.^1)) +...         3*kron(kz.^0,kron(ky.^1,kx.^1)) ); elseif regorder == 3    %    % Cost function based on sum of squared 3rd derivatives    %    H = (1*kron(kz.^3,kron(ky.^0,kx.^0)) +...         1*kron(kz.^0,kron(ky.^3,kx.^0)) +...         1*kron(kz.^0,kron(ky.^0,kx.^3)) +...         3*kron(kz.^2,kron(ky.^1,kx.^0)) +...         3*kron(kz.^2,kron(ky.^0,kx.^1)) +...         3*kron(kz.^1,kron(ky.^2,kx.^0)) +...         3*kron(kz.^0,kron(ky.^2,kx.^1)) +...         3*kron(kz.^1,kron(ky.^0,kx.^2)) +...         3*kron(kz.^0,kron(ky.^1,kx.^2)) +...         6*kron(kz.^1,kron(ky.^1,kx.^1)) ); else    error('Invalid order of regularisation'); end return %_______________________________________________________________________ %_______________________________________________________________________ function AtA = build_AtA(ref,dx,dy,dz,Bx,By,Bz,dBy,ds,P) % Now lets build up the design matrix A, or rather A'*A since % A itself would be forbiddingly large. if ds.jm, spm_uw_show('StartAtA',10); else spm_uw_show('StartAtA',6); end nof = prod(size(ds.fot)) + size(ds.sot,1); AxtAx = uwAtA1(dx.*dx,Bx,By,Bz); spm_uw_show('NewAtA',1); AytAy = uwAtA1(dy.*dy,Bx,By,Bz); spm_uw_show('NewAtA',2); AztAz = uwAtA1(dz.*dz,Bx,By,Bz); spm_uw_show('NewAtA',3); AxtAy = uwAtA1(dx.*dy,Bx,By,Bz); spm_uw_show('NewAtA',4); AxtAz = uwAtA1(dx.*dz,Bx,By,Bz); spm_uw_show('NewAtA',5); AytAz = uwAtA1(dy.*dz,Bx,By,Bz); spm_uw_show('NewAtA',6); if ds.jm    AjtAj = uwAtA1(ref.*ref,Bx,dBy,Bz); spm_uw_show('NewAtA',7);    AxtAj = uwAtA2( dx.*ref,Bx, By,Bz,Bx,dBy,Bz); spm_uw_show('NewAtA',8);    AytAj = uwAtA2( dy.*ref,Bx, By,Bz,Bx,dBy,Bz); spm_uw_show('NewAtA',9);    AztAj = uwAtA2( dz.*ref,Bx, By,Bz,Bx,dBy,Bz); spm_uw_show('NewAtA',10); end R = zeros(length(P),3); for i=1:length(P)    tmp = inv(P(i).mat\P(1).mat);    R(i,:) = tmp(1:3,2)'; end tmp = ones(1,nof); tmp1 = ds.q.*kron(tmp,R(:,1)); tmp2 = ds.q.*kron(tmp,R(:,2)); tmp3 = ds.q.*kron(tmp,R(:,3)); AtA = kron(tmp1'*tmp1,AxtAx) + kron(tmp2'*tmp2,AytAy) + kron(tmp3'*tmp3,AztAz) +...        2*(kron(tmp1'*tmp2,AxtAy) + kron(tmp1'*tmp3,AxtAz) + kron(tmp2'*tmp3,AytAz)); if ds.jm    tmp = [ds.q.*kron(tmp,ones(length(P),1))];    AtA = AtA + kron(tmp'*tmp,AjtAj) +...              2*(kron(tmp1'*tmp,AxtAj) + kron(tmp2'*tmp,AytAj) + kron(tmp3'*tmp,AztAj)); end spm_uw_show('EndAtA'); return; %_______________________________________________________________________ %_______________________________________________________________________ function AtA = uwAtA1(y,Bx,By,Bz) % Calculating off-diagonal block of AtA. [nx,mx] = size(Bx); [ny,my] = size(By); [nz,mz] = size(Bz); AtA = zeros(mx*my*mz); for sl =1:nz    tmp = reshape(y((sl-1)*nx*ny+1:sl*nx*ny),nx,ny);    AtA = AtA + kron(Bz(sl,:)'*Bz(sl,:),spm_krutil(tmp,Bx,By,1)); end return %_______________________________________________________________________ %_______________________________________________________________________ function AtA = uwAtA2(y,Bx1,By1,Bz1,Bx2,By2,Bz2) % Calculating cross-term of diagonal block of AtA % when A is a sum of the type A1+A2 and where both % A1 and A2 are possible to express as a kronecker % product of lesser matrices. [nx,mx1] = size(Bx1,1); [nx,mx2] = size(Bx2,1); [ny,my1] = size(By1,1); [ny,my2] = size(By2,1); [nz,mz1] = size(Bz1,1); [nz,mz2] = size(Bz2,1); AtA = zeros(mx1*my1*mz1,mx2*my2*mz2); for sl =1:nz    tmp = reshape(y((sl-1)*nx*ny+1:sl*nx*ny),nx,ny);    AtA = AtA + kron(Bz1(sl,:)'*Bz2(sl,:),spm_krutil(tmp,Bx1,By1,Bx2,By2)); end return %_______________________________________________________________________ %_______________________________________________________________________ function [Aty,yty] = build_Aty(ref,dx,dy,dz,Bx,By,Bz,dBy,ds,P,xyz,beta,sf,def,ddefa,msk) % Building Aty. nof = prod(size(ds.fot)) + size(ds.sot,1); Aty = zeros(nof*prod(ds.order),1); yty = 0; spm_uw_show('StartAty',length(P)); for scan = 1:length(P)    spm_uw_show('NewAty',scan);    T = P(scan).mat\ds.M;    txyz = xyz*T(1:3,:)';    if ~(all(beta == 0) & isempty(ds.sfield))       [idef,jac] = spm_get_image_def(scan,ds,def,ddefa);       txyz(:,2) = txyz(:,2)+idef;    end;    c = spm_bsplinc(P(scan),ds.hold);    y = sf(scan) * spm_bsplins(c,txyz(:,1),txyz(:,2),txyz(:,3),ds.hold);    if ds.jm & ~(all(beta == 0) & isempty(ds.sfield))       y = y .* jac;    end;    y_diff = (ref - y).*msk;    indx = find(isnan(y));    y_diff(indx) = 0;    iTcol = inv(T(1:3,1:3));    tmpAty = spm_get_def(Bx',By',Bz',([dx dy dz]*iTcol(:,2)).*y_diff);    if ds.jm ~= 0       tmpAty = tmpAty + spm_get_def(Bx',dBy',Bz',ref.*y_diff);    end    for i=1:nof       rindx = (i-1)*prod(ds.order)+1:i*prod(ds.order);       Aty(rindx) = Aty(rindx) + ds.q(scan,i)*tmpAty;    end    yty = yty + y_diff'*y_diff; end spm_uw_show('EndAty'); return; %_______________________________________________________________________ %_______________________________________________________________________ function [ref,dx,dy,dz,P,ds,sf,dispP] = make_ref(ds,def,ddefa,P,xyz,M,msk,beta,dispP) % First of all get the mean of all scans given their % present deformation fields. When using this as the % "reference" we will explicitly be minimising variance. % % First scan in P is still reference in terms of % y-direction (in the scanner framework). A single set of % image gradients is estimated from the mean of all scans, % transformed into the space of P(1), and used for all scans. % spm_uw_show('StartRef',length(P)); rem = ds.rem; if all(beta==0), rem=0; end; if rem    [m_ref,D] = get_refD(ds,def,ddefa,P,xyz,msk); end ref = zeros(size(xyz,1),1); for i=1:length(P)    spm_uw_show('NewRef',i);    T = P(i).mat\ds.M;    txyz = xyz*T(1:3,:)';    if ~(all(beta == 0) & isempty(ds.sfield))       [idef,jac] = spm_get_image_def(i,ds,def,ddefa);       txyz(:,2) = txyz(:,2)+idef;    end;    c = spm_bsplinc(P(i),ds.hold);    f = spm_bsplins(c,txyz(:,1),txyz(:,2),txyz(:,3),ds.hold);    if ds.jm ~= 0 & exist('jac')==1       f = f .* jac;    end    indx = find(~isnan(f));    sf(i) = 1 / (sum(f(indx).*msk(indx)) / sum(msk(indx)));    ref = ref + f;    if rem       indx = find(isnan(f)); f(indx) = 0;       Dty{i} = (((m_ref - sf(i)*f).*msk)'*D)';    end end ref = ref / length(P); ref = reshape(ref,dispP.dim(1:3)); indx = find(~isnan(ref)); % Scale to roughly 100 mean intensity to ensure % consistent weighting of regularisation. gl = spm_global(ref); sf = (100 * (sum(ref(indx).*msk(indx)) / sum(msk(indx))) / gl) * sf; ref = (100 / gl) * ref; dispP.dat = ref; c = spm_bsplinc(ref,ds.hold); txyz = xyz*M(1:3,:)'; [ref,dx,dy,dz] = spm_bsplins(c,txyz(:,1),txyz(:,2),txyz(:,3),ds.hold); ref = ref.*msk; dx = dx.*msk; dy = dy.*msk; dz = dz.*msk; % Re-estimate (or rather nudge) movement parameters. if rem ~= 0    iDtD = inv(spm_atranspa(D));    for i=2:length(P)       P(i).mat = inv(spm_matrix((iDtD*Dty{i})'))*P(i).mat;    end    [ds.q,ds.p0] = make_q(P,ds.fot,ds.sot,ds.exp_round); end spm_uw_show('EndRef'); return %_______________________________________________________________________ %_______________________________________________________________________ function [m_ref,D] = get_refD(ds,def,ddefa,P,xyz,msk) % Get partials w.r.t. movements from first scan. [idef,jac] = spm_get_image_def(1,ds,def,ddefa); T = P(1).mat\ds.M; txyz = xyz*T'; c = spm_bsplinc(P(1),ds.hold); [m_ref,dx,dy,dz] = spm_bsplins(c,txyz(:,1),...                    txyz(:,2)+idef,txyz(:,3),ds.hold); indx = ~isnan(m_ref); mref_sf = 1 / (sum(m_ref(indx).*msk(indx)) / sum(msk(indx))); m_ref(indx) = m_ref(indx) .* mref_sf; m_ref(~indx) = 0; dx(indx) = dx(indx) .* mref_sf; dx(~indx) = 0; dy(indx) = dy(indx) .* mref_sf; dy(~indx) = 0; dz(indx) = dz(indx) .* mref_sf; dz(~indx) = 0; if ds.jm ~= 0    m_ref = m_ref .* jac;    dx = dx .* jac;    dy = dy .* jac;    dz = dz .* jac; end D = make_D(dx.*msk,dy.*msk,dz.*msk,txyz,P(1).mat); return; %_______________________________________________________________________ %_______________________________________________________________________ function D = make_D(dx,dy,dz,xyz,M) % Utility function that creates a matrix of partial % derivatives in units of /mm and /radian. % % dx,dy,dz - Partial derivatives (/pixel) wrt x-, y- and z-translation. % xyz - xyz-matrix (original positions). % M - Current voxel->world matrix. D = zeros(length(xyz),6); tiny = 0.0001; for i=1:6    p = [0 0 0 0 0 0 1 1 1 0 0 0];    p(i) = p(i)+tiny;    T = M\spm_matrix(p)*M;    dxyz = xyz*T';    dxyz = dxyz(:,1:3)-xyz(:,1:3);    D(:,i) = sum(dxyz.*[dx dy dz],2)/tiny; end return %_______________________________________________________________________ %_______________________________________________________________________ function cleanup(P,ds) % Delete temporary smooth files. % if ~isempty(ds.fwhm) & ds.fwhm > 0    for i=1:length(P)       spm_unlink(P(i).fname);       [fpath,fname,ext] = fileparts(P(i).fname);       spm_unlink(fullfile(fpath,[fname '.hdr']));       spm_unlink(fullfile(fpath,[fname '.mat']));    end end return; %_______________________________________________________________________ %_______________________________________________________________________ function beta = refit(P,dispP,ds,def) % We have now estimated the fields on a grid that % does not coincide with the voxel centers. We must % now calculate the betas that correspond to a % a grid centered on the voxel centers. % spm_uw_show('StartRefit',1); rsP = P(1); p = spm_imatrix(rsP.mat); p = [zeros(1,6) p(7:9) 0 0 0]; p(1) = -mean(1:rsP.dim(1))*p(7); p(2) = -mean(1:rsP.dim(2))*p(8); p(3) = -mean(1:rsP.dim(3))*p(9); rsP.mat = spm_matrix(p); clear p; [x,y,z] = ndgrid(1:rsP.dim(1),1:rsP.dim(2),1:rsP.dim(3)); xyz = [x(:) y(:) z(:) ones(prod(size(x)),1)]; txyz = ((inv(dispP.mat)*rsP.mat)*xyz')'; Bx = spm_dctmtx(rsP.dim(1),ds.order(1)); By = spm_dctmtx(rsP.dim(2),ds.order(2)); Bz = spm_dctmtx(rsP.dim(3),ds.order(3)); nx = rsP.dim(1); mx = ds.order(1); ny = rsP.dim(2); my = ds.order(2); nz = rsP.dim(3); mz = ds.order(3); nof = prod(size(ds.fot)) + size(ds.sot,1); for i=1:nof    dispP.dat = reshape(def(:,i),dispP.dim(1:3));    c = spm_bsplinc(dispP,ds.hold);    field = spm_bsplins(c,txyz(:,1),txyz(:,2),txyz(:,3),ds.hold);    indx = isnan(field);    wgt = ones(size(field));    wgt(indx) = 0;    field(indx) = 0;    AtA = zeros(mx*my*mz);    Aty = zeros(mx*my*mz,1);    for sl = 1:nz       indx = (sl-1)*nx*ny+1:sl*nx*ny;       tmp1 = reshape(field(indx).*wgt(indx),nx,ny);       tmp2 = reshape(wgt(indx),nx,ny);       AtA = AtA + kron(Bz(sl,:)'*Bz(sl,:),spm_krutil(tmp2,Bx,By,1));       Aty = Aty + kron(Bz(sl,:)',spm_krutil(tmp1,Bx,By,0));    end    beta((i-1)*prod(ds.order)+1:i*prod(ds.order)) = AtA\Aty; end spm_uw_show('EndRefit'); return; %_______________________________________________________________________ %_______________________________________________________________________ function msk = get_mask(P,xyz,ds,dm) % % Create a mask to avoid regions where data doesnt exist % for all scans. This mask is slightly less Q&D than that % of version 1 of Unwarp. It checks where data exist for % all scans with present movement parameters and given % (optionally) the static field. It creates a mask with % non-zero values only for those voxels, and then does a % 3D erode to preempt effects of re-estimated movement % parameters and movement-by-susceptibility effects. % spm_uw_show('MaskStart',length(P)); msk = logical(ones(length(xyz),1)); for i=1:length(P)    txyz = xyz * (P(i).mat\ds.M)';    tmsk = (txyz(:,1)>=1 & txyz(:,1)<=P(1).dim(1) &...            txyz(:,2)>=1 & txyz(:,2)<=P(1).dim(2) &...            txyz(:,3)>=1 & txyz(:,3)<=P(1).dim(3));    msk = msk & tmsk;    spm_uw_show('MaskUpdate',i); end msk = erode_msk(msk,dm); spm_uw_show('MaskEnd'); % maskP = P(1); % [mypath,myname,myext] = fileparts(maskP.fname); % maskP.fname = fullfile(mypath,['mask' myext]); % maskP.dim = [nx ny nz P(1).dim(4)]; % maskP = spm_write_vol(maskP,reshape(msk,[nx ny nz])); return; %_______________________________________________________________________ %_______________________________________________________________________ function omsk = erode_msk(msk,dim) omsk = zeros(dim+[4 4 4]); omsk(3:end-2,3:end-2,3:end-2) = reshape(msk,dim); omsk = spm_erode(omsk(:),dim+[4 4 4]); omsk = reshape(omsk,dim+[4 4 4]); omsk = omsk(3:end-2,3:end-2,3:end-2); omsk = omsk(:); return %_______________________________________________________________________

Top of Message | Previous Page | Permalink

JiscMail Tools


RSS Feeds and Sharing


Advanced Options


Archives

April 2024
March 2024
February 2024
January 2024
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
December 2021
November 2021
October 2021
September 2021
August 2021
July 2021
June 2021
May 2021
April 2021
March 2021
February 2021
January 2021
December 2020
November 2020
October 2020
September 2020
August 2020
July 2020
June 2020
May 2020
April 2020
March 2020
February 2020
January 2020
December 2019
November 2019
October 2019
September 2019
August 2019
July 2019
June 2019
May 2019
April 2019
March 2019
February 2019
January 2019
December 2018
November 2018
October 2018
September 2018
August 2018
July 2018
June 2018
May 2018
April 2018
March 2018
February 2018
January 2018
December 2017
November 2017
October 2017
September 2017
August 2017
July 2017
June 2017
May 2017
April 2017
March 2017
February 2017
January 2017
December 2016
November 2016
October 2016
September 2016
August 2016
July 2016
June 2016
May 2016
April 2016
March 2016
February 2016
January 2016
December 2015
November 2015
October 2015
September 2015
August 2015
July 2015
June 2015
May 2015
April 2015
March 2015
February 2015
January 2015
December 2014
November 2014
October 2014
September 2014
August 2014
July 2014
June 2014
May 2014
April 2014
March 2014
February 2014
January 2014
December 2013
November 2013
October 2013
September 2013
August 2013
July 2013
June 2013
May 2013
April 2013
March 2013
February 2013
January 2013
December 2012
November 2012
October 2012
September 2012
August 2012
July 2012
June 2012
May 2012
April 2012
March 2012
February 2012
January 2012
December 2011
November 2011
October 2011
September 2011
August 2011
July 2011
June 2011
May 2011
April 2011
March 2011
February 2011
January 2011
December 2010
November 2010
October 2010
September 2010
August 2010
July 2010
June 2010
May 2010
April 2010
March 2010
February 2010
January 2010
December 2009
November 2009
October 2009
September 2009
August 2009
July 2009
June 2009
May 2009
April 2009
March 2009
February 2009
January 2009
December 2008
November 2008
October 2008
September 2008
August 2008
July 2008
June 2008
May 2008
April 2008
March 2008
February 2008
January 2008
December 2007
November 2007
October 2007
September 2007
August 2007
July 2007
June 2007
May 2007
April 2007
March 2007
February 2007
January 2007
2006
2005
2004
2003
2002
2001
2000
1999
1998


JiscMail is a Jisc service.

View our service policies at https://www.jiscmail.ac.uk/policyandsecurity/ and Jisc's privacy policy at https://www.jisc.ac.uk/website/privacy-notice

For help and support help@jisc.ac.uk

Secured by F-Secure Anti-Virus CataList Email List Search Powered by the LISTSERV Email List Manager