|
a |
|
b/Thoracic Organs Segmentation code/OpticalFlow3D/OpticalFlow3D.asv |
|
|
1 |
/*----------------------------------------------------------------------- |
|
|
2 |
|
|
|
3 |
--------------------------------------------------------------------------*/ |
|
|
4 |
|
|
|
5 |
#include <mex.h> |
|
|
6 |
#include <mat.h> |
|
|
7 |
#include <matrix.h> |
|
|
8 |
|
|
|
9 |
#define cimg_plugin "cimgmatlab.h" |
|
|
10 |
|
|
|
11 |
#include "CImg.h" |
|
|
12 |
#include <iostream> |
|
|
13 |
#include <string> |
|
|
14 |
|
|
|
15 |
using namespace cimg_library; |
|
|
16 |
using namespace std; |
|
|
17 |
|
|
|
18 |
// The lines below are necessary when using a non-standard compiler as visualcpp6. |
|
|
19 |
#ifdef cimg_use_visualcpp6 |
|
|
20 |
#define std |
|
|
21 |
#endif |
|
|
22 |
#ifdef min |
|
|
23 |
#undef min |
|
|
24 |
#undef max |
|
|
25 |
#endif |
|
|
26 |
|
|
|
27 |
#ifndef cimg_imagepath |
|
|
28 |
#define cimg_imagepath "img/" |
|
|
29 |
#endif |
|
|
30 |
|
|
|
31 |
//global constants |
|
|
32 |
const float smooth = 0.1f;//"Flow Smoothness" |
|
|
33 |
const float precision = 0.09f;//"Convergence precision" |
|
|
34 |
const unsigned int nb=110;//"Number of warped frames" |
|
|
35 |
const unsigned int nbscale = 0 ;//"Number of scales (0=auto)"); |
|
|
36 |
|
|
|
37 |
const bool normalize = true; //"Histogram normalization of the images" |
|
|
38 |
const bool morph = true;//"Morphing mode" |
|
|
39 |
const bool imode = true;//"Complete interpolation (or last frame is missing)" |
|
|
40 |
const bool dispflag = true;//"Visualization" |
|
|
41 |
//Functions |
|
|
42 |
CImg<> optmonoflow(const CImg<>& I1, const CImg<>& I2, const CImg<>& u0, |
|
|
43 |
const float smooth, const float precision, CImgDisplay& disp); |
|
|
44 |
CImg<> optflow(const CImg<>& xsrc, const CImg<>& xdest, |
|
|
45 |
const float smooth, const float precision, const unsigned int pnb_scale, CImgDisplay& disp); |
|
|
46 |
|
|
|
47 |
//mex function |
|
|
48 |
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { |
|
|
49 |
if (nrhs < 2) mexErrMsgTxt("No enough input arguments."); |
|
|
50 |
if (nrhs > 2) mexErrMsgTxt("Too many input arguments."); |
|
|
51 |
if (nrhs == 2){ |
|
|
52 |
CImg<> src_blur(prhs[0],false), dest_blur(prhs[1],false);//2 Input Volumes |
|
|
53 |
//Input images preprocessing |
|
|
54 |
src_blur = normalize?src_blur.get_blur(0.5f).equalize(256):src_blur.get_blur(0.5f), |
|
|
55 |
dest_blur = normalize?dest_blur.get_blur(0.5f).equalize(256):dest_blur.get_blur(0.5f); |
|
|
56 |
CImgDisplay disp; |
|
|
57 |
const CImg<> u = optflow(src_blur,dest_blur,smooth,precision,nbscale,disp); |
|
|
58 |
CImgDisplay disp2(src_blur); |
|
|
59 |
|
|
|
60 |
plhs[0] = u.toMatlab(); |
|
|
61 |
|
|
|
62 |
} |
|
|
63 |
return; |
|
|
64 |
|
|
|
65 |
} |
|
|
66 |
///////////////////////////////////////////////////////////////////////////////// |
|
|
67 |
|
|
|
68 |
CImg<> optflow(const CImg<>& xsrc, const CImg<>& xdest, |
|
|
69 |
const float smooth, const float precision, const unsigned int pnb_scale, CImgDisplay& disp) { |
|
|
70 |
const CImg<> |
|
|
71 |
src = xsrc.get_pointwise_norm(1).resize(xdest.dimx(),xdest.dimy(),xdest.dimz()).normalize(0,1), |
|
|
72 |
dest = xdest.get_pointwise_norm(1).resize(xdest.dimx(),xdest.dimy(),xdest.dimz()).normalize(0,1); |
|
|
73 |
CImg<> u = CImg<>(src.dimx(),src.dimy(),src.dimz(),3,1).fill(0); |
|
|
74 |
|
|
|
75 |
//multi-scalling |
|
|
76 |
const unsigned int nb_scale = pnb_scale>0?pnb_scale:(unsigned int)(2*log((double)(max(max(src.dimx(),src.dimy()),src.dimz())))); |
|
|
77 |
//const unsigned int nb_scale = pnb_scale>0?pnb_scale:(unsigned int)(2*std::log((double)(cimg::max(src.dimx(),src.dimy())))); |
|
|
78 |
for (int scale=nb_scale-1; scale>=0; scale--) { |
|
|
79 |
const CImg<> I1 = src.get_resize((int)(src.dimx()/std::pow(1.5,scale)), (int)(src.dimy()/std::pow(1.5,scale)) ,(int)(ceil(src.dimz()/std::pow(1.5,scale)))); |
|
|
80 |
const CImg<> I2 = dest.get_resize((int)(src.dimx()/std::pow(1.5,scale)), (int)(src.dimy()/std::pow(1.5,scale)) ,(int)(ceil(src.dimz()/std::pow(1.5,scale)))); |
|
|
81 |
u*=1.5; |
|
|
82 |
u = optmonoflow(I1,I2,u,smooth,(float)(precision/std::pow(2.25,1+scale)),disp);//apply optical flow algorithm for different scales |
|
|
83 |
|
|
|
84 |
} |
|
|
85 |
return u; |
|
|
86 |
} |
|
|
87 |
|
|
|
88 |
// optmonoflow() : estimate optical flow for one scale ( semi-implicite PDE scheme ) between I2->I1 |
|
|
89 |
//--------------- |
|
|
90 |
CImg<> optmonoflow(const CImg<>& I1, const CImg<>& I2, const CImg<>& u0, |
|
|
91 |
const float smooth, const float precision, CImgDisplay& disp) { |
|
|
92 |
|
|
|
93 |
CImg<float> u = u0.get_resize(I1.dimx(),I1.dimy(),I1.dimz(),3); |
|
|
94 |
CImg<float> dI(I2.dimx(),I2.dimy(),I2.dimz(),3); |
|
|
95 |
dI.fill(0); |
|
|
96 |
//CImg_3x3x3(I,float); |
|
|
97 |
float dt=2,E=1e20f; |
|
|
98 |
|
|
|
99 |
// compute first derivatives of I2 |
|
|
100 |
cimg_for3XYZ(dI,x,y,z){ |
|
|
101 |
dI(x,y,z,0) = 0.5*(I2(_n1x,y,z)-I2(_p1x,y,z));//derivatives of I2 |
|
|
102 |
dI(x,y,z,1) = 0.5*(I2(x,_n1y,z)-I2(x,_p1y,z)); |
|
|
103 |
dI(x,y,z,2) = 0.5*(I2(x,y,_n1z)-I2(x,y,_p1z)); |
|
|
104 |
|
|
|
105 |
} |
|
|
106 |
|
|
|
107 |
// Main PDE iteration |
|
|
108 |
for (unsigned int iter=0; iter<10000; iter++) { |
|
|
109 |
std::fprintf(stderr,"\r- Iteration %d - E = %g",iter,E); std::fflush(stderr); |
|
|
110 |
const float Eold = E; |
|
|
111 |
E = 0; |
|
|
112 |
cimg_for3XYZ(u,x,y,z) { //3x3 neighborhood |
|
|
113 |
const float |
|
|
114 |
X = x + u(x,y,z,0), |
|
|
115 |
Y = y + u(x,y,z,1), |
|
|
116 |
Z = z + u(x,y,z,2), |
|
|
117 |
deltaI = (float)(I2.linear_atXYZ(X,Y,Z) - I1(x,y,z));// partial derivative over time-dI/dt |
|
|
118 |
float tmpf = 0; |
|
|
119 |
cimg_forV(u,k) { |
|
|
120 |
const float |
|
|
121 |
ux = 0.5f*(u(_n1x,y,z,k)-u(_p1x,y,z,k)),//derivatives of velocity(displacemenet) |
|
|
122 |
uy = 0.5f*(u(x,_n1y,z,k)-u(x,_p1y,z,k)), |
|
|
123 |
uz = 0.5f*(u(x,y,_n1z,k)-u(x,y,_p1z,k)); |
|
|
124 |
u(x,y,z,k) = (float)( u(x,y,z,k) + |
|
|
125 |
dt*( |
|
|
126 |
-deltaI*dI.linear_atXYZ(X,Y,Z,k) + |
|
|
127 |
smooth* ( u(_n1x,y,z,k) + u(_p1x,y,z,k) + u(x,_n1y,z,k) + u(x,_p1y,z,k)+ u(x,y,_n1z,k) + u(x,y,_p1z,k)-6*u(x,y,z,k)) |
|
|
128 |
)/(1+4*smooth*dt) |
|
|
129 |
); |
|
|
130 |
tmpf += ux*ux + uy*uy + uz*uz; |
|
|
131 |
|
|
|
132 |
} |
|
|
133 |
E += deltaI*deltaI + smooth * tmpf; |
|
|
134 |
} |
|
|
135 |
if (cimg::abs(Eold-E)<precision) break; |
|
|
136 |
if (Eold<E) dt*=0.5; |
|
|
137 |
|
|
|
138 |
} |
|
|
139 |
return I1; |
|
|
140 |
} |
|
|
141 |
|
|
|
142 |
|