Code covered by the BSD License  

Highlights from
Active contour platform

image thumbnail

Active contour platform

by

 

26 May 2010 (Updated )

Compare the performance of different level sets and active contours methods.

creaseg_shi(img,init_mask,max_its,Na,Ns,Sigma,Ng,color,display)
% Copyright or © or Copr. CREATIS laboratory, Lyon, France.
% 
% Contributor: Olivier Bernard, Associate Professor at the french 
% engineering university INSA (Institut National des Sciences Appliquees) 
% and a member of the CREATIS-LRMN laboratory (CNRS 5220, INSERM U630, 
% INSA, Claude Bernard Lyon 1 University) in France (Lyon).
% 
% Date of creation: 8th of October 2009
% 
% E-mail of the author: olivier.bernard@creatis.insa-lyon.fr
% 
% This software is a computer program whose purpose is to evaluate the 
% performance of different level-set based segmentation algorithms in the 
% context of image processing (and more particularly on biomedical 
% images).
% 
% The software has been designed for two main purposes. 
% - firstly, CREASEG allows you to use six different level-set methods. 
% These methods have been chosen in order to work with a wide range of 
% level-sets. You can select for instance classical methods such as 
% Caselles or Chan & Vese level-set, or more recent approaches such as the 
% one developped by Lankton or Bernard.
% - finally, the software allows you to compare the performance of the six 
% level-set methods on different images. The performance can be evaluated 
% either visually, or from measurements (either using the Dice coefficient 
% or the PSNR value) between a reference and the results of the 
% segmentation.
%  
% The level-set segmentation platform is citationware. If you are 
% publishing any work, where this program has been used, or which used one 
% of the proposed level-set algorithms, please remember that it was 
% obtained free of charge. You must reference the papers shown below and 
% the name of the CREASEG software must be mentioned in the publication.
% 
% CREASEG software
% "T. Dietenbeck, M. Alessandrini, D. Friboulet, O. Bernard. CREASEG: a
% free software for the evaluation of image segmentation algorithms based 
% on level-set. In IEEE International Conference On Image Processing. 
% Hong Kong, China, 2010."
%
% Bernard method
% "O. Bernard, D. Friboulet, P. Thevenaz, M. Unser. Variational B-Spline 
% Level-Set: A Linear Filtering Approach for Fast Deformable Model 
% Evolution. In IEEE Transactions on Image Processing. volume 18, no. 06, 
% pp. 1179-1191, 2009."
% 
% Caselles method
% "V. Caselles, R. Kimmel, and G. Sapiro. Geodesic active contours. 
% International Journal of Computer Vision, volume 22, pp. 61-79, 1997."
% 
% Chan & Vese method
% "T. Chan and L. Vese. Active contours without edges. IEEE Transactions on
% Image Processing. volume10, pp. 266-277, February 2001."
% 
% Lankton method
% "S. Lankton, A. Tannenbaum. Localizing Region-Based Active Contours. In 
% IEEE Transactions on Image Processing. volume 17, no. 11, pp. 2029-2039, 
% 2008."
% 
% Li method
% "C. Li, C.Y. Kao, J.C. Gore, Z. Ding. Minimization of Region-Scalable 
% Fitting Energy for Image Segmentation. In IEEE Transactions on Image 
% Processing. volume 17, no. 10, pp. 1940-1949, 2008."
% 
% Shi method
% "Yonggang Shi, William Clem Karl. A Real-Time Algorithm for the 
% Approximation of Level-Set-Based Curve Evolution. In IEEE Transactions 
% on Image Processing. volume 17, no. 05, pp. 645-656, 2008."
% 
% This software is governed by the BSD license and
% abiding by the rules of distribution of free software.
% 
% As a counterpart to the access to the source code and rights to copy,
% modify and redistribute granted by the license, users are provided only
% with a limited warranty and the software's author, the holder of the
% economic rights, and the successive licensors have only limited
% liability. 
% 
% In this respect, the user's attention is drawn to the risks associated
% with loading, using, modifying and/or developing or reproducing the
% software by the user in light of its specific status of free software,
% that may mean that it is complicated to manipulate, and that also
% therefore means that it is reserved for developers and experienced
% professionals having in-depth computer knowledge. Users are therefore
% encouraged to load and test the software's suitability as regards their
% requirements in conditions enabling the security of their systems and/or 
% data to be ensured and, more generally, to use and operate it in the 
% same conditions as regards security.
% 
%------------------------------------------------------------------------

