Code covered by the BSD License  

Highlights from
multimodality non-rigid demon algorithm image registration

image thumbnail
from multimodality non-rigid demon algorithm image registration by Dirk-Jan Kroon
non-rigid 2D and 3D image registration with demon (fluid) algorithm, extended with modality transf.

[E,Egrad]=demons_energy(M,F,M_TF,F_TF,T,sizes,options)
function [E,Egrad]=demons_energy(M,F,M_TF,F_TF,T,sizes,options)
% This function DEMONS_ENERGY calculates the registration energy and
% gradient of the registration energy at each pixel. Which can be used by an 
% (steepest gradient) optimizer to register two images.
%
% The energy gradient on each pixel equals the the demon velocity field 
% which is  described by the paper of Thirion 1998 and extended 
% by Cachier 1999 and He Wang 2005. 
%  
% GradientPixels =-(ImageStatic-ImageMoving) * 
%    ((GradientImageStatic./(||GradientImageStatic||^2+alpha^2*(ImageStatic-ImageMoving)^2))+
%    (GradientImageMoving./(||GradientImageMoving||^2+alpha^2*(ImageStatic-ImageMoving)^2)));
%
% This gradient is gaussian smoothed by this function to get fluid regularization.
% 
% Also the energy value itself at a certain transformation is calculated
%    E =(ImageStatic-ImageMoving)^2 + 
%         alpha^2*(ImageStatic-ImageMoving)^2.*||UpdateTransformationField||^2;
% 
% This energy value equation is not described by Thirion but needed by the
% line search of the optimizer. The paper by Tom Vercauteren et Al.
% "Non-parametric Diffeomorphic Image ...", gives more insight on how the
% Thirions equation can be derived from it.
%
% The gradient of the transformation field it self can also be smoothed by
% this function to get diffusion regularization (not part of original 
% demon registration).
%
% [E,Egrad]=DEMONS_ENERGY(M,F,M_TF,F_TF,T,SIZES,OPTIONS)
%
% inputs,
%  M: 2D or 3D moving input image
%  F: 2D or 3D static image
%  M_TF: image M but then modality transformed into grey values of F. Only
%         needed in case of multiple modalities, otherwise set to []
%  F_TF: image F but then modality transformed into grey values of M. Only
%         needed in case of multiple modalities, otherwise set to []
%  T: Current transformation field as a long vector
%  SIZES: The dimensions of the transformation field variable
%  OPTIONS: The parameters.
%     OPTIONS.sigma_fluid : Sigma used to smooth gradient(/update) field
%                           (Fluid regularization)
%     OPTIONS.sigma_diff : Sigma used to smooth current transformation
%                           field (Diffusion regularization)
%     OPTIONS.alpha : Kind of noise suppression constant, see equations
%                      above.
%     OPTIONS.interpolation : linear (default) or cubic.
%
% Outputs,
%  E: Current registration energy (registration error)
%  Egrad: Energy gradient on all pixels
%
% note: This function works better with steepest gradient optimizers,
%       than other Matlab optimizers.
%
% Example 1,
%   % Read both images 
%    M=im2double(imread('lenag1.png'));
%    F=im2double(imread('lenag2.png'));
%   % Parameters
%    options.sigma_fluid=8; options.sigma_diff=0; options.alpha=1.5;
%   % Transformation field
%    T=zeros([size(M) 2]);
%   % Store the dimensions of transformation field, and make, a long vector from T
%    sizes=size(T); T=T(:);
%   % Start the demon energy registration optimizer
%    optim=struct('Display','iter','GradObj','on','MaxIter',500,'OutputFcn', @store_transf);
%    T=fminlbfgs(@(x)demons_energy(M,F,[],[],x,sizes,options),T,optim);
%   % Reshape O_trans from a vector to a matrix
%    T=reshape(T,sizes);
%   % If diffusion regularization is used: smooth transformation field
%    if(options.sigma_diff>0)
%      Hsmooth=fspecial('gaussian',[options.sigma_diff*6 options.sigma_diff*6],options.sigma_diff);
%      T(:,:,1)=imfilter(T(:,:,1),Hsmooth); T(:,:,2)=imfilter(T(:,:,2),Hsmooth);
%    end
%   % Transform the input image
%    Ms=movepixels(M,T(:,:,1),T(:,:,2));
%   % Show the registration results
%    figure,
%    subplot(1,3,1), imshow(M); title('input image 1');
%    subplot(1,3,2), imshow(F); title('input image 2');
%    subplot(1,3,3), imshow(Ms); title('transformed image 1');
%
% See also FMINSD, DEMONREGISTRATION
%
% Function is written by D.Kroon University of Twente (October 2008)

