00001 #ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_CHANVESE_H
00002 #define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_CHANVESE_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/core/math/math_vector3.h>
00013 #include <OpenTissue/core/math/math_matrix3x3.h>
00014 #include <OpenTissue/core/containers/grid/grid.h>
00015
00016 #include <boost/cast.hpp>
00017
00018 #include <iostream>
00019 #include <cmath>
00020 #include <algorithm>
00021
00022 namespace OpenTissue
00023 {
00024 namespace grid
00025 {
00026
00027
00028
00029 namespace chan_vese{
00030
00047 template<
00048 typename grid_type_in
00049 , typename image_grid_type
00050 , typename real_type
00051 , typename grid_type_out
00052 >
00053 inline real_type update(
00054 grid_type_in const & phi
00055 , image_grid_type const & U
00056 , typename image_grid_type::value_type const & C_in
00057 , typename image_grid_type::value_type const & C_out
00058 , real_type const & lambda
00059 , real_type const & mu
00060 , real_type const & nu
00061 , real_type const & dt
00062 , grid_type_out & psi
00063 )
00064 {
00065 using std::max;
00066 using std::fabs;
00067
00068 typedef typename grid_type_in::value_type input_type;
00069 typedef typename grid_type_out::value_type output_type;
00070 typedef typename image_grid_type::value_type image_type;
00071 typedef typename grid_type_in::const_index_iterator input_iterator;
00072 typedef typename grid_type_out::index_iterator output_iterator;
00073
00074 assert(mu>=0 || !"update(): curvature coefficient must be non-negative");
00075 assert(nu>=0 || !"update(): area coefficient must be non-negative");
00076 assert(dt>0 || !"update(): time-step must be positive");
00077 assert(lambda>=0 || !"update(): region weight must be non-negative");
00078 assert(lambda<=1 || !"update(): region weight must be less than or equal to one");
00079
00080 assert(phi.I() == psi.I() || !"update(): incompatible grid dimensions");
00081 assert(phi.J() == psi.J() || !"update(): incompatible grid dimensions");
00082 assert(phi.K() == psi.K() || !"update(): incompatible grid dimensions");
00083
00084 real_type lambda_in = lambda;
00085 real_type lambda_out = real_type(1.0) - lambda;
00086 real_type max_delta = real_type(0.0);
00087
00088 input_iterator input_begin = phi.begin();
00089 input_iterator input_end = phi.end();
00090 input_iterator input = input_begin;
00091
00092 output_iterator output_begin = psi.begin();
00093 output_iterator output_end = psi.end();
00094 output_iterator output = output_begin;
00095
00096 input_type unused = phi.unused();
00097
00098 for(;input!=input_end;++input,++output)
00099 {
00100 if(*input!=unused)
00101 {
00102 input_type old_val = *input;
00103
00104 image_type u0 = U(input.get_index());
00105 output_type speed = output_type(0);
00106 if(mu)
00107 {
00108 input_type H = input_type(0);
00109 mean_curvature( input, H );
00110 speed -= mu*H;
00111 }
00112 speed += nu;
00113 speed -= lambda_in*(u0-C_in)*(u0-C_in);
00114 speed += lambda_out*(u0-C_out)*(u0-C_out);
00115 *output = old_val - dt*speed;
00116
00117 max_delta = max(max_delta, fabs(*output - old_val) );
00118 }
00119 }
00120 return max_delta;
00121 }
00122
00132 template<typename grid_type,typename image_grid_type>
00133 inline typename image_grid_type::value_type compute_cin(
00134 grid_type const & phi
00135 , image_grid_type const & U
00136 )
00137 {
00138 typedef typename grid_type::value_type input_type;
00139 typedef typename image_grid_type::value_type image_type;
00140 typedef typename grid_type::const_index_iterator input_iterator;
00141
00142 size_t voxels_inside = 0;
00143 double C_in = 0.0;
00144 input_iterator input_begin = phi.begin();
00145 input_iterator input_end = phi.end();
00146 input_iterator input;
00147 input_type unused = phi.unused();
00148 for(input=input_begin;input!=input_end;++input)
00149 {
00150 if(*input==unused)
00151 continue;
00152 if(*input<0)
00153 {
00154 C_in += U( input.get_index() );
00155 ++voxels_inside;
00156 }
00157 }
00158 C_in /= voxels_inside;
00159 return image_type(C_in);
00160 }
00161
00171 template<typename grid_type,typename image_grid_type>
00172 inline typename image_grid_type::value_type compute_cout(
00173 grid_type const & phi
00174 , image_grid_type const & U
00175 )
00176 {
00177 typedef typename grid_type::value_type input_type;
00178 typedef typename image_grid_type::value_type image_type;
00179 typedef typename grid_type::const_index_iterator input_iterator;
00180
00181 size_t voxels_outside = 0;
00182 double C_out = 0.0;
00183 input_iterator input_begin = phi.begin();
00184 input_iterator input_end = phi.end();
00185 input_iterator input;
00186 input_type unused = phi.unused();
00187 for(input=input_begin;input!=input_end;++input)
00188 {
00189 if(*input==unused)
00190 continue;
00191 if(*input>=0)
00192 {
00193 C_out += U( input.get_index() );
00194 ++voxels_outside;
00195 }
00196 }
00197 C_out /= voxels_outside;
00198 return image_type(C_out);
00199 }
00200
00211 template<typename grid_type,typename real_type>
00212 inline void compute_volume(
00213 grid_type const & phi
00214 , real_type & V
00215 )
00216 {
00217 typedef typename grid_type::const_iterator input_iterator;
00218 typedef typename grid_type::value_type input_type;
00219
00220 size_t voxels = 0;
00221 input_iterator input_begin = phi.begin();
00222 input_iterator input_end = phi.end();
00223 input_iterator input;
00224 input_type unused = phi.unused();
00225 for(input=input_begin;input!=input_end;++input)
00226 {
00227 if(*input==unused)
00228 continue;
00229 if(*input<0)
00230 ++ voxels;
00231 }
00232 V = real_type( voxels*phi.dx()*phi.dy()*phi.dz());
00233 }
00234
00243 template<typename grid_type,typename image_grid_type>
00244 inline void threshold_initialize(
00245 image_grid_type const & U
00246 , typename image_grid_type::value_type const& min_value
00247 , typename image_grid_type::value_type const& max_value
00248 , grid_type & phi
00249 )
00250 {
00251 using OpenTissue::grid::min_element;
00252 using OpenTissue::grid::max_element;
00253
00254 typedef typename image_grid_type::value_type image_type;
00255 typedef typename grid_type::index_iterator output_iterator;
00256
00257 assert(min_value < max_value || !"threshold_initialize(): min value must be less than max value");
00258 assert(min_value>min_element(U) || !"threshold_initialize(): min value must be greather than minimum image value");
00259 assert(max_value<max_element(U) || !"threshold_initialize(): max value must be lesser than maximum image value");
00260
00261 output_iterator output_begin = phi.begin();
00262 output_iterator output_end = phi.end();
00263 output_iterator output;
00264 for(output=output_begin;output!=output_end;++output)
00265 {
00266 image_type value = U( output.get_index() );
00267 if(value >= min_value && value <= max_value)
00268 *output = -100;
00269 else
00270 *output = 100;
00271 }
00272 }
00273
00274 }
00275
00289 template<
00290 typename grid_type_in
00291 , typename image_grid_type
00292 , typename real_type
00293 , typename grid_type_out
00294 >
00295 inline void chan_vese_auto_in_out(
00296 grid_type_in & phi
00297 , image_grid_type const & U
00298 , real_type const & lambda
00299 , real_type const & mu
00300 , real_type const & nu
00301 , real_type const & dt
00302 , grid_type_out & psi
00303 , real_type const & epsilon = 10e-7
00304 , size_t const & max_iterations = 10
00305 )
00306 {
00307 typedef typename image_grid_type::value_type image_type;
00308
00309 assert(mu>=0 || !"chan_vese_auto_in_out(): curvature coefficient must be non-negative");
00310 assert(nu>=0 || !"chan_vese_auto_in_out(): area coefficient must be non-negative");
00311 assert(dt>0 || !"chan_vese_auto_in_out(): time-step must be positive");
00312 assert(lambda>=0 || !"chan_vese_auto_in_out(): region weight must be non-negative");
00313 assert(lambda<=1 || !"chan_vese_auto_in_out(): region weight must be less than or equal to one");
00314
00315 image_type C_in = chan_vese::compute_cin(phi,U);
00316 image_type C_out = chan_vese::compute_cout(phi,U);
00317 size_t unchanged = 0;
00318 for(size_t iteration = 0;iteration<max_iterations;++iteration)
00319 {
00320 if (C_in == C_out)
00321 {
00322
00323
00324
00325 const real_type upper = boost::numeric_cast<real_type>( 1.1 );
00326 const real_type lower = boost::numeric_cast<real_type>( 0.9 );
00327 C_in = boost::numeric_cast<image_type>( C_in* upper );
00328 C_out = boost::numeric_cast<image_type>( C_out * lower );
00329 }
00330 real_type max_delta = chan_vese::update(phi,U,C_in,C_out,lambda,mu,nu,dt,psi);
00331 std::cout << "Chan-Vese: Delta max = " << max_delta << std::endl;
00332 if(max_delta < epsilon )
00333 {
00334 std::cout << "Chan-Vese: Steady state reached in " << iteration << " iteration, delta max = " << max_delta << std::endl;
00335 return;
00336 }
00337 phi = psi;
00338 image_type C_in_new = chan_vese::compute_cin(phi,U);
00339 image_type C_out_new = chan_vese::compute_cout(phi,U);
00340
00341
00342 if((C_in == C_in_new)&&(C_out == C_out_new))
00343 {
00344 ++unchanged;
00345 if(unchanged >= 3)
00346 {
00347 std::cout << "Chan-Vese: Average region unchanged in 3 iterations" << std::endl;
00348 return;
00349 }
00350 }
00351 else if(unchanged>0)
00352 --unchanged;
00353
00354 C_in = C_in_new;
00355 C_out = C_out_new;
00356
00357 }
00358 std::cout << "Chan-Vese: Maximum iterations reached minimum" << std::endl;
00359 }
00360
00373 template<
00374 typename grid_type_in
00375 , typename image_type
00376 , typename real_type
00377 , typename grid_type_out
00378 >
00379 inline void chan_vese_fixed_in_out(
00380 grid_type_in const & phi
00381 , image_type const & U
00382 , typename image_type::value_type const & C_in
00383 , typename image_type::value_type const & C_out
00384 , real_type const & lambda
00385 , real_type const & mu
00386 , real_type const & nu
00387 , real_type const & dt
00388 , grid_type_out & psi
00389 )
00390 {
00391 assert(mu>=0 || !"chan_vese_fixed_in_out(): curvature coefficient must be non-negative");
00392 assert(nu>=0 || !"chan_vese_fixed_in_out(): area coefficient must be non-negative");
00393 assert(dt>0 || !"chan_vese_fixed_in_out(): time-step must be positive");
00394 assert(lambda>=0 || !"chan_vese_fixed_in_out(): region weight must be non-negative");
00395 assert(lambda<=1 || !"chan_vese_fixed_in_out(): region weight must be less than or equal to one");
00396
00397 chan_vese::update(phi,U,C_in,C_out,lambda,mu,nu,dt,psi);
00398 }
00399
00400
00412 template<
00413 typename grid_type_in
00414 , typename image_grid_type
00415 , typename real_type
00416 , typename grid_type_out
00417 >
00418 inline void chan_vese_fixed_in(
00419 grid_type_in const & phi
00420 , image_grid_type const & U
00421 , typename image_grid_type::value_type C_in
00422 , real_type const & lambda
00423 , real_type const & mu
00424 , real_type const & nu
00425 , real_type const & dt
00426 , grid_type_out & psi
00427 )
00428 {
00429 typedef typename image_grid_type::value_type image_type;
00430
00431 assert(mu>=0 || !"chan_vese_fixed_in(): curvature coefficient must be non-negative");
00432 assert(nu>=0 || !"chan_vese_fixed_in(): area coefficient must be non-negative");
00433 assert(dt>0 || !"chan_vese_fixed_in(): time-step must be positive");
00434 assert(lambda>=0 || !"chan_vese_fixed_in(): region weight must be non-negative");
00435 assert(lambda<=1 || !"chan_vese_fixed_in(): region weight must be less than or equal to one");
00436
00437 image_type C_out = chan_vese::compute_cout(phi,U);
00438 if (C_in == C_out)
00439 {
00440
00441
00442
00443 const real_type upper = boost::numeric_cast<real_type>( 1.1 );
00444 const real_type lower = boost::numeric_cast<real_type>( 0.9 );
00445 C_in = boost::numeric_cast<image_type>( C_in* upper );
00446 C_out = boost::numeric_cast<image_type>( C_out * lower );
00447 }
00448 chan_vese::update(phi,U,C_in,C_out,lambda,mu,nu,dt,psi);
00449 }
00450
00451
00463 template<
00464 typename grid_type_in
00465 , typename image_grid_type
00466 , typename real_type
00467 , typename grid_type_out
00468 >
00469 inline void chan_vese_fixed_out(
00470 grid_type_in const & phi
00471 , image_grid_type const & U
00472 , typename image_grid_type::value_type C_out
00473 , real_type const & lambda
00474 , real_type const & mu
00475 , real_type const & nu
00476 , real_type const & dt
00477 , grid_type_out & psi
00478 )
00479 {
00480 typedef typename image_grid_type::value_type image_type;
00481
00482 assert(mu>=0 || !"chan_vese_fixed_out(): curvature coefficient must be non-negative");
00483 assert(nu>=0 || !"chan_vese_fixed_out(): area coefficient must be non-negative");
00484 assert(dt>0 || !"chan_vese_fixed_out(): time-step must be positive");
00485 assert(lambda>=0 || !"chan_vese_fixed_out(): region weight must be non-negative");
00486 assert(lambda<=1 || !"chan_vese_fixed_out(): region weight must be less than or equal to one");
00487
00488 image_type C_in = chan_vese::compute_cin(phi,U);
00489 if (C_in == C_out)
00490 {
00491
00492
00493
00494 const real_type upper = boost::numeric_cast<real_type>( 1.1 );
00495 const real_type lower = boost::numeric_cast<real_type>( 0.9 );
00496 C_in = boost::numeric_cast<image_type>( C_in* upper );
00497 C_out = boost::numeric_cast<image_type>( C_out * lower );
00498 }
00499 chan_vese::update(phi,U,C_in,C_out,lambda,mu,nu,dt,psi);
00500 }
00501
00502 }
00503 }
00504
00505
00506 #endif