%------------------------------------------------------------------------
% Description: This code implements the paper: "A Real-Time Algorithm for 
% the Approximation of Level-Set-Based Curve Evolution." By Yonggang Shi.
%
% Coded by: Olivier Bernard (www.creatis.insa-lyon.fr/~bernard)
%------------------------------------------------------------------------


function [seg,phi,n] = creaseg_shi(img,init_mask,max_its,Na,Ns,Sigma,Ng,color,display)

    %-- default value for parameter max_its is 100
    if(~exist('max_its','var')) 
        max_its = 100; 
    end
    %-- default value for parameter na is 30
    if(~exist('Na','var')) 
        Na = 30; 
    end    
    %-- default value for parameter ns is 3
    if(~exist('Ns','var')) 
        Ns = 3;
    end
    %-- default value for parameter sigma is 9
    if(~exist('Sigma','var')) 
        Sigma = 3;
    end
    %-- default value for parameter ng is 7
    if(~exist('Ng','var')) 
        Ng = 1;
    end   
    %-- default value for parameter color is 'r'
    if(~exist('color','var')) 
        color = 'r'; 
    end       
    %-- default behavior is to display intermediate outputs
    if(~exist('display','var'))
        display = true;
    end   
    
%     init_mask = init_mask<=0;

    %--
    fig = findobj(0,'tag','creaseg');
    ud = get(fig,'userdata');
    
    
    %-- Create the initial level-set
    [phi,Lin,Lout,size_in,size_out] = createInitialLevelSet(init_mask);

    %-- Create feature image
    [feature,u,v,Ain,Aout] = createFeatureImage(phi,img);

    %-- main looop
    stop_cond = 0;  % Stopping condition
    n = 1;

    while ( (n<=max_its) && (stop_cond==0) )

        % Data dependent evolution
        na = 0;
        while ( (na<Na) && (n<=max_its) && (stop_cond==0) )

            [Lin,Lout,phi,u,v,Ain,Aout,size_in,size_out] = ...
                shi_evolution_subCV(img,Lin,Lout,phi,feature,u,v,Ain,Aout,size_in,size_out);

            %-- intermediate output
            if (display>0)
                if ( mod(na,50)==0 )            
                    set(ud.txtInfo1,'string',sprintf('iteration: %d',n),'color',[1 1 0]);
                    showCurveAndPhi(phi,ud,color);
                    drawnow;
                end
            else
                if ( mod(na,10)==0 )            
                    set(ud.txtInfo1,'string',sprintf('iteration: %d',n),'color',[1 1 0]);
                    drawnow;
                end
            end        

            stop_cond = stopping_condition(feature,Lin,Lout,size_in,size_out);

            if ( stop_cond==0 )  % Mise à jour de la feature image
                feature = zeros(size(phi));
                [x,y] = find(abs(phi) < 2);
                feature(x,y) = -(img(x,y) - u).^2 + (img(x,y) - v).^2;
                feature = feature./max(abs(feature(:)));
            end

            na = na+1;
            n = n+1;

        end

        % smoothing evolution
        for ns=1:1:Ns
            Fint = smoothing(phi,Lin,Lout,size_in,size_out,Ng,Sigma);
            [Lin,Lout,phi,u,v,Ain,Aout,size_in,size_out] = ...
                shi_evolution_subCV(img,Lin,Lout,phi,Fint,u,v,Ain,Aout,size_in,size_out);
            n = n+1;
        end

        if (stop_cond==0)
            feature = zeros(size(phi));
            [x,y] = find(abs(phi) < 2);
            feature(x,y) = -(img(x,y) - u).^2 + (img(x,y) - v).^2; % Chan & Vese
            feature = feature./max(abs(feature(:)));
        end

    end

    %-- final output
    showCurveAndPhi(phi,ud,color);   

    %-- make mask from SDF
    seg = phi<=0; %-- Get mask from levelset