% Get transformation field of previous itteration
global last_transformation_field updatemovie;
if(isempty(last_transformation_field)), last_transformation_field=T; 
else
    if(nnz(size(last_transformation_field)-size(T))>0)
        last_transformation_field=T; 
    end
end

% Check/set input options
defaultoptions=struct('sigma_fluid',8, 'sigma_diff',0,'alpha',1.5,'interpolation','linear');
if(~exist('options','var')), 
    options=defaultoptions; 
else
    tags = fieldnames(defaultoptions);
    for i=1:length(tags)
         if(~isfield(options,tags{i})),  options.(tags{i})=defaultoptions.(tags{i}); end
    end
    if(length(tags)~=length(fieldnames(options))), 
        warning('BsplineRegistrationGradient:unknownoption','unknown options found');
    end
end
% Set all parameters
alpha=options.alpha;
sigma_diff=options.sigma_diff;
sigma_fluid=options.sigma_fluid;
if(strcmpi(options.interpolation(1),'l')), interpolation_mode=0; else interpolation_mode=2; end 
  
if(ndims(M)==2)
    C=reshape(last_transformation_field,sizes);
    cx=C(:,:,1); cy=C(:,:,2);

    % Get the current transformation update
    T=reshape(T,sizes);
    ux=T(:,:,1)-C(:,:,1); uy=T(:,:,2)-C(:,:,2);

    if(sigma_diff>0)
        % Smooth transformation field
        sx=imgaussian(cx,sigma_diff);
        sy=imgaussian(cy,sigma_diff);
    else
        sx=cx; sy=cy;
    end

     % Calculate current moving image
    Ms=movepixels(M,sx+ux,sy+uy,[],interpolation_mode);
    if(~isempty(M_TF)), 
        Ms_TF=movepixels(M_TF,sx+ux,sy+uy,[],interpolation_mode); 
    end
    
    % If no multiple modalities, set F_TF to F and Ms_TF to Ms
    if(isempty(F_TF)), F_TF=F; Ms_TF=Ms; end
    
    % Calculate difference image
    Idiff_M=Ms-F_TF;
    Idiff_F=Ms_TF-F;
            

    % Calculate error after current transformation
    E_M=Idiff_M.^2+alpha^2*Idiff_M.^2.*(ux.^2+uy.^2);
    E_F=Idiff_F.^2+alpha^2*Idiff_F.^2.*(ux.^2+uy.^2);
    
    E=0.5*(sum(E_M(:))+sum(E_F(:)));
        
    % Make movie
    if(updatemovie),
        makemovie(movepixels(M_TF,sx,sy,[],interpolation_mode));
        updatemovie=false;
    end
  
    
    % If gradient needed, also determine the gradient.
    if ( nargout > 1 )
        % Calculate gradients in both images
        [My,Mx] = gradient(Ms);
        [Fy,Fx] = gradient(F);

        % Calculate gradient (update field) in x and y direction
        Ma=1./(eps+(Mx.^2+My.^2)+alpha^2*Idiff_M.^2);
        Fa=1./(eps+(Fx.^2+Fy.^2)+alpha^2*Idiff_F.^2);
        ux=Idiff_F.*(Fx.*Fa)+Idiff_M.*(Mx.*Ma); 
        uy=Idiff_F.*(Fy.*Fa)+Idiff_M.*(My.*Ma);

        % Smooth gradient incase of fluid-like regularization
        if(sigma_fluid>0)
            ux=imgaussian(ux,sigma_fluid);
            uy=imgaussian(uy,sigma_fluid);
        end

        % Both x and y gradient to one output variable
        Egrad=zeros(size(T));
        Egrad(:,:,1)=ux;
        Egrad(:,:,2)=uy;
        Egrad=Egrad(:);
    end
