Code covered by the BSD License  

Highlights from
Interpolation with Reverse Diffusion

image thumbnail
from Interpolation with Reverse Diffusion by Olivier Salvado
Partial volume correction method using reverse diffusion interpolation

PVcorr2D(Ir,ratio,option);
function [I,Flow,H] = PVcorr2D(Ir,ratio,option);
%   PVcorr2D:   partial vollume correction with reverse difusion
%
%   [I,Flow,H] = PVcorr2D(Ir,ratio,option);
%
%  Ir: image to be interpolated
% ratio: 2 for x2 interpolation
% option: structure with parameters
% option.Niter = 200; Maxnumber of iteration
% option.tol = 0.001; tolerance for stopping
% option.f_H = 1; if 1, compute the entropy
% option.f_display = 1; if 1 dispaly intermediate results
% option.f_PVE = 1; if 1 use flow constraint 
% option.ordmax = 5; neighbor to compute max flow (out of 8 neighbors)
% option.ordmin = 4; neighbor to compute min flow (out of 8 neighbors)
% for the two last options, one can try 6 and 3, or 7 and 2
%
% I: corrected image
% Flow: flow across iterations
% H: entropy across iterations if option.f_H is set to 1
% 
% OS, Case Western Reserve University, 16jul04
%
% From paper:
% Olivier  Salvado, Claudia M. Hillenbrand, and David L. Wilson, 
% Partial Volume Reduction by Interpolation with Reverse Diffusion, 
% International Journal of Biomedical Imaging, 
% vol. 2006, Article ID 92092, 13 pages, 2006. doi:10.1155/IJBI/2006/92092
%
% available online at: 
% http://www.hindawi.com/GetArticle.aspx?doi=10.1155/IJBI/2006/92092&e=cta



optiondef.Niter = 200;
optiondef.tol = 0.001;
optiondef.f_H = 1;
optiondef.f_display = 1;
optiondef.f_PVE = 1;
optiondef.ordmax = 5;
optiondef.ordmin = 4;


if nargin == 0,
    I = optiondef;
    return
end

if ~exist('option','var'),
    option = optiondef;
end

Niter = option.Niter;
tol = option.tol;
f_H = option.f_H;
f_display = option.f_display;
f_PVE = option.f_PVE;  % flag = 1 to use PVE constraints
ordmax = option.ordmax;
ordmin = option.ordmin;



[Mx,My,Mxy,Myx,I] = PVEMaskGeneration(Ir,ratio);
[Ny,Nx] = size(I);

% --- init parameters
noise = 0;
if noise>0,
    % to remove noise as in bicubic interp to avoid aliasing artifact
    I = imfilter(I,fspecial('gaussian',11,0.75),'same','symmetric');
end

NiterDisp = Niter;
Dx = [2:Nx Nx];
Dy = [2:Ny Ny];
C = 4;
kernelG = fspecial('gaussian',3*ratio+1,ratio/2);%ratio*3+1,9);
% kernelG = fspecial('average',ratio);%ratio*3+1,9);
Gt0 = 1;  % thermal energy
H = 0;
iter = 0;
bins = [-0.1:0.01:1.1];
Nbins = length(bins);
Npix = Ny*Nx;
Hmax= -Nbins*log(Npix/Nbins);
Hmin = -Npix*log(Npix);


again = 1;
if f_display,
    disp('')
    disp('  Starting correction')
end
stop  = 0;
Flowf(1) = 0;
while again,
    Iold = I;
    iter = iter +1;
    If = imfilter(I,kernelG,'same','replicate');
    % --- uses the filtered image for the gradient