%---------------------------------------------------------------------
%---------------------------------------------------------------------
%-- AUXILIARY FUNCTIONS ----------------------------------------------
%---------------------------------------------------------------------
%---------------------------------------------------------------------
  
 
%-- Displays the image with curve superimposed
function showCurveAndPhi(phi,ud,cl)

	axes(get(ud.imageId,'parent'));
	delete(findobj(get(ud.imageId,'parent'),'type','line'));
	hold on; [c,h] = contour(phi,[0 0],cl{1},'Linewidth',3); hold off;
	delete(h);
    test = isequal(size(c,2),0);
	while (test==false)
        s = c(2,1);
        if ( s == (size(c,2)-1) )
            t = c;
            hold on; plot(t(1,2:end)',t(2,2:end)',cl{1},'Linewidth',3);
            test = true;
        else
            t = c(:,2:s+1);
            hold on; plot(t(1,1:end)',t(2,1:end)',cl{1},'Linewidth',3);
            c = c(:,s+2:end);
        end
	end    



%-- Create the initial discrete level-set from mask
function [u,Lin,Lout,size_in,size_out] = createInitialLevelSet(mask)

    tmp = ones(size(mask))*3;
    tmp(mask>0) = -3;

    u = tmp;
    [nrow,ncol] = size(u);
    [x,y] = find(tmp==-3);
    for j=1:size(x,1)
        neigh = voisinage([x(j);y(j)],nrow,ncol);
        k = 1;
        stop = 0;
        while ( ( k<5 ) && ( stop==0 ) )
            if ( tmp(neigh(1,k),neigh(2,k)) > -3 )
                u(x(j),y(j)) = 1;
                stop = 1;
            end                
            k = k + 1;
        end
    end
    tmp(u>-3) = 3;
    [x,y] = find(tmp==-3);
    for j=1:size(x,1)
        neigh = voisinage([x(j);y(j)],nrow,ncol);
        k = 1;
        stop = 0;
        while ( ( k<5 ) && ( stop==0 ) )
            if ( tmp(neigh(1,k),neigh(2,k)) > -3 )
                u(x(j),y(j)) = -1;
                stop = 1;
            end                
            k = k + 1;
        end
    end
    

    Lin = zeros(2,round(size(u,1)*size(u,2)/6));
    Lout = zeros(2,round(size(u,1)*size(u,2)/6));
    size_in = 0;
    size_out = 0;
    for i=1:1:size(u,1)
        for j=1:1:size(u,2)
            if ( u(i,j) == 1 )
                size_out = size_out + 1;
                Lout(:,size_out) = [i;j];
            end
            if ( u(i,j) == -1 )
                size_in = size_in + 1;
                Lin(:,size_in) = [i;j];
            end
        end
    end    


%-- Find the neighborhood of one pixel 
function N = voisinage(x,nrow,ncol)

    i = x(1);
    j = x(2);
    I1 = i+1;
    if (I1 > nrow)
        I1 = nrow;
    end
    I2 = i-1;
    if (I2 < 1)
        I2 = 1;
    end
    J1 = j+1;
    if (J1 > ncol)
        J1 = ncol;
    end
    J2 = j-1;
    if (J2 < 1)
        J2 = 1;
    end
    N = [I1, I2, i, i; j, j, J1, J2];


%-- Create feature image for data dependent cycle
function [feature, u, v, Ain, Aout] = createFeatureImage(phi, im)
   
    upts = find(phi<=0);            % interior points
    vpts = find(phi>0);             % exterior points
    Ain = length(upts);             % interior area
    Aout = length(vpts);            % exterior area
    u = sum(im(upts))/(Ain+eps);    % interior mean
    v = sum(im(vpts))/(Aout+eps);   % exterior mean
    
    feature = zeros(size(phi));
    [x,y] = find(abs(phi) < 2);
    feature(x,y) = -(im(x,y) - u).^2 + (im(x,y) - v).^2;
    feature = feature./max(abs(feature(:)));
   
        