else
    C=reshape(last_transformation_field,sizes);
    cx=C(:,:,:,1); cy=C(:,:,:,2); cz=C(:,:,:,3);

    % Get the current transformation update
    T=reshape(T,sizes);
    ux=T(:,:,:,1)-C(:,:,:,1); 
    uy=T(:,:,:,2)-C(:,:,:,2);
    uz=T(:,:,:,3)-C(:,:,:,3);

    if(sigma_diff>0)
        sx=imgaussian(cx,sigma_diff);
        sy=imgaussian(cy,sigma_diff);
        sz=imgaussian(cz,sigma_diff);
    else
        sx=cx; sy=cy; sz=cz;
    end 

    % Calculate current moving image
    Ms=movepixels(M,sx+ux,sy+uy,sz+uz,interpolation_mode);
    if(~isempty(M_TF)), 
        Ms_TF=movepixels(M_TF,sx+ux,sy+uy,sz+uz,interpolation_mode); 
    end
    
    % If no multiple modalities, set F_TF to F and Ms_TF to Ms
    if(isempty(F_TF)), F_TF=F; Ms_TF=Ms; end
    
    % Calculate difference image
    Idiff_M=Ms-F_TF;
    Idiff_F=Ms_TF-F;
    
    % Calculate error after current transformation
    E_M=Idiff_M.^2+alpha^2*Idiff_M.^2.*(ux.^2+uy.^2+uz.^2);
    E_F=Idiff_F.^2+alpha^2*Idiff_F.^2.*(ux.^2+uy.^2+uz.^2);
    
    E=0.5*(sum(E_M(:))+sum(E_F(:)));
        

    % If gradient needed, also determine the gradient.
    if ( nargout > 1 )
        % Calculate gradients in both images
        [My,Mx,Mz] = gradient(Ms);
        [Fy,Fx,Fz] = gradient(F);

        % Calculate gradient (update field) in x and y direction
        Ma=1./(eps+(Mx.^2+My.^2+Mz.^2)+alpha^2*Idiff_M.^2);
        Fa=1./(eps+(Fx.^2+Fy.^2+Fz.^2)+alpha^2*Idiff_F.^2);
        ux=Idiff_F.*(Fx.*Fa)+Idiff_M.*(Mx.*Ma); 
        uy=Idiff_F.*(Fy.*Fa)+Idiff_M.*(My.*Ma);
        uz=Idiff_F.*(Fz.*Fa)+Idiff_M.*(Mz.*Ma);
        
        % Smooth gradient incase of fluid-like regularization
        if(sigma_fluid>0)
            ux=imgaussian(ux,sigma_fluid);
            uy=imgaussian(uy,sigma_fluid);
            uz=imgaussian(uz,sigma_fluid);
        end

        % Both x and y and z gradient to one output variable
        Egrad=zeros(size(T));
        Egrad(:,:,:,1)=ux;
        Egrad(:,:,:,2)=uy;
        Egrad(:,:,:,3)=uz;
        Egrad=Egrad(:);
    end
end
    
function makemovie(I)
global Mmovie Mindex;
if(isempty(Mindex)), Mindex=1; end
I=imresize(I,[256 256]);
if(isempty(Mmovie)), 
    Mmovie = im2frame(uint8(I*256),gray(256));
else
    Mmovie(Mindex) = im2frame(uint8(I*256),gray(256));
end
Mindex=Mindex+1;



Contact us at files@mathworks.com