contrib/brl/bseg/sdet/sdet_watershed_region_proc.cxx
Go to the documentation of this file.
00001 // This is brl/bseg/sdet/sdet_watershed_region_proc.cxx
00002 #include "sdet_watershed_region_proc.h"
00003 //:
00004 // \file
00005 #include <vcl_algorithm.h>
00006 #include <vnl/vnl_numeric_traits.h>
00007 #include <vil1/vil1_memory_image_of.h>
00008 #include <vsol/vsol_box_2d.h>
00009 #include <brip/brip_vil1_float_ops.h>
00010 #include <brip/brip_roi.h>
00011 #include <brip/brip_watershed.h>
00012 #include <bdgl/bdgl_region_algs.h>
00013 #include <sdet/sdet_region.h>
00014 
00015 //Gives a sort on region intensity in increasing order
00016 static bool region_intensity_compare_increasing(sdet_region_sptr const r1,
00017                                                 sdet_region_sptr const r2)
00018 {
00019   return r2->Io() > r1->Io();
00020 }
00021 
00022 //Gives a sort on region intensity in decreasing order
00023 static bool region_intensity_compare_decreasing(sdet_region_sptr const r1,
00024                                                 sdet_region_sptr const r2)
00025 {
00026   return r1->Io() > r2->Io();
00027 }
00028 
00029 //Gives a sort on region area in increasing order
00030 static bool region_area_compare_increasing(sdet_region_sptr const r1,
00031                                            sdet_region_sptr const r2)
00032 {
00033   return r2->Npix() > r1->Npix();
00034 }
00035 
00036 //Gives a sort on region area in decreasing order
00037 static bool region_area_compare_decreasing(sdet_region_sptr const r1,
00038                                            sdet_region_sptr const r2)
00039 {
00040   return r1->Npix() > r2->Npix();
00041 }
00042 
00043 //---------------------------------------------------------------
00044 // Constructors
00045 //  regions_ = temp2;
00046 
00047 //----------------------------------------------------------------
00048 
00049 //: constructor from a parameter block (the only way)
00050 //
00051 sdet_watershed_region_proc::sdet_watershed_region_proc(sdet_watershed_region_proc_params& wrpp)
00052   : sdet_watershed_region_proc_params(wrpp)
00053 {
00054   regions_valid_ = false;
00055   region_image_valid_ =false;
00056   boundaries_valid_ = false;
00057   min_label_ = 0;
00058   max_label_ = 0;
00059 }
00060 
00061 //:Default Destructor
00062 sdet_watershed_region_proc::~sdet_watershed_region_proc()
00063 {
00064   for (vcl_map<sdet_region_sptr, vcl_vector<sdet_region_sptr>* >::iterator
00065        rait = region_adjacency_.begin(); rait != region_adjacency_.end(); ++rait)
00066     delete (*rait).second;
00067 }
00068 
00069 //: if an roi is defined then create a chip image and define the bounds
00070 void sdet_watershed_region_proc::clip_image()
00071 {
00072   if (!image_ || !roi_)
00073     return;
00074   vsol_box_2d_sptr box = roi_->region(0);
00075   if (! brip_vil1_float_ops::chip(image_, box, clip_))
00076     vcl_cout << "sdet_watershed_region_proc::chip_out_roi(.) - failed\n";
00077 }
00078 
00079 //-------------------------------------------------------------------------
00080 //: Set the image to be processed
00081 //
00082 void sdet_watershed_region_proc::set_image(vil1_image const& image,
00083                                            vsol_box_2d_sptr const& box)
00084 {
00085   if (!image)
00086   {
00087     vcl_cout <<"In sdet_watershed_region_proc::set_image(.) - null input\n";
00088     return;
00089   }
00090 
00091   image_ = brip_vil1_float_ops::convert_to_float(image);
00092 
00093   if (box)
00094   {
00095     roi_ = new brip_roi(image.width(), image.height());
00096     roi_->add_region(box);
00097     this->clip_image();
00098   }
00099   regions_valid_ = false;
00100   region_image_valid_ =false;
00101   boundaries_valid_ = false;
00102 }
00103 
00104 
00105 //----------------------------------------------------------------
00106 //: scan the region label array to fill region pixel data
00107 //
00108 void sdet_watershed_region_proc::scan_region_data(vbl_array_2d<unsigned int> const & lab_array)
00109 {
00110   int rows = lab_array.rows(), cols = lab_array.cols();
00111   int n_regions = max_label_ - min_label_ +1;
00112   //initialize the regions
00113   for (int r = 0; r<rows; r++)
00114     for (int c = 0; c<cols; c++)
00115     {
00116       int imgc = c, imgr = r;
00117       if (roi_)
00118       {
00119         imgc = roi_->ic(c);
00120         imgr = roi_->ir(r);
00121       }
00122       unsigned int lab = lab_array[r][c];
00123       if (lab<min_label_ || lab>max_label_)
00124         continue;
00125       int index = lab-min_label_;
00126       //dangerous, might not be scaled properly (FIXME)
00127       unsigned short v =  (unsigned short) image_(imgc, imgr);
00128       regions_[index]->IncrementMeans(float(imgc), float(imgr), v);
00129     }
00130   //fill the region data
00131   for (int i = 0; i<n_regions; i++)
00132     regions_[i]->InitPixelArrays();
00133 
00134   for (int r = 0; r<rows; r++)
00135     for (int c = 0; c<cols; c++)
00136     {
00137       int imgc = c, imgr = r;
00138       if (roi_)
00139       {
00140         imgc = roi_->ic(c);
00141         imgr = roi_->ir(r);
00142       }
00143       unsigned int lab = lab_array[r][c];
00144       if (lab<min_label_ || lab>max_label_)
00145         continue;
00146       int index = lab-min_label_;
00147       //dangerous, might not be scaled properly (FIXME)
00148       unsigned short v = (unsigned short) image_(imgc, imgr);
00149       regions_[index]->InsertInPixelArrays(float(imgc), float(imgr), v);
00150       regions_[index]->ComputeIntensityStdev();
00151     }
00152 }
00153 
00154 bool sdet_watershed_region_proc::add_adjacency(sdet_region_sptr const& reg,
00155                                                sdet_region_sptr const& adj_reg)
00156 {
00157   vcl_map<sdet_region_sptr, vcl_vector<sdet_region_sptr>* >::iterator rai;
00158   rai = region_adjacency_.find(reg);
00159 
00160   if (rai !=region_adjacency_.end())
00161   {
00162     vcl_vector<sdet_region_sptr> * vec = region_adjacency_[reg];
00163 
00164     for (unsigned int i =0 ; i < vec->size(); ++i)
00165       if ((*vec)[i] == adj_reg)
00166         return false; //adjacency relation already known
00167 
00168     vec->push_back(adj_reg);
00169   }
00170   else//make a new adjacent region array
00171   {
00172     vcl_vector<sdet_region_sptr>* adj_array = new vcl_vector<sdet_region_sptr>;
00173     adj_array->push_back(adj_reg);
00174     region_adjacency_[reg]=adj_array;
00175   }
00176   return true;
00177 }
00178 
00179 bool
00180 sdet_watershed_region_proc::remove_adjacencies(sdet_region_sptr const& reg)
00181 {
00182   vcl_map<sdet_region_sptr, vcl_vector<sdet_region_sptr>* >::iterator rai;
00183   rai = region_adjacency_.find(reg);
00184   if (rai ==region_adjacency_.end())
00185     return false;
00186   vcl_vector<sdet_region_sptr>* adjacencies = (*rai).second;
00187   region_adjacency_.erase(rai);
00188   delete adjacencies;
00189   return true;
00190 }
00191 
00192 bool sdet_watershed_region_proc::
00193 adjacent_regions(sdet_region_sptr const& reg,
00194                  vcl_vector<sdet_region_sptr>& adj_regs)
00195 {
00196   adj_regs.clear();
00197   vcl_map<sdet_region_sptr, vcl_vector<sdet_region_sptr>* >::iterator rai;
00198   rai = region_adjacency_.find(reg);
00199 
00200   if (rai !=region_adjacency_.end())
00201   {
00202     vcl_vector<sdet_region_sptr> * vec = region_adjacency_[reg];
00203     adj_regs = *vec;
00204     return true;
00205   }
00206   return false;
00207 }
00208 
00209 static bool found_in_regions(sdet_region_sptr const &r,
00210                              vcl_vector<sdet_region_sptr> const & regions)
00211 {
00212   bool found = false;
00213   for (vcl_vector<sdet_region_sptr>::const_iterator rit = regions.begin();
00214        rit != regions.end() && !found; rit++)
00215     if ((*rit).ptr() == r.ptr())
00216       found = true;
00217   return found;
00218 }
00219 
00220 static
00221 void add_new_adjacent_regs(vcl_vector<sdet_region_sptr> const& new_adj_regs,
00222                            vcl_vector<sdet_region_sptr>& adj_regs)
00223 {
00224   for (vcl_vector<sdet_region_sptr>::const_iterator rit = new_adj_regs.begin();
00225        rit != new_adj_regs.end(); rit++)
00226     if (!found_in_regions(*rit, adj_regs))
00227       adj_regs.push_back(*rit);
00228 }
00229 
00230 bool sdet_watershed_region_proc::merge_regions()
00231 {
00232   //sort input on priority type
00233   switch (merge_priority_)
00234   {
00235    case DARK:
00236     vcl_sort(regions_.begin(),
00237              regions_.end(), region_intensity_compare_increasing);
00238     break;
00239    case LIGHT:
00240     vcl_sort(regions_.begin(),
00241              regions_.end(), region_intensity_compare_decreasing);
00242     break;
00243    case SMALL:
00244     vcl_sort(regions_.begin(),
00245              regions_.end(), region_area_compare_increasing);
00246     break;
00247    case BIG:
00248     vcl_sort(regions_.begin(),
00249              regions_.end(), region_area_compare_decreasing);
00250     break;
00251    default:
00252     ;      //don't sort at all
00253   }
00254 
00255   if (verbose_)
00256   {
00257     vcl_cout << "Regions before merge\n";
00258     this->print_region_info();
00259   }
00260 
00261   vcl_vector<sdet_region_sptr> new_regions;
00262   vcl_vector<sdet_region_sptr> merged_regions;
00263   for (vcl_vector<sdet_region_sptr>::iterator rit = regions_.begin();
00264        rit != regions_.end(); rit++)
00265   {
00266     sdet_region_sptr& r = *rit;
00267     if (found_in_regions(r, merged_regions))
00268       continue;
00269     sdet_region_sptr& rm = r; //merged region
00270     vcl_vector<sdet_region_sptr> adj_regs;
00271     if (!adjacent_regions(r, adj_regs))
00272       continue;
00273     bool merged = false;
00274     vcl_vector<sdet_region_sptr> temp_adj;
00275     for (vcl_vector<sdet_region_sptr>::iterator arit = adj_regs.begin();
00276          arit != adj_regs.end(); arit++)
00277     {
00278       sdet_region_sptr& ar = *arit;
00279       if (found_in_regions(ar, merged_regions))
00280         continue;
00281       if (r->Npix()<min_area_ || ar->Npix()<min_area_)
00282         continue;
00283 #ifdef DEBUG
00284       vcl_cout << "R[" << r->label() <<"]:vs:[" << ar->label() << "]\n";
00285 #endif
00286       if (bdgl_region_algs::
00287           earth_mover_distance(r->cast_to_digital_region(),
00288                               ar->cast_to_digital_region()) > merge_tol_)
00289       {
00290         //will potentially be adjacent to the new region
00291         temp_adj.push_back(ar);
00292         continue;
00293       }
00294       //found two mergeable regions
00295       vdgl_digital_region_sptr temp;
00296       if (bdgl_region_algs::merge(rm->cast_to_digital_region(),
00297                                   ar->cast_to_digital_region(), temp))
00298       {
00299         rm = new sdet_region(*temp);
00300         merged = true;
00301         merged_regions.push_back(ar);
00302         //now we must add the regions that are adjacent to ar
00303         //since they are adjacent to the new region
00304         vcl_vector<sdet_region_sptr> new_adj_regs;
00305         if (adjacent_regions(ar, new_adj_regs))
00306           add_new_adjacent_regs(new_adj_regs, temp_adj);
00307       }
00308     }
00309     //declare a new region and update region adjacency map
00310     if (merged)
00311     {
00312       merged_regions.push_back(r);
00313       new_regions.push_back(rm);
00314       this->remove_adjacencies(r);
00315       rm->set_label(++max_label_);
00316 #ifdef DEBUG
00317       vcl_cout << "New Region[" << rm->label() << "](" << rm->Npix()
00318                << ")(Xo: " << rm->Xo() << " Yo: " << rm ->Yo()
00319                << " Io: " << rm ->Io() <<')' << vcl_endl;
00320 #endif
00321       for (vcl_vector<sdet_region_sptr>::iterator arit = temp_adj.begin();
00322            arit != temp_adj.end(); arit++)
00323         this->add_adjacency(rm, *arit);
00324     }
00325   }
00326   if (verbose_)
00327   {
00328     vcl_cout << "# merged regions " << merged_regions.size() << '\n'
00329              << "# new regions " << new_regions.size() << '\n';
00330   }
00331   //remove merged regions from the region_index
00332   vcl_vector<sdet_region_sptr> temp2;
00333   for (vcl_vector<sdet_region_sptr>::iterator rit = regions_.begin();
00334        rit != regions_.end(); rit++)
00335     if (!found_in_regions(*rit, merged_regions))
00336       temp2.push_back(*rit);
00337   //add new regions to region index
00338   for (vcl_vector<sdet_region_sptr>::iterator rit = new_regions.begin();
00339        rit != new_regions.end(); rit++)
00340     temp2.push_back(*rit);
00341   //replace the index
00342   regions_ = temp2;
00343   if (verbose_)
00344   {
00345     vcl_cout << "Regions after merge\n";
00346     this->print_region_info();
00347   }
00348   boundaries_valid_ = false;
00349   return true;
00350 }
00351 
00352 //--------------------------------------------------------------------------
00353 //: extract a set of digital regions
00354 bool sdet_watershed_region_proc::extract_regions()
00355 {
00356   if (regions_valid_)
00357     return true;
00358 
00359   // Check the image
00360   if (!image_)
00361   {
00362     vcl_cout << "In sdet_watershed_region_proc::extract_regions() - no image\n";
00363     return false;
00364   }
00365 
00366   vcl_cout << "sdet_watershed_region_proc::extract_regions(): width = "
00367            << image_.width() << " height = " << image_.height() << vcl_endl;
00368 
00369   //Process the image to extract regions
00370   //for now we assume the image is unsigned char or unsigned short
00371   regions_.clear();
00372 
00373   brip_watershed watershed(wp_);
00374   if (roi_)
00375     watershed.set_image(clip_);
00376   else
00377     watershed.set_image(image_);
00378   if (!watershed.compute_regions())
00379     return false;
00380   overlay_image_ = watershed.overlay_image();
00381   vil1_memory_image_of<vil1_rgb<unsigned char> > color_image =
00382     brip_vil1_float_ops::convert_to_rgb(image_, 0, 255);
00383   if (roi_)
00384     overlay_image_ =
00385       brip_vil1_float_ops::insert_chip_in_image(color_image, overlay_image_, roi_);
00386 
00387 
00388   vbl_array_2d<unsigned int>& lab_array = watershed.region_label_array();
00389   min_label_ = watershed.min_region_label();
00390   max_label_ = watershed.max_region_label();
00391   int n_labs = max_label_ - min_label_ + 1;//number of labels
00392 
00393   //initialize the region array
00394   regions_.resize(n_labs);
00395   for (int n = 0; n<n_labs; n++)
00396   {
00397     regions_[n] = new sdet_region();
00398     regions_[n]->set_label(n+min_label_);
00399   }
00400   //initialize region adjacency
00401   vcl_vector<unsigned int> adj_regs;
00402   for (int n = 0; n<n_labs; n++)
00403   {
00404     unsigned int ln = min_label_ + n;
00405     sdet_region_sptr rn = regions_[n];
00406     if (watershed.adjacent_regions(ln, adj_regs))
00407       for (unsigned int i = 0; i<adj_regs.size(); ++i)
00408         this->add_adjacency(rn, regions_[adj_regs[i]-min_label_]);
00409   }
00410 
00411   //fill the region intensity data
00412   this->scan_region_data(lab_array);
00413 
00414   //sort the regions on intensity (not really needed but good for debugging)
00415   vcl_sort(regions_.begin(),
00416            regions_.end(), region_intensity_compare_increasing);
00417   regions_valid_ = true;
00418   boundaries_valid_ = false;
00419   return true;
00420 }
00421 
00422 //----------------------------------------------------------
00423 //: Clear internal storage
00424 //
00425 void sdet_watershed_region_proc::clear()
00426 {
00427   regions_.clear();
00428 }
00429 
00430 //--------------------------------------------------------------------------
00431 //: Use a linear approximation to intensity to predict region data.
00432 //  Return the residual error
00433 vil1_image sdet_watershed_region_proc::get_residual_image()
00434 {
00435   if (!image_ || !regions_valid_)
00436   {
00437     vcl_cout << "In sdet_watershed_region_proc::get_residual_image() - no regions\n";
00438     return 0;
00439   }
00440   int xsize = image_.width(), ysize = image_.height();
00441   vil1_memory_image_of<unsigned char> res_image(xsize, ysize);
00442   res_image.fill(0);
00443   float min_res = (float)vnl_numeric_traits<unsigned short>::maxval;
00444   for (vcl_vector<sdet_region_sptr>::iterator rit = regions_.begin();
00445        rit != regions_.end(); rit++)
00446     for ((*rit)->reset(); (*rit)->next();)
00447     {
00448       float res = (*rit)->Ir();
00449       if (res<min_res)
00450         min_res = res;
00451     }
00452 
00453   for (vcl_vector<sdet_region_sptr>::iterator rit = regions_.begin();
00454        rit != regions_.end(); rit++)
00455     for ((*rit)->reset(); (*rit)->next();)
00456     {
00457       int x = int((*rit)->X()), y = int((*rit)->Y());
00458       float res = (*rit)->Ir();
00459       float is = res-min_res;//to ensure non-negative
00460       if (is>255)
00461         is = 255;//to ensure within char
00462       unsigned char pix = (unsigned char)is;
00463       res_image(x, y)=pix;
00464     }
00465   return res_image;
00466 }
00467 
00468 void sdet_watershed_region_proc::print_region_info()
00469 {
00470   if (!regions_valid_)
00471     return;
00472   int index = 0;
00473   for (vcl_vector<sdet_region_sptr>::iterator rit = regions_.begin();
00474        rit != regions_.end(); rit++, index++)
00475   {
00476     unsigned int npix = (*rit)->Npix();
00477     if (npix<min_area_)
00478       continue;
00479     vcl_cout << "R[" << (*rit)->label() << "](Np:" << npix << " Io:"
00480              << (*rit)->Io() << " Xo:" << (*rit)->Xo()
00481              << " Yo:" << (*rit)->Yo() << "):sd"<< (*rit)->Io_sd() << vcl_endl;
00482   }
00483 }
00484 
00485 bool sdet_watershed_region_proc::compute_region_image()
00486 {
00487   if (!regions_valid_ || !image_)
00488     return false;
00489   //create the image assume for now everything is unsigned char
00490   int w = image_.width(), h = image_.height();
00491   region_image_.resize(w, h);
00492   region_image_.fill(255);
00493   for (vcl_vector<sdet_region_sptr>::iterator rit = regions_.begin();
00494        rit != regions_.end(); rit++)
00495     for ((*rit)->reset(); (*rit)->next();)
00496     {
00497       int c = int((*rit)->X()), r = int((*rit)->Y());
00498       if (c<0 || r<0 || c>=w || r>=h)
00499         continue;
00500       unsigned char val = (unsigned char)(*rit)->I();
00501       region_image_(c,r) = val;
00502     }
00503   region_image_valid_ = true;
00504   return true;
00505 }
00506 
00507 vil1_image sdet_watershed_region_proc::region_image()
00508 {
00509   vil1_image out;
00510   if (!region_image_valid_)
00511     if (!this->compute_region_image())
00512       return out;
00513   return region_image_;
00514 }
00515 
00516 void sdet_watershed_region_proc::compute_boundaries()
00517 {
00518   for (vcl_vector<sdet_region_sptr>::iterator rit =  regions_.begin();
00519        rit != regions_.end(); rit++)
00520   {
00521     if ((*rit)->Npix()<min_area_)
00522       continue;
00523     if ((*rit)->boundary())
00524       boundaries_.push_back((*rit)->boundary());
00525   }
00526   boundaries_valid_ = true;
00527 }
00528 
00529 vcl_vector<vsol_polygon_2d_sptr> sdet_watershed_region_proc::boundaries()
00530 {
00531   if (!boundaries_valid_)
00532     this->compute_boundaries();
00533   return boundaries_;
00534 }