%     bal = 1;
%     grady =  (If(Dy,:) - If)*bal - 0.5*(1-bal)*(I(Dy,:) - I );
%     gradx =  (If(:,Dx) - If )*bal - 0.5*(1-bal)*(I(Dy,:) - I );
    grady =  (If(Dy,:) - If);
    gradx =  (If(:,Dx) - If );
    
    
    % ---- compute flow limits
    if 1,
        Imin = I-ordfilt2(I,ordmin,[1 1 1; 1 0 1; 1 1 1],'symmetric');
        Imax = ordfilt2(I,ordmax,[1 1 1; 1 0 1; 1 1 1],'symmetric')-I;
    else
        K = ones(2*ratio-1,2*ratio-1);
        K(ratio,ratio) = 0;
        KS = sum(K(:));
        Imin = I-ordfilt2(I,KS/2-3,K,'symmetric');
        Imax = ordfilt2(I,KS/2+4,K,'symmetric')-I;
    end
    
    % --- actual flows
    flowx1 = min(   (Imax(:,Dx))/C    ,    min( max(0,gradx) , Imin/C       ) ) ;             % grad >0
    flowx2 = max( -Imax/C        ,    max( min(0,gradx) , -Imin(:,Dx)/C ) );   % grad<0
    
    flowy1 = min(   Imax(Dy,:)/C    ,    min( max(0,grady) , Imin/C       ) ) ;             % grad >0
    flowy2 = max(  -Imax/C        ,    max( min(0,grady) , -Imin(Dy,:)/C ) );   % grad<0
    
    % --- block the flow across pseudo boundaries if f_PVE
    if f_PVE,
        flowx    = Mx.*(flowx1 + flowx2);    % in fact either 1 or 2
        flowy    = My.*(flowy1 + flowy2);    % in fact either 1 or 2
    else
        flowx    = (flowx1 + flowx2);    % in fact either 1 or 2
        flowy    = (flowy1 + flowy2);    % in fact either 1 or 2
    end    
    
    % --- update the image
    flow_tot = (flowx+flowy);
    I = I - flow_tot;
    I(:,Dx(1:end-1)) = I(:,Dx(1:end-1)) + flowx(:,1:end-1);
    I(Dy(1:end-1),:) = I(Dy(1:end-1),:) + flowy(1:end-1,:);
    
    % entropy
    if f_H | f_display,
        hi = hist(I(:),bins);
%         Npix = Ny*Nx;
%         Hmin = 1/Npix*log(1/Npix);
%         Hmax = Npix*log(Npix);
        H(iter) = -sum( hi(hi>0).*log(hi(hi>0)) );
        H(iter) = (H(iter)-Hmin) / (Hmax-Hmin) ;
    end
    
    % --- compute metrics
    Flow(iter) = sum(abs(flow_tot(:)))*0.1;

    if iter>1,
        Flowf(iter) = Flow(iter)*0.5+0.5*Flowf(iter-1);
        if f_H,
            Hf(iter) = H(iter)*0.5+Hf(iter-1)*0.5;
        end

%         stop = abs(Flowf(iter)-Flowf(iter-1))/Flowf(iter-1)<tol;
        if Flowf>Flowmax,Flowmax = Flowf(iter);end
        stop = (Flowf(iter)<Flowmax*tol);
    else
        Flowf(iter) = Flow(iter);
        Flowmax = Flowf(1);
        if f_H,
            Hf(iter) = H(iter);
        end
    end
    
    
    
    if (f_display & (mod(iter,round(Niter/NiterDisp)) == 0) ),
        
        M(iter) = im2frame(uint8(I*255),gray(256));
        subplot(221)
        imagesc(Ir,[0 1]),title('I0'),axis image
        subplot(222)
        imagesc(I,[0 1]),title(['I corrected, Iteration : ' num2str(iter) ' / ' num2str(Niter)]),axis image
        
        if f_H,
            subplot(245)
            plot([Flow' Flowf'])
            title(['Flow'])
            subplot(246)
             plot([H' Hf'])      
             title(['Entropy'])
        else,
           subplot(223)
            plot([Flow'-mean(Flow) Flowf'-mean(Flow)])      
            title(['Flow'])
        end
        subplot(224)
        bar(bins,hi),xlim([-0.5 1.5])
    end
    
    
    % --- end the simulation
    again = ((iter<Niter) & (~stop | 0));
    drawnow
    
end
if f_display
    disp('end')
end



% ===============  SUB FUNCTIONS =======================

function [Mx,My,Mxy,Myx,I] = PVEMaskGeneration(I0,N);
%
% [Mx,My,Mxy,Myx,I] = PVEMaskGeneration(I0,N);
%
% Generate masks to be used for reverse diffusion PVE correction
%

if N<2,
    disp('error N should be >=2');
    return;
end

% --- resize with nearest neigbhors
I = imresize(I0,N);
[Ly,Lx]= size(I);

% --- build the masks
Mx = ones(size(I));
My = Mx;
Mxy = Mx;
Myx = Mx;
Dx = [N:N:Lx];
Dy = [N:N:Ly];

Mx(:,Dx) = 0;
My(Dy,:) = 0;
Mxy(Dy,:) = 0;
Mxy(:,Dx) = 0;
Myx(:,Dx) = 0;
Myx(Dy-(N-1),:) = 0;

Contact us at files@mathworks.com