00001
00009 #ifndef SEGMENTATION_H
00010 #define SEGMENTATION_H
00011
00012 #include <sstream>
00013 #include <vector>
00014
00015 #include <Globals.h>
00016 #include <Schemes.h>
00017 #include <LevelSet.h>
00018 #include <Initializer.h>
00019 #include <DericheFilter.h>
00020
00021 #include <SegmentationModule/SegmentationModule.h>
00022
00023 using namespace Images;
00024 using namespace levelset;
00025
00026
00028 namespace segmentation {
00029
00031 template <class _Modules,class _LevelSet,class _Index>
00032 float sum(_Modules & modules, const _LevelSet & phi, const _Index & ind, int& indice)
00033 {
00034
00035
00036 float result = 0;
00037 for (int i=0; i<modules.size(); i++){
00038 const float value = modules[i]->value(phi, ind);
00039 const float weight = modules[i]->weight(ind);
00040 result += value*weight;
00041 }
00042 return result;
00043 }
00044
00060 template<unsigned DIM, typename Pixel = float>
00061 class Segmentation
00062 {
00063 public:
00064
00065 typedef BaseImage<DIM, Pixel> ImageType;
00066 typedef Initializer<DIM, float> Initializer;
00067 typedef LevelSet<DIM, float> LevelSet;
00068 typedef typename LevelSet::Index Index;
00069 typedef SegmentationModule<DIM,float> SegmentationModule;
00070 typedef std::vector<SegmentationModule *> Modules;
00071
00072 typedef float (* ModuleAssembler)(Modules &, const LevelSet &, const Index &, int &);
00073
00074 typedef Schemes<DIM,float> Schemes;
00075 typedef Pixels::RGB<unsigned char> RGBPixel;
00076 typedef BaseImage<DIM, RGBPixel> ColorImageType;
00077
00080
00082 Segmentation(LevelSet * _phi,
00083 Initializer * _init,
00084 ImageType * _data = NULL,
00085 BaseImage<DIM, bool> * _mask = NULL,
00086 float _dt = 0.5f,
00087 int _reinit_freq = 1
00088 );
00089
00091 virtual ~Segmentation();
00092
00094
00096
00098 void add_module(SegmentationModule & _sm);
00100 void remove_module(SegmentationModule & _sm);
00102 void set_module_assembler(ModuleAssembler _assembler);
00104 void set_level_set(LevelSet & _phi);
00106 void set_initializer(Initializer & _init);
00108 void set_data_term(ImageType & _data);
00110 void set_mask(BaseImage<DIM, bool>& _mask);
00112 float & dt();
00114 int & reinit_freq();
00115
00117
00119
00121 ColorImageType get_result(RGBPixel neg = RGBPixel(0,0,0), RGBPixel pos = RGBPixel(255,255,255));
00123 ImageType get_binary_result();
00125 ImageType get_speed(int _module = 0);
00127 float get_energy();
00128
00130
00132
00134 void segment(int nbiter = 30, std::string evodir="", RGBPixel neg = RGBPixel(0,0,0), RGBPixel pos = RGBPixel(255,255,255));
00136 bool stop_condition(int iter, int nbiter);
00138 void init();
00140 void iterate(int iter, int nbiter);
00141
00142 protected:
00143
00145
00147
00148 LevelSet * m_phi;
00149 BaseImage<DIM, float> m_dphi;
00150 Initializer * m_init;
00151 ImageType * m_data;
00152 std::vector<SegmentationModule *> m_sm;
00153 ModuleAssembler m_assembler;
00154 BaseImage<DIM, bool> * m_mask;
00155 int m_reinit_freq;
00156 float m_dt;
00157 bool m_stop_condition;
00158
00160 };
00161
00162
00170
00171
00172
00173
00174 template<unsigned DIM, typename Pixel>
00175 Segmentation<DIM, Pixel>::Segmentation(LevelSet * _phi, Initializer * _init, ImageType * _data, BaseImage<DIM, bool> * _mask, float _dt, int _reinit_freq)
00176 :m_phi(_phi), m_dphi(_phi->shape()), m_init(_init), m_data(_data), m_assembler(&sum), m_mask(_mask), m_reinit_freq(_reinit_freq), m_dt(_dt), m_stop_condition(false)
00177 {
00178 if (_data != NULL && _data->shape() != _phi->shape()) {
00179 std::cerr << "Error : Shape of the data term and shape of the LevelSet don't match" << std::endl;
00180 exit(1);
00181 }
00182 if (_mask != NULL && _mask->shape() != _phi->shape()) {
00183 std::cerr << "Error : Shape of the mask and shape of the LevelSet don't match" << std::endl;
00184 exit(1);
00185 }
00186 }
00187
00188 template<unsigned DIM, typename Pixel>
00189 Segmentation<DIM, Pixel>::~Segmentation()
00190 { }
00191
00192
00194
00195
00196
00197 template<unsigned DIM, typename Pixel>
00198 void Segmentation<DIM, Pixel>::add_module(SegmentationModule & _sm)
00199 {
00200 m_sm.push_back(&_sm);
00201 }
00202
00203 template<unsigned DIM, typename Pixel>
00204 void Segmentation<DIM, Pixel>::remove_module(SegmentationModule & _sm)
00205 {
00206 for (int i=0 ; i<m_sm.size() ; i++)
00207 if (m_sm[i] == &_sm){
00208 std::swap(m_sm[i], *m_sm.end());
00209 m_sm.pop_back();
00210 return;
00211 }
00212 }
00213
00214 template<unsigned DIM, typename Pixel>
00215 void Segmentation<DIM, Pixel>::set_module_assembler(ModuleAssembler _assembler)
00216 {
00217 m_assembler = _assembler;
00218 }
00219
00220 template<unsigned DIM, typename Pixel>
00221 void Segmentation<DIM, Pixel>::set_mask( BaseImage<DIM, bool>& _mask)
00222 {
00223 if (_mask.shape() != m_phi->shape()) {
00224 std::cerr << "Error : Shape of the mask and shape of the LevelSet don't match" << std::endl;
00225 exit(1);
00226 }
00227 m_mask = &_mask;
00228 }
00229
00230 template<unsigned DIM, typename Pixel>
00231 void Segmentation<DIM, Pixel>::set_initializer(Initializer & _init)
00232 {
00233 m_init = &_init;
00234 }
00235
00236 template<unsigned DIM, typename Pixel>
00237 void Segmentation<DIM, Pixel>::set_level_set(LevelSet & _phi)
00238 {
00239 m_phi = &_phi;
00240 }
00241
00242 template<unsigned DIM, typename Pixel>
00243 void Segmentation<DIM, Pixel>::set_data_term(ImageType & _data)
00244 {
00245 if (_data.shape() != m_phi->shape()) {
00246 std::cerr << "Error : Shape of the data term and shape of the LevelSet don't match" << std::endl;
00247 exit(1);
00248 }
00249 m_data = &_data;
00250 }
00251
00252 template<unsigned DIM, typename Pixel>
00253 float & Segmentation<DIM, Pixel>::dt()
00254 {
00255 return m_dt;
00256 }
00257
00258 template<unsigned DIM, typename Pixel>
00259 int & Segmentation<DIM, Pixel>::reinit_freq()
00260 {
00261 return m_reinit_freq;
00262 }
00263
00264
00266
00267
00268
00269 template<unsigned DIM, typename Pixel>
00270 typename Segmentation<DIM, Pixel>::ColorImageType Segmentation<DIM, Pixel>::get_result(RGBPixel neg, RGBPixel pos)
00271 {
00272 ColorImageType result;
00273
00274 result.resize(m_phi->shape());
00275
00276 if (m_data == NULL)
00277 result = 255;
00278 else
00279 result = blitz::cast<unsigned char>(*m_data);
00280
00281 #pragma omp parallel for
00282 for (int i = 0 ; i < m_phi->nb_points() ; i++){
00283 const Index& ind = m_phi->get_point(i);
00284
00285 const float _phi = (*m_phi)(ind);
00286
00287 int inf_coords[DIM];
00288 int sup_coords[DIM];
00289 Schemes::find_neighbours(*m_phi, ind, inf_coords, sup_coords);
00290
00291 for (int i=0 ; i<DIM ; i++){
00292 Index inf = ind;
00293 Index sup = ind;
00294 inf(i+1) = inf_coords[i];
00295 sup(i+1) = sup_coords[i];
00296 if ((_phi * (*m_phi)(inf) <= 0) || (_phi * (*m_phi)(sup) <= 0))
00297 result(ind) = (_phi>0)? pos: neg;
00298 }
00299 }
00300
00301 return result;
00302 }
00303
00304 template<unsigned DIM, typename Pixel>
00305 typename Segmentation<DIM, Pixel>::ImageType Segmentation<DIM, Pixel>::get_binary_result()
00306 {
00307 ImageType result(m_phi->shape());
00308 for (typename ImageType::template iterator<domain> ind=result.begin() ; ind!=result.end() ; ++ind )
00309 result(ind) = ((*m_phi)(ind) < 0)? 0 : 255;
00310
00311 return result;
00312 }
00313
00314 template<unsigned DIM, typename Pixel>
00315 typename Segmentation<DIM, Pixel>::ImageType Segmentation<DIM, Pixel>::get_speed(int _module)
00316 {
00317 ImageType result(m_phi->shape());
00318 result = 0;
00319
00320 if (_module < 0 || _module > m_sm.size()){
00321 std::cerr << " Module does not exist !" << std::endl;
00322 return result;
00323 }
00324
00325 if (_module == 0){
00326 int indice;
00327 #pragma omp parallel for
00328 for (int i = 0 ; i < m_phi->nb_points() ; i++){
00329 const Index& ind = m_phi->get_point(i);
00330 if (m_mask==NULL || (*m_mask)(ind)==true)
00331 result(ind) = m_assembler(m_sm, *m_phi, ind, indice);
00332 }
00333 }
00334 else {
00335 #pragma omp parallel for
00336 for (int i = 0 ; i < m_phi->nb_points() ; i++){
00337 const Index& ind = m_phi->get_point(i);
00338 if (m_mask==NULL || (*m_mask)(ind)==true){
00339 const float value = m_sm[_module-1]->value(*m_phi, ind);
00340 const float weight = m_sm[_module-1]->weight(ind);
00341 result(ind) = value*weight;
00342 }
00343 }
00344 }
00345
00346 return result;
00347 }
00348
00349 template<unsigned DIM, typename Pixel>
00350 float Segmentation<DIM, Pixel>::get_energy()
00351 {
00352 float total_energy = 0;
00353
00354 for (unsigned int i = 0 ; i < m_phi->nb_points() ; i++){
00355
00356 const Index& ind = m_phi->get_point(i);
00357
00358 if (m_mask==NULL || (*m_mask)(ind)!=0)
00359 for (int j=0; j<m_sm.size(); j++){
00360 const float energy = m_sm[j]->energy(*m_phi, ind);
00361 const float weight = m_sm[j]->weight(ind);
00362 total_energy += energy*weight;
00363 }
00364 }
00365
00366 return total_energy;
00367 }
00368
00369
00371
00372
00373 template<unsigned DIM, typename Pixel>
00374 void Segmentation<DIM, Pixel>::segment(int nbiter, std::string evodir, RGBPixel neg, RGBPixel pos)
00375 {
00376
00377 init();
00378
00379
00380 for (int i=0 ; !m_stop_condition ; i++){
00381
00382 std::cout << i << std::endl;
00383
00384 #ifdef SAVE_EVOLUTION
00385 if((i%int(SAVE_EVOLUTION))==0) {
00386
00387 std::ostringstream name;
00388
00389
00390 std::ofstream file1;
00391 std::ofstream file2;
00392 std::ofstream file3;
00393
00394 #if 1
00395
00396 std::cout << " - Energy : " << get_energy() << std::endl;
00397
00398 name.str("");
00399 name << evodir << "phi_" << std::setw(6) << std::setfill('0') << i << ".inr";
00400 file1.open(name.str().c_str());
00401 file1 << format("inrimage") << *m_phi;
00402 std::cout << " - Saved " << name.str() << " ..." << std::endl;
00403 #endif
00404
00405 #if 1
00406 if (DIM == 2){
00407
00408 name.str("");
00409 name << evodir << "result_" << std::setw(6) << std::setfill('0') << i << ".ppm";
00410 file2.open(name.str().c_str());
00411 file2 << format("rawppm") << get_result(neg, pos);
00412 std::cout << " - Saved " << name.str() << " ..." << std::endl;
00413 }
00414 else {
00415
00416 name.str("");
00417 name << evodir << "result_" << std::setw(6) << std::setfill('0') << i << ".inr";
00418 file2.open(name.str().c_str());
00419 ImageType result(m_phi->shape());
00420 result = blitz::cast<float>(get_result(neg, pos));
00421 file2 << format("Inrimage-5") << result;
00422 std::cout << " - Saved " << name.str() << " ..." << std::endl;
00423 }
00424 #endif
00425
00426 #if 0 // speed
00427 for (int j=1; j<=m_sm.size(); j++){
00428 std::ofstream file3;
00429 name.str("");
00430 name << evodir << "speed_module" << j << "_" << std::setw(6) << std::setfill('0') << i << ".inr";
00431 file3.open(name.str().c_str());
00432 file3 << format("inrimage") << get_speed(j) ;
00433 std::cout << " - Saved " << name.str() << " ..." << std::endl;
00434 }
00435 name.str("");
00436 name << evodir << "speed_" << std::setw(6) << std::setfill('0') << i << ".inr";
00437 file3.open(name.str().c_str());
00438 file3 << format("inrimage") << get_speed(0) ;
00439 std::cout << " - Saved " << name.str() << " ..." << std::endl;
00440 #endif
00441
00442 #if 1
00443 for (int j=0; j<m_sm.size(); j++)
00444 m_sm[j]->save_result(*m_phi, evodir, i);
00445 #endif
00446 }
00447 #endif
00448
00449 iterate(i, nbiter);
00450 }
00451 }
00452
00453 template<unsigned DIM, typename Pixel>
00454 bool Segmentation<DIM, Pixel>::stop_condition(int iter, int nbiter)
00455 {
00456
00457 if (nbiter < 0){
00458
00459
00460
00461 static BaseImage<DIM, short> sign_change(m_phi->shape());
00462 static int count = 0;
00463
00464 if (iter == 0) {
00465 sign_change = 0;
00466 count = 0;
00467 }
00468
00469 int nb_sign_change = 0;
00470 for (int i = 0 ; i < m_phi->pos_to_neg_index() ; i++){
00471 const Index& ind = m_phi->get_point(i);
00472 if (iter - sign_change(ind) > 50)
00473 nb_sign_change++;
00474 sign_change(ind) = iter;
00475 }
00476
00477 for (int i = m_phi->neg_to_pos_index() ; i < m_phi->nb_points() ; i++){
00478 const Index& ind = m_phi->get_point(i);
00479 if (iter - sign_change(ind) > 50)
00480 nb_sign_change++;
00481 sign_change(ind) = iter;
00482 }
00483
00484 if (nb_sign_change > 0) count = 0;
00485 return ((nb_sign_change == 0) && (++count > 20)) || (iter >= 2000);
00486 }
00487
00488
00489 else return (iter >= nbiter);
00490 }
00491
00492 template<unsigned DIM, typename Pixel>
00493 void Segmentation<DIM, Pixel>::init()
00494 {
00495
00496 if (m_dphi.shape() != m_phi->shape())
00497 m_dphi.resize(m_phi->shape());
00498
00499 m_dphi=0.0f;
00500
00501
00502 for (int i=0; i<m_sm.size(); i++)
00503 m_sm[i]->init(*m_phi);
00504
00505 m_stop_condition = false;
00506 }
00507
00508 template<unsigned DIM, typename Pixel>
00509 void Segmentation<DIM, Pixel>::iterate(int iter, int nbiter)
00510 {
00511 #ifdef PRINT_TIME
00512 timeval _time;
00513 Globals::initChrono(_time);
00514 #endif
00515
00516 m_dphi=0.0f;
00517
00519
00520
00521 int indice;
00523
00524
00525 #pragma omp parallel for
00526 for (int i = 0 ; i < m_phi->nb_points() ; i++){
00527
00528 const Index& ind = m_phi->get_point(i);
00529 m_dphi(ind)=0.0f;
00530
00531 if (m_mask==NULL || (*m_mask)(ind)==true)
00532 m_dphi(ind) = m_assembler(m_sm, *m_phi, ind, indice);
00533
00534 }
00535
00537
00538
00539
00540
00541
00542
00543
00545
00546 #ifdef PRINT_TIME
00547 Globals::printChrono(" => compute speed : ", _time);
00548 Globals::initChrono(_time);
00549 #endif
00550
00551
00552 m_phi->update(m_dphi, m_dt);
00553
00554 #ifdef PRINT_TIME
00555 Globals::printChrono(" => update Level set : ", _time);
00556 Globals::initChrono(_time);
00557 #endif
00558
00559
00560 m_stop_condition = stop_condition(iter, nbiter);
00561
00562 #ifdef PRINT_TIME
00563 Globals::printChrono(" => stop condition : ", _time);
00564 Globals::initChrono(_time);
00565 #endif
00566
00567
00568 for (int i=0; i<m_sm.size(); i++)
00569 if (m_sm[i]->adaptive()) m_sm[i]->update(*m_phi);
00570
00571 #ifdef PRINT_TIME
00572 Globals::printChrono(" => total update modules : ", _time);
00573 Globals::initChrono(_time);
00574 #endif
00575
00576
00577 if(iter%m_reinit_freq == 0)
00578 m_init->reinit_band(*m_phi);
00579
00580 #ifdef PRINT_TIME
00581 Globals::printChrono(" => total reinit band : ", _time);
00582 Globals::initChrono(_time);
00583 #endif
00584 }
00585 }
00586
00587 #endif // SEGMENTATION_H