%-- Testing convergence
function sc = stopping_condition(F, Li, Lo,size_in,size_out)

    sc = 1; i = 1;
    while( i<size_out && sc )
        x = Lo(1,i);
        y = Lo(2,i);
        if F(x,y)>0
            sc = 0;
        end
        i = i+1;
    end
    
    i = 1;
    while( i<size_in && sc )
        x = Li(1,i);
        y = Li(2,i);
        if F(x,y)<0
            sc = 0;
        end   
        i = i + 1;
    end    
    

%-- Create feature image for smoothing cycle
function Fi = smoothing(phi, Li, Lo,size_in,size_out, sg, sigma)
   
    [nr, nc] = size(phi);
    Fi = zeros(nr, nc);

    Gaussian = fspecial('gaussian', [sg, sg], sigma);
    
    H = zeros(size(phi));
    H(phi<0) = 1;
    HG = imfilter(H, Gaussian);

    for i = 1:1:size_out
        x = Lo(1,i);    
        y = Lo(2,i);
        if ( HG(x,y)>1/2 )
            Fi(x,y) = 1;
        end   
    end

    for i = 1:1:size_in
        x = Li(1,i);
        y = Li(2,i);
        if ( HG(x,y)<1/2 )
            Fi(x,y) = -1;
        end   
    end
    
    
%-- shi_evolution_subCV
function [Linmod, Loutmod, Phimod, umod, vmod, Ai, Ao,s_i,s_o] = ...
                    shi_evolution_subCV(img, Lin, Lout, phi, feature, u, v, Ain, Aout,size_in,size_out)

    [nrow,ncol] = size(phi);

    Linmod = Lin;
    Loutmod = Lout;
    Phimod = phi;
    s_i = size_in;
    s_o = size_out;    

    umod = u;
	Ai = Ain;
    vmod = v;
	Ao = Aout;

    % Step 1: Outward evolution
    c = 1;
    N = s_o;
    while ( c <= N )
        i = Loutmod(1, c);      j = Loutmod(2, c);
        if ( feature(i, j) > 0 )
            [Linmod, Loutmod, Phimod,s_i,s_o] = ...
                switch_in(c, Linmod, Loutmod, Phimod, s_i, s_o, nrow, ncol);

            umod = (umod*Ai + img(i, j))/(Ai + 1);
            vmod = (vmod*Ao - img(i, j))/(Ao - 1);
            Ai = Ai + 1;   Ao = Ao - 1;

            c = c-1;
            N = N-1;
        end
        c = c+1;
    end

    % Step 2: Eliminate redundant point in Lin
    [Linmod, Phimod, s_i] = suppr_Lin(Linmod, Phimod, s_i, nrow, ncol);


    % Step 3: Inward evolution
    c = 1;
    N = s_i;
    while (c <= N)
        i = Linmod(1, c);       j = Linmod(2, c);
        if ( feature(i, j) < 0 )
            [Linmod, Loutmod, Phimod,s_i,s_o] = ...
                    switch_out(c, Linmod, Loutmod, Phimod,s_i,s_o, nrow, ncol);

            umod = (umod*Ai - img(i, j))/(Ai - 1);
            vmod = (vmod*Ao + img(i, j))/(Ao + 1);
            Ai = Ai - 1;   Ao = Ao + 1;

            c = c-1;
            N = N-1;
        end
        c = c+1;
    end


    % Step 4: Eliminate redundant point in Lout
    [Loutmod, Phimod,s_o] = suppr_Lout(Loutmod, Phimod,s_o,nrow, ncol);


function [Linmod, Loutmod, Phimod,s_i,s_o] = ...
            switch_in(c, Lin, Lout, phi,size_in,size_out, nrow, ncol)

    x = [Lout(1, c); Lout(2, c)];
    Phimod = phi;
    Linmod = Lin;
    Loutmod = Lout;
    
    % on ajoute x a Lin
    Linmod(:,size_in+1) = x;
    Phimod(x(1, 1), x(2, 1)) = -1;
    s_i = size_in + 1;

    % Suppression de x de Lout
    if (c == 1)
        Loutmod(:,1:size_out-1) = Lout(:, 2:size_out);
    elseif (c == size_out)
        Loutmod(:,1:size_out-1) = Lout(:, 1:size_out-1);
    else
        Loutmod(:,1:size_out-1) = [Lout(:, 1:c-1),Lout(:, c+1:size_out)];
    end
    s_o = size_out - 1;

    % Mise a jour du voisinage
    N = voisinage(x, nrow, ncol);
    for k=1:1:4
        y = [N(1, k); N(2, k)];
        i = N(1, k);
        j = N(2, k);
        if phi(i, j) == 3 % y est un point exterieur
            Phimod(i, j) = 1; % Mise a jour de phi(j)
            Loutmod(:,s_o+1) = y; % Mise a jour de Lout
            s_o = s_o + 1;
        end
    end


