Switch to unified view

a b/Thoracic Organs Segmentation code/TwoPhaseLevel Sets/EvolutionProcess.cpp
1
/*/////////////////////////////////////////////////////////////////////////////////////
2
                            2 phase level set method
3
 0-input image
4
 1-initial phi1
5
 2-dt=>time-step of iteration
6
 3-kappa =>coefficient of the weighted length term L(phi1)
7
 4-lambda1 =>coefficient of insice C term
8
 5-lambda2 =>coefficient of outside C term
9
 6-lambda=>coefficient of the weighted length term L(phi2)
10
 7-mu => coefficient of the internal (penalizing) energy term P(phi1),P(phi2)
11
 8-v=>coefficient of the weighted area term A(phi2)
12
 9-iterations
13
 10-g=>edge indicator
14
/*/////////////////////////////////////////////////////////////////////////////////////
15
#include <mex.h>
16
#include <mat.h>
17
#include <matrix.h>
18
19
#define cimg_plugin "cimgmatlab.h"
20
21
#include "CImg.h"
22
#include <iostream>
23
#include <string>
24
#include <math.h>
25
26
using namespace cimg_library;
27
using namespace std;
28
29
//globa values
30
const double  epsilon=0.8; // the papamater smooth Dirac function (default value 1.5);
31
const float precision=0.009f;//precision of the error estimation
32
33
//functions
34
CImg<double> DiracU( CImg<double>& u0) ;
35
CImg<double> Heaviside(CImg<double>& u0);
36
CImg<double> ExtractContour(CImg<double> LevelSet);
37
CImg<unsigned char> get_level0(const CImg<>& img);
38
39
CImg<unsigned char> InitialLevelSet(CImg<double>&Img);
40
CImg<double> DiracF(CImg<double>& u1,CImg<double>& u2); 
41
42
43
//-----------------
44
// Main-MexFunction
45
//-----------------
46
47
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
48
   if (nrhs < 13) mexErrMsgTxt("No enough input arguments.");
49
   if (nrhs >13) mexErrMsgTxt("Too many input arguments.");
50
   if (nrhs == 13){
51
         
52
       //Input Parameters ( inputs)
53
       CImg<double>  Img(prhs[0],true);         //input image
54
       CImg<double>  phi1(prhs[1],true);        //Rib cage curve
55
       CImg<double>  phi2(prhs[2],true);        //Second level set function which tracks the heart inside the rib cage
56
       CImg<int>     VolumeMask(prhs[3],true);
57
       const double dt= mxGetScalar( prhs[4]);     //time-step of iteration
58
       const double kappa = mxGetScalar(prhs[5]);  //coefficient of the weighted length term L(phi1)
59
       const double lambda1 = mxGetScalar(prhs[6]);//coefficient of insice C term
60
       const double lambda2 = mxGetScalar(prhs[7]);//coefficient of outside C term
61
       const double lambda = mxGetScalar(prhs[8]); //coefficient of the weighted length term L(phi2)
62
       const double mu = mxGetScalar(prhs[9]);     // coefficient of the internal (penalizing) energy term P(u)
63
       const double v = mxGetScalar(prhs[10]);     //coefficient of the weighted area term A(u)
64
       const unsigned int nb_iter = mxGetScalar(prhs[11]);//number of iterations
65
       CImg<double> g(prhs[12],true);              //edge indicator for phi2 evolution
66
       //////////////////////////////////////////////////////////////////////////////////////////////////
67
       
68
      //Design the initial distance functions phi1,phi2 
69
      unsigned char col[1]={2};//color filling
70
   
71
      phi1.draw_fill(0,0,col);
72
      phi2.draw_fill(0,0,col);
73
     
74
      //Define rib cage Mask;
75
      CImg<double> f(phi1.dimx(),phi1.dimy());
76
      f.fill(-2);
77
      cimg_forXY(phi1,x,y){if(phi1(x,y)==0) f(x,y)=1;}
78
     
79
      
80
      cimg_forXY(phi1,x,y){
81
        phi1(x,y)=-floor(phi1(x,y)-phi2(x,y))-1;
82
        phi2(x,y)=5*(phi2(x,y)-1);
83
      }
84
      phi1.distance_hamilton(15);//distance function
85
    //  CImgDisplay disp(phi2,"phi2",0);
86
        //Initializations
87
       CImg<double> dphi1(Img.dimx(),Img.dimy(),2); //derivatives of phi
88
       CImg<double> veloc1(phi1.dimx(),phi1.dimy());//evolution matrix
89
       CImg<double> N_dphi1(phi1.dimx(),phi1.dimy(),2); //Normalize gradient of function Phi1
90
       CImg<double> veloc2(phi2.dimx(),phi2.dimy());
91
       CImg<double> N_dphi2(phi2.dimx(),phi2.dimy(),2); //Normalize gradient of function Phi2
92
       
93
       //Chan-Vese Coefficients
94
       double c1=0, c2=0, Averagec1=0, Averagec2=0;
95
      
96
      //Edge indicator for Phi2 evolution
97
      CImg<double>dg(g.dimx(),g.dimy(),1,2);
98
      cimg_for3XY(g,x,y){
99
              dg(x,y,0)=0.5*(g(_n1x,y)-g(_p1x,y)), 
100
              dg(x,y,1)=0.5*(g(x,_n1y)-g(x,_p1y));
101
       }
102
              
103
      //Heaviside for the initial rib cage
104
     CImg<double> HeavisideF_R=Heaviside(f);
105
     
106
     double E1=1e20f,E2=1e20f;//Initial energies
107
     double Eold1 = 0, Eold2=0;  
108
     veloc1.fill(0);
109
     veloc2.fill(0);
110
     
111
     //////////////////////////////////////////////////////////////////////////////////////////////
112
     // PDEs
113
     for (unsigned int iter=0; iter<=nb_iter; iter++) {
114
                
115
                                       
116
             CImg<double>diracF1=DiracU(phi1);
117
             CImg<double>HeavisideF1=Heaviside(phi1);
118
             CImg<double>diracF2=DiracU(phi2);
119
             CImg<double>HeavisideF2=Heaviside(-phi2);
120
           
121
           //Estimation of derivatives of the Phi1,Phi2 and the chan-vese coefficients for the Phi1 evolution
122
            cimg_for3XY(phi1,x,y)if (VolumeMask(x,y)==0){
123
                
124
                 //Phi1-Chan Vese             
125
                 const double
126
                      phix1=0.5*(phi1(_n1x,y)-phi1(_p1x,y)),
127
                      phiy1=0.5*(phi1(x,_n1y)-phi1(x,_p1y));  //derivatives of phi1(central approximation)
128
129
                  const double Mag_dphi1= sqrt(pow(phix1,2)+ pow(phiy1,2)+1e-10); //magnitude of grad(phi)
130
                      N_dphi1(x,y,0)=phix1/Mag_dphi1;
131
                      N_dphi1(x,y,1)=phiy1/Mag_dphi1;
132
133
                 c1+=HeavisideF1(x,y)* Img(x,y);
134
                 c2+=(1-HeavisideF1(x,y))*Img(x,y);
135
                 Averagec1+=HeavisideF1(x,y);
136
                 Averagec2+=HeavisideF1(x,y);
137
                 /////////////////////////////////////////////////////////////////////////////////////
138
                 
139
                 //Phi2 evolution-Front propagation or Level set function without re-initialization
140
                 const double
141
                      phix2=0.5*(phi2(_n1x,y)-phi2(_p1x,y)),
142
                      phiy2=0.5*(phi2(x,_n1y)-phi2(x,_p1y));  //derivatives of phi2
143
144
                 const double Mag_dphi2= sqrt(pow(phix2,2)+ pow(phiy2,2)+1e-10); //magnitude of grad(phi2)
145
                      N_dphi2(x,y,0)=phix2/Mag_dphi2;
146
                      N_dphi2(x,y,1)=phiy2/Mag_dphi2;
147
             }
148
149
            //chan-vese coefficients update
150
            c1/=(Averagec1+1e-5);
151
            c2/=(Averagec2+1e-5);
152
                          
153
             
154
            cimg_for3XY(Img,x,y)if (VolumeMask(x,y)==0){
155
                     
156
                 //Chan-Vese level set function 
157
                const double
158
                    Laplac_phi1=(phi1(_n1x,y) + phi1(_p1x,y) + phi1(x,_n1y) + phi1(x,_p1y))-4*phi1(x,y),     //laplacian operator
159
                    K1=0.5*(N_dphi1(_n1x,y,0)-N_dphi1(_p1x,y,0))+0.5*(N_dphi1(x,_n1y,1)-N_dphi1(x,_p1y,1));//curvature estimation
160
                const double
161
                    phixx1=(phi1(_n1x,y)+phi1(_p1x,y)-2*phi1(x,y)),//second derivatives of Phi1
162
                    phiyy1=(phi1(x,_n1y)+phi1(x,_p1y)-2*phi1(x,y)); 
163
                
164
                //Evolution equation of Phi1
165
                veloc1(x,y)=mu*(Laplac_phi1-K1)-lambda1* diracF1(x,y)* pow(Img(x,y)-c1,2)+lambda2*diracF1(x,y)*pow(Img(x,y)-c2,2)+kappa*diracF1(x,y)*K1;
166
                E1+=lambda1*HeavisideF1(x,y)*pow(Img(x,y)-c1,2)+lambda2*(1-HeavisideF1(x,y))*pow(Img(x,y)-c2,2);  
167
                
168
                //Phi2-front propagation level set function (without re-initiallization)
169
                  const double
170
                     Laplac_phi2=(phi2(_n1x,y) + phi2(_p1x,y) + phi2(x,_n1y) + phi2(x,_p1y))-4*phi2(x,y),
171
                     K2=0.5*(N_dphi2(_n1x,y,0)-N_dphi2(_p1x,y,0))+0.5*(N_dphi2(x,_n1y,1)-N_dphi2(x,_p1y,1));
172
                  const double
173
                     phixx2=(phi2(_n1x,y)+phi2(_p1x,y)-2*phi2(x,y)),
174
                     phiyy2=(phi2(x,_n1y)+phi2(x,_p1y)-2*phi2(x,y));
175
               
176
                 
177
                  veloc2(x,y)=lambda* diracF2(x,y)*( dg(x,y,0)* N_dphi2(x,y,0) +dg(x,y,1)* N_dphi2(x,y,1) + g(x,y)*K2)+mu*(Laplac_phi2-K2)+v*g(x,y)*diracF2(x,y);
178
                  veloc2(x,y)=veloc2(x,y)*HeavisideF_R(x,y)*(1-HeavisideF1(x,y)*(-HeavisideF2(x,y)));
179
                //Energy estimation
180
                // E2+=lambda*g(x,y)*diracF2(x,y)* Mag_dphi2+1/2*mu*pow( Mag_dphi2-1,2)+v*HeavisideF2(x,y)*g(x,y);
181
//                   if (!(iter%400)) {
182
//                   get_level0(phi2).resize(disp.dimx(),disp.dimy()).draw_grid(20,20,0,0,false,false,col,0.4f,0xCCCCCCCC,0xCCCCCCCC).
183
//                   draw_text(5,5,"Iteration %d",col,0,1,11,iter).display(disp);
184
//                 }
185
               
186
            }
187
         
188
            phi1+=dt*veloc1;
189
            phi2+=dt*veloc2;
190
           
191
          if ((abs(Eold1-E1)<0.001f) && (abs(Eold2-E2)<0.001f)) break; 
192
          
193
            c1=0,Averagec1=0;
194
            c2=0,Averagec2=0;
195
            Eold1 = E1, Eold2=E2;
196
            E1=0;E2=0;
197
     
198
     }
199
  
200
    plhs[0]=  phi1.toMatlab();
201
    plhs[1]=  phi2.toMatlab();
202
  
203
    
204
  } 