function [Linmod, Loutmod, Phimod,s_i,s_o] = ...
            switch_out(c, Lin, Lout, phi,size_in,size_out, nrow, ncol)
        
    x = [Lin(1, c); Lin(2, c)];
    Phimod = phi;
    Linmod = Lin;
    Loutmod = Lout;
    
    % on ajoute x a Lout
    Loutmod(:,size_out+1) = x;
    Phimod(x(1, 1), x(2, 1)) = 1;
    s_o = size_out + 1;

    % Suppression de x de Lin
    if (c == 1)
        Linmod(:,1:size_in-1) = Lin(:, 2:size_in);
    elseif (c == size_in)
        Linmod(:,1:size_in-1) = Lin(:, 1:size_in-1);
    else
        Linmod(:,1:size_in-1) = [Lin(:, 1:c-1), Lin(:, c+1:size_in)];
    end
    s_i = size_in-1;
    
    N = voisinage(x, nrow, ncol);
    for k=1:1:4
        y = [N(1, k); N(2, k)];
        i = N(1, k);
        j = N(2, k);
        if (phi(i, j) == -3) % y est un point interieur
            Phimod(i, j) = -1; % Mise a jour de phi(j)
            Linmod(:,s_i+1) = y; % Mise a jour de Lin
            s_i = s_i + 1;
        end
    end


function [Linmod, Phimod,s_i] = suppr_Lin(Lin, phi,size_in, nrow, ncol)

    Linmod = Lin;
    Phimod = phi;
    s_i = size_in;
    
    k=1;
    while (k <= s_i)
        x = [Lin(1, k); Lin(2, k)];
        N = voisinage(x, nrow, ncol);
        i = x(1, 1);
        j = x(2, 1);
        b = 0;
        for c=1:1:4
            if (phi(N(1, c), N(2, c)) < 0)
                b = b+1;
            end
        end
        if (b == 4)
            % Suppression de x de Lin
            if (k == 1)
                Linmod(:,1:s_i-1) = Lin(:,2:s_i);
            elseif (k == s_i)
                Linmod(:,1:s_i-1) = Lin(:,1:s_i-1);
            else
                Linmod(:,1:s_i-1) = [Lin(:,1:k-1),Lin(:,k+1:s_i)];
            end
            k = k-1;
            s_i = s_i-1;
            Phimod(i,j) = -3;
            Lin = Linmod;
        end

        k = k+1;
    end


function [Loutmod, Phimod,s_o] = suppr_Lout(Lout, phi,size_out, nrow, ncol)

    Loutmod = Lout;
    Phimod = phi;
    s_o = size_out;
    
    k = 1;
    while (k <= s_o)
        x = [Lout(1, k); Lout(2, k)];
        N = voisinage(x, nrow, ncol);
        i = x(1, 1);
        j = x(2, 1);
        b = 0;
        for c = 1:1:4
            if (phi(N(1, c), N(2, c)) > 0)
                b = b+1;
            end
        end
        if (b == 4)
            % Suppression de x de Lout
            if (k == 1)
                Loutmod(:,1:s_o-1) = Lout(:, 2:s_o);
            elseif (k == s_o)
                Loutmod(:,1:s_o-1) = Lout(:, 1:s_o-1);
            else
                Loutmod(:,1:s_o-1) = [Lout(:, 1:k-1),Lout(:, k+1:s_o)];
            end
            k = k-1;
            s_o = s_o-1;
            Phimod(i, j) = 3;
            Lout = Loutmod;
        end

        k = k+1;
    end


Contact us