205
    
206
   return;    
207
 
208
}
209
  
210
211
   
212
CImg<double> DiracU(CImg<double>& u0) {
213
214
  CImg<double> u(u0.dimx(),u0.dimy());
215
  u.fill(0);
216
   
217
  cimg_forXY(u0,x,y) { 
218
       if (u0(x,y)<=epsilon && u0(x,y)>=-epsilon){
219
           u(x,y)=(double)1/(2*epsilon)*(1+cos(3.14*u0(x,y)/epsilon));
220
       }
221
  
222
   }
223
   return u;
224
}
225
226
CImg<double> Heaviside(CImg<double>& u0) {
227
228
  CImg<double> u(u0.dimx(),u0.dimy());
229
  u.fill(0);
230
/*cimg_forXY(u0,x,y){
231
    u(x,y)=1/2*(1+2/3.14*atan(u(x,y)/epsilon));
232
}*/  
233
 cimg_forXY(u0,x,y) { 
234
                  
235
       if (u0(x,y)>=-epsilon && u0(x,y)<=epsilon){
236
           u(x,y)=(double) 1/2+u0(x,y)/(2*epsilon)+1/(2*3.14)*sin(3.14*u0(x,y)/epsilon);
237
       }
238
       if (u0(x,y)>epsilon) u(x,y)=1;
239
  
240
   }
241
    return u;
242
} 
243
244
245
/*******************************************************************************/
246
CImg<double> ExtractContour(CImg<double> LevelSet)
247
{
248
 CImg<double> Contour(LevelSet.dimx(),LevelSet.dimy(),1,1);
249
 Contour.fill(0);
250
251
 CImg_3x3(I,double);
252
 cimg_for3x3(LevelSet,x,y,0,0,I)
253
 {
254
  if(Icc*Icp<=0 || Icc*Icn<=0 || Icc*Ipc<=0 || Icc*Inc<=0)
255
   Contour(x,y) = 1;
256
 }
257
 return Contour;
258
}
259
260
//////////////////////////////////////////////////////////////////////////////////////////////
261
// Create a user-defined closed curve (Initial level set fuction)
262
CImg<unsigned char> InitialLevelSet(CImg<double>&Img){
263
       CImg<unsigned char> curve(Img.dimx(),Img.dimy(),Img.dimz(),2,0);
264
       unsigned char col1[2]={0,255}, col2[2]={200,255}, col3[2]={255,255};//colors
265
       curve.draw_grid(20,20,0,0,false,false,col1,0.4f,0xCCCCCCCC,0xCCCCCCCC).
266
       draw_text(5,5,"Please draw your curve\nin the middle of this window\n(Use your mouse)\n-heart initial curve",col1);
267
      CImgDisplay disp(curve,"Image",0);
268
       CImg<double> tempImg(Img);
269
270
       int xo=-1,yo=-1,x0=-1,y0=-1,x1=-1,y1=-1;
271
       while (!disp.is_closed && (x0<0 || disp.button)) {
272
        if (disp.button && disp.mouse_x>=0 && disp.mouse_y>=0) {
273
             if (x0<0) { xo = x0 = disp.mouse_x; yo = y0 = disp.mouse_y; } else {
274
                 x1 = disp.mouse_x; y1 = disp.mouse_y;
275
                 curve.draw_line(x0,y0,x1,y1,col2);//.display(disp);
276
                
277
                  tempImg.draw_point(x1,y1,col1).display(disp);
278
                 x0 = x1; y0 = y1;
279
              }
280
         }
281
         disp.wait();
282
        if (disp.is_resized) disp.resize(disp);
283
       }
284
 curve.draw_line(x1,y1,xo,yo,col2).channel(0).draw_fill(0,0,col3);
285
return curve;
286
}
287
//////////////////////////////////////////////////////////////////////////////////////////////
288
289
290
291
292
// get_level0() : Retrieve the curve corresponding to the zero level set of the distance function
293
//-------------
294
CImg<unsigned char> get_level0(const CImg<>& img) {
295
  CImg<unsigned char> dest(img);
296
  CImg_2x2(I,float); Inn = 0;
297
  cimg_for2x2(img,x,y,0,0,I) if (Icc*Inc<0 || Icc*Icn<0) dest(x,y) = 255; else dest(x,y) = Icc<0?100:0;
298
  return dest;
299
}
300
        
301
   
302
  
303
     
304
305
  
306
307
308