contrib/brl/bseg/bbgm/bbgm_features.cxx
Go to the documentation of this file.
00001 #include "bbgm_features.h"
00002 //:
00003 // \file
00004 #include <vnl/io/vnl_io_vector_fixed.h>
00005 #include <vgl/vgl_point_2d.h>
00006 #include <vgl/algo/vgl_convex_hull_2d.h>
00007 #include <brip/brip_line_generator.h>
00008 
00009 //===========================================================================
00010 // Methods for mask feature
00011 
00012 //===========================================================================
00013 // mask feature - static member initialization
00014 
00015 unsigned bbgm_mask_feature::uid_ = 0; //initialize unique id counter
00016 
00017 unsigned bbgm_mask_feature::ni() const
00018 {
00019   if (mid_ == brip_rect_mask::ntypes||aid_ == brip_rect_mask::ntypes)
00020     return 0;
00021   brip_rect_mask m(static_cast<brip_rect_mask::mask_id>(mid_));
00022   m.set_angle_id(static_cast<brip_rect_mask::ang_id>(aid_));
00023   return m.ni();
00024 }
00025 
00026 unsigned bbgm_mask_feature::nj() const
00027 {
00028   if (mid_ == brip_rect_mask::ntypes||aid_ == brip_rect_mask::ntypes)
00029     return 0;
00030   brip_rect_mask m(static_cast<brip_rect_mask::mask_id>(mid_));
00031   m.set_angle_id(static_cast<brip_rect_mask::ang_id>(aid_));
00032   return m.nj();
00033 }
00034 
00035 vcl_vector<vgl_point_2d<unsigned short> > bbgm_mask_feature::
00036 pixels(unsigned i, unsigned j)
00037 {
00038   vcl_vector<vgl_point_2d<unsigned short> > pix;
00039   if (mid_ == brip_rect_mask::ntypes||aid_ == brip_rect_mask::ntypes)
00040     return pix;
00041   brip_rect_mask m(static_cast<brip_rect_mask::mask_id>(mid_));
00042   m.set_angle_id(static_cast<brip_rect_mask::ang_id>(aid_));
00043   unsigned ni = m.ni(), nj = m.nj();
00044   int ri = (ni-1)/2, rj = (nj-1)/2;
00045   for (int jj = -rj; jj<=rj; ++jj) {
00046     for (int ii = -ri; ii<=ri; ++ii) {
00047       if (m(ii, jj)>0) {
00048         unsigned short pi = static_cast<unsigned short>(ii+i);
00049         unsigned short pj = static_cast<unsigned short>(jj+j);
00050         if (pi>=320||pj>=180) {
00051           vcl_cout << "Write out of bounds in mask(" << pi << ' ' << pj << ")\n";
00052           continue;
00053         }
00054         pix.push_back(vgl_point_2d<unsigned short>(pi, pj));
00055       }
00056     }
00057   }
00058   return pix;
00059 }
00060 
00061 //: Return a string name
00062 // \note this is probably not portable
00063 
00064 vcl_string bbgm_mask_feature::is_a() const
00065 {
00066   return "bbgm_mask_feature";
00067 }
00068 
00069 
00070 bbgm_mask_feature* bbgm_mask_feature::clone() const
00071 {
00072   return new bbgm_mask_feature(*this);
00073 }
00074 
00075 
00076 //: Return IO version number;
00077 
00078 short bbgm_mask_feature::version() const
00079 {
00080   return 1;
00081 }
00082 
00083 
00084 //: Binary save self to stream.
00085 
00086 void bbgm_mask_feature::b_write(vsl_b_ostream &os) const
00087 {
00088   vsl_b_write(os, version());
00089   vsl_b_write(os, mid_);
00090   vsl_b_write(os, aid_);
00091   vsl_b_write(os, p_);
00092 }
00093 
00094 
00095 //: Binary load self from stream.
00096 void bbgm_mask_feature::b_read(vsl_b_istream &is)
00097 {
00098   if (!is)
00099     return;
00100   short ver;
00101   vsl_b_read(is, ver);
00102   switch (ver)
00103     {
00104     case 1:
00105       vsl_b_read(is, mid_);
00106       vsl_b_read(is, aid_);
00107       vsl_b_read(is, p_);
00108       break;
00109     default:
00110       vcl_cerr << "bbgm_mask_feature: unknown I/O version " << ver << '\n';
00111     }
00112 }
00113 
00114 // public methods
00115 void vsl_b_write(vsl_b_ostream &os, const bbgm_mask_feature& b)
00116 {
00117   b.b_write(os);
00118 }
00119 
00120 //: Binary load bbgm_templ_prob_image
00121 void vsl_b_read(vsl_b_istream &is, bbgm_mask_feature& b)
00122 {
00123   bbgm_mask_feature temp;
00124   temp.b_read(is);
00125   b = temp;
00126 }
00127 
00128 void vsl_print_summary(vcl_ostream& /*os*/, const bbgm_mask_feature & /*b*/)
00129 {
00130   vcl_cerr << "bbgm_mask_feature::vsl_print_summary not implemented\n";
00131 }
00132 
00133 //===========================================================================
00134 // mask pair feature - static member initialization
00135 //===========================================================================
00136 
00137 unsigned bbgm_mask_pair_feature::uid_ = 0; //initialize unique id counter
00138 
00139 
00140 vcl_vector<vgl_point_2d<unsigned short> > bbgm_mask_pair_feature::pixels()
00141 {
00142   vcl_vector<vgl_point_2d<unsigned short> > pixp;
00143   //start of path
00144   float isf = static_cast<float>(i0_), jsf = static_cast<float>(j0_);
00145   // end point of path
00146   float ief = static_cast<float>(i1_), jef = static_cast<float>(j1_);
00147   float lif = 0, ljf = 0; //current point
00148   bool init = true;
00149   while (brip_line_generator::generate(init, isf, jsf, ief, jef,
00150                                        lif, ljf))
00151   {
00152     //cast the line pixel location to unsigned short
00153     unsigned ili = static_cast<unsigned short>(lif),
00154       ilj = static_cast<unsigned short>(ljf);
00155       if (ili>=320||ilj>=180) {
00156         vcl_cout << "Write out of bounds in mask pair(" << ili << ' ' << ilj << ")\n";
00157         continue;
00158       }
00159     pixp.push_back(vgl_point_2d<unsigned short>(ili, ilj));
00160   }
00161   //get the positive elements of masks
00162   bbgm_mask_feature mf0(mid_, ang0_), mf1(mid_, ang1_);
00163   vcl_vector<vgl_point_2d<unsigned short> > pixm0 = mf0.pixels(i0_, j0_);
00164   vcl_vector<vgl_point_2d<unsigned short> > pixm1 = mf0.pixels(i1_, j1_);
00165   vcl_vector<vgl_point_2d<unsigned short> > pix;
00166   for (vcl_vector<vgl_point_2d<unsigned short> >::iterator pit = pixp.begin();
00167        pit!= pixp.end(); ++pit)
00168     pix.push_back(*pit);
00169   //add mask pixels (removing duplicates)
00170   for (vcl_vector<vgl_point_2d<unsigned short> >::iterator pit = pixm0.begin();
00171        pit!= pixm0.end(); ++pit) {
00172     bool found = false;
00173     for (vcl_vector<vgl_point_2d<unsigned short> >::iterator pot = pix.begin();
00174          pot != pix.end()&&!found; ++pot)
00175       if ((*pot)==(*pit)) {
00176         found = true;
00177       }
00178     if (!found) pix.push_back(*pit);
00179   }
00180   for (vcl_vector<vgl_point_2d<unsigned short> >::iterator pit = pixm1.begin();
00181        pit!= pixm1.end(); ++pit) {
00182     bool found = false;
00183     for (vcl_vector<vgl_point_2d<unsigned short> >::iterator pot = pix.begin();
00184          pot != pix.end()&&!found; ++pot)
00185       if ((*pot)==(*pit)) {
00186         found = true;
00187       }
00188     if (!found) pix.push_back(*pit);
00189   }
00190   return pix;
00191 }
00192 
00193 //===========================================================================
00194 // Binary I/O Methods for mask pair feature
00195 
00196 //: Return a string name
00197 // \note this is probably not portable
00198 
00199 vcl_string bbgm_mask_pair_feature::is_a() const
00200 {
00201   return "bbgm_mask_pair_feature";
00202 }
00203 
00204 
00205 bbgm_mask_pair_feature* bbgm_mask_pair_feature::clone() const
00206 {
00207   return new bbgm_mask_pair_feature(*this);
00208 }
00209 
00210 
00211 //: Return IO version number;
00212 
00213 short bbgm_mask_pair_feature::version() const
00214 {
00215   return 1;
00216 }
00217 
00218 
00219 //: Binary save self to stream.
00220 
00221 void bbgm_mask_pair_feature::b_write(vsl_b_ostream &os) const
00222 {
00223   vsl_b_write(os, version());
00224   vsl_b_write(os, static_cast<unsigned>(mid_));
00225   vsl_b_write(os, static_cast<unsigned>(ang0_));
00226   vsl_b_write(os, static_cast<unsigned>(ang1_));
00227   vsl_b_write(os, i0_);
00228   vsl_b_write(os, j0_);
00229   vsl_b_write(os, i1_);
00230   vsl_b_write(os, j1_);
00231   vsl_b_write(os, id0_);
00232   vsl_b_write(os, id1_);
00233   vsl_b_write(os, p_);
00234 }
00235 
00236 
00237 //: Binary load self from stream.
00238 void bbgm_mask_pair_feature::b_read(vsl_b_istream &is)
00239 {
00240   if (!is)
00241     return;
00242   short ver;
00243   vsl_b_read(is, ver);
00244   switch (ver)
00245   {
00246    case 1:
00247     unsigned temp0, temp1, temp2;
00248     vsl_b_read(is, temp0);
00249     vsl_b_read(is, temp1);
00250     vsl_b_read(is, temp2);
00251     vsl_b_read(is, i0_);
00252     vsl_b_read(is, j0_);
00253     vsl_b_read(is, i1_);
00254     vsl_b_read(is, j1_);
00255     vsl_b_read(is, id0_);
00256     vsl_b_read(is, id1_);
00257     vsl_b_read(is, p_);
00258     mid_ = static_cast<brip_rect_mask::mask_id>(temp0);
00259     ang0_ = static_cast<brip_rect_mask::ang_id>(temp1);
00260     ang1_ = static_cast<brip_rect_mask::ang_id>(temp2);
00261     break;
00262    default:
00263     vcl_cerr << "bbgm_mask_pair_feature: unknown I/O version " << ver << '\n';
00264     break;
00265   }
00266 }
00267 
00268 // public methods
00269 void vsl_b_write(vsl_b_ostream &os, const bbgm_mask_pair_feature& b)
00270 {
00271   b.b_write(os);
00272 }
00273 
00274 //: Binary load bbgm_templ_prob_image
00275 void vsl_b_read(vsl_b_istream &is, bbgm_mask_pair_feature& b)
00276 {
00277   bbgm_mask_pair_feature temp;
00278   temp.b_read(is);
00279   b = temp;
00280 }
00281 
00282 void vsl_print_summary(vcl_ostream& /*os*/, const bbgm_mask_pair_feature& /*b*/)
00283 {
00284   vcl_cerr << "bbgm_mask_pair_feature::vsl_print_summary not implemented\n";
00285 }
00286 
00287 
00288 //===========================================================================
00289 // Methods for pair group features
00290 
00291 unsigned bbgm_pair_group_feature::uid_ = 0; //initialize unique id counter
00292 
00293 //constructor from single pair
00294 bbgm_pair_group_feature::
00295 bbgm_pair_group_feature(bbgm_mask_pair_feature const& mp)
00296 {
00297   id_ = mp.id();
00298   mid_ = mp.mask_id();
00299   pairs_.insert(mp);
00300   unsigned short ci, cj;
00301   mp.center(ci, cj);
00302   ci_ = ci; cj_ = cj;
00303   p_ = mp();
00304 }
00305 
00306 //: compute a bounding box for the group based on the vertices
00307 vgl_box_2d<unsigned> bbgm_pair_group_feature::bounding_box() const
00308 {
00309   vgl_box_2d<unsigned> box;
00310   if (!pairs_.size())
00311     return box;
00312   vcl_set<bbgm_mask_pair_feature, fless >::const_iterator vit;
00313   for (vit=pairs_.begin(); vit != pairs_.end(); ++vit)
00314   {
00315     unsigned short ci, cj;
00316     vit->center(ci, cj);
00317     vgl_point_2d<unsigned> p(ci, cj);
00318     box.add(p);
00319   }
00320   return box;
00321 }
00322 
00323 vgl_polygon<double> bbgm_pair_group_feature::convex_hull() const
00324 {
00325   vcl_vector<vgl_point_2d<double> > points;
00326   vcl_set<bbgm_mask_pair_feature, fless >::const_iterator vit;
00327   for (vit=pairs_.begin(); vit != pairs_.end(); ++vit)
00328   {
00329     unsigned short ci, cj;
00330     vit->center(ci, cj);
00331     vgl_point_2d<double> p(ci, cj);
00332     points.push_back(p);
00333   }
00334   if (points.size()<3)
00335     return vgl_polygon<double>();
00336   vgl_convex_hull_2d<double> h(points);
00337 
00338   return h.hull();
00339 }
00340 
00341 vcl_vector<vgl_point_2d<unsigned short> > bbgm_pair_group_feature::pixels()
00342 {
00343   vcl_vector<vgl_point_2d<unsigned short> > pix;
00344   vcl_set<bbgm_mask_pair_feature, fless >::iterator pit = pairs_.begin();
00345   for (; pit!=pairs_.end(); ++pit)
00346   {
00347     bbgm_mask_pair_feature mpf = *pit;
00348     vcl_vector<vgl_point_2d<unsigned short> > pixp = mpf.pixels();
00349     for (vcl_vector<vgl_point_2d<unsigned short> >::iterator pxt = pixp.begin();
00350          pxt!= pixp.end(); ++pxt) {
00351       bool found = false;
00352       for (vcl_vector<vgl_point_2d<unsigned short> >::iterator pot = pix.begin();
00353            pot != pix.end()&&!found; ++pot)
00354         if ((*pot)==(*pxt)) {
00355           found = true;
00356         }
00357       if (!found) pix.push_back(*pxt);
00358     }
00359     //insert the pixels of the star
00360     unsigned short im, jm;
00361     mpf.center(im, jm);
00362     //start of path
00363     float isf = static_cast<float>(ci_), jsf = static_cast<float>(cj_);
00364     // end point of path
00365     float ief = static_cast<float>(im), jef = static_cast<float>(jm);
00366     float lif = 0, ljf = 0; //current point
00367     bool init = true;
00368     while (brip_line_generator::generate(init, isf, jsf, ief, jef,
00369                                          lif, ljf))
00370     {
00371       //cast the line pixel location to unsigned short
00372       unsigned short ili = static_cast<unsigned short>(lif),
00373         ilj = static_cast<unsigned short>(ljf);
00374       vgl_point_2d<unsigned short> pt(ili, ilj);
00375       if (ili>=320||ilj>=180) {
00376         vcl_cout << "Write out of bounds in pair group(" << ili << ' ' << ilj << ")\n";
00377         continue;
00378       }
00379       bool found = false;
00380       for (vcl_vector<vgl_point_2d<unsigned short> >::iterator pot = pix.begin();
00381            pot != pix.end()&&!found; ++pot)
00382         if ((*pot)==pt) {
00383           found = true;
00384         }
00385       if (!found) pix.push_back(pt);
00386     }
00387   }
00388   return pix;
00389 }
00390 
00391 
00392 //: Return a string name
00393 // \note this is probably not portable
00394 
00395 vcl_string bbgm_pair_group_feature::is_a() const
00396 {
00397   return "bbgm_pair_group_feature";
00398 }
00399 
00400 
00401 bbgm_pair_group_feature* bbgm_pair_group_feature::clone() const
00402 {
00403   return new bbgm_pair_group_feature(*this);
00404 }
00405 
00406 
00407 //: Return IO version number;
00408 
00409 short bbgm_pair_group_feature::version() const
00410 {
00411   return 1;
00412 }
00413 
00414 
00415 //: Binary save self to stream.
00416 
00417 void bbgm_pair_group_feature::b_write(vsl_b_ostream &os) const
00418 {
00419   vsl_b_write(os, version());
00420   vsl_b_write(os, static_cast<unsigned>(mid_));
00421   vsl_b_write(os, ci_);
00422   vsl_b_write(os, cj_);
00423   //have to implement explicitly
00424   //since general vsl_set_io doesn't take a predicate.
00425   unsigned n = pairs_.size();
00426   vsl_b_write(os, n);
00427   vcl_set<bbgm_mask_pair_feature, fless>::const_iterator vit;
00428   vit = pairs_.begin();
00429   for (; vit!= pairs_.end(); ++vit)
00430     vsl_b_write(os, *vit);
00431   vsl_b_write(os, p_);
00432 }
00433 
00434 
00435 //: Binary load self from stream.
00436 void bbgm_pair_group_feature::b_read(vsl_b_istream &is)
00437 {
00438   if (!is)
00439     return;
00440   short ver;
00441   vsl_b_read(is, ver);
00442   switch (ver)
00443   {
00444    case 1:
00445     unsigned temp;
00446     vsl_b_read(is, temp);
00447     vsl_b_read(is, ci_);
00448     vsl_b_read(is, cj_);
00449     unsigned n;
00450     vsl_b_read(is, n);
00451     for (unsigned i = 0; i<n; ++i) {
00452       bbgm_mask_pair_feature mpf;
00453       vsl_b_read(is, mpf);
00454       pairs_.insert(mpf);
00455     }
00456     vsl_b_read(is, p_);
00457     mid_ = static_cast<brip_rect_mask::mask_id>(temp);
00458     break;
00459    default:
00460     vcl_cerr << "bbgm_pair_group_feature: unknown I/O version " << ver << '\n';
00461     break;
00462   }
00463 }
00464 
00465 // public methods
00466 void vsl_b_write(vsl_b_ostream &os, const bbgm_pair_group_feature& b)
00467 {
00468   b.b_write(os);
00469 }
00470 
00471 //: Binary load bbgm_templ_prob_image
00472 void vsl_b_read(vsl_b_istream &is, bbgm_pair_group_feature& b)
00473 {
00474   bbgm_pair_group_feature temp;
00475   temp.b_read(is);
00476   b = temp;
00477 }
00478 
00479 void vsl_print_summary(vcl_ostream& /*os*/, const bbgm_pair_group_feature& /*b*/)
00480 {
00481   vcl_cerr << "bbgm_pair_group_feature::vsl_print_summary not implemented\n";
00482 }
00483 
00484 bool pair_intersect(bbgm_mask_pair_feature const& mp0,
00485                     bbgm_mask_pair_feature const& mp1,
00486                     bool plus_intersect_only)
00487 {
00488   // first see if they share a common mask
00489   unsigned id00 = mp0.id0(), id01 = mp0.id1();
00490   unsigned id10 = mp1.id0(), id11 = mp1.id1();
00491   if (id00==id10||id00==id11||id01==id00||id01==id11)
00492     return true;
00493   //check if the masks have intersecting positive elements
00494   brip_rect_mask::mask_id mid = mp0.mask_id();
00495   brip_rect_mask::ang_id ang00 = mp0.ang0();
00496   brip_rect_mask::ang_id ang01 = mp0.ang1();
00497   brip_rect_mask::ang_id ang10 = mp1.ang0();
00498   brip_rect_mask::ang_id ang11 = mp1.ang1();
00499   unsigned short i00, j00, i01, j01, i10, j10, i11, j11;
00500   mp0.x0(i00, j00);   mp0.x1(i01, j01);
00501   mp1.x0(i10, j10);   mp1.x1(i11, j11);
00502   if (plus_intersect_only) {
00503     if (brip_rect_mask::intersect(mid, ang00, i00, j00, ang10, i10, j10))
00504       return true;
00505     if (brip_rect_mask::intersect(mid, ang00, i00, j00, ang11, i11, j11))
00506       return true;
00507     if (brip_rect_mask::intersect(mid, ang01, i01, j01, ang10, i10, j10))
00508       return true;
00509     if (brip_rect_mask::intersect(mid, ang01, i01, j01, ang11, i11, j11))
00510       return true;
00511   }
00512   else {
00513     if (brip_rect_mask::intersect_domain(mid, ang00, i00, j00, ang10, i10, j10))
00514       return true;
00515     if (brip_rect_mask::intersect_domain(mid, ang00, i00, j00, ang11, i11, j11))
00516       return true;
00517     if (brip_rect_mask::intersect_domain(mid, ang01, i01, j01, ang10, i10, j10))
00518       return true;
00519     if (brip_rect_mask::intersect_domain(mid, ang01, i01, j01, ang11, i11, j11))
00520       return true;
00521   }
00522   return false;
00523 }
00524 
00525 bbgm_pair_group_feature pair_group_merge(bbgm_pair_group_feature const& pg0,
00526                                          bbgm_pair_group_feature const& pg1,
00527                                          float p_path)
00528 {
00529   //collect the vertices
00530   const vcl_set<bbgm_mask_pair_feature, fless>& pairs0 =
00531     pg0.pairs();
00532   double pr0 = pg0();
00533 
00534   const vcl_set<bbgm_mask_pair_feature, fless>& pairs1 = pg1.pairs();
00535   double pr1 = pg1();
00536 
00537   vcl_set<bbgm_mask_pair_feature, fless> merged_verts;
00538 
00539   vcl_set<bbgm_mask_pair_feature, fless>::const_iterator pit;
00540 
00541   for (pit = pairs0.begin(); pit != pairs0.end(); ++pit)
00542     merged_verts.insert(*pit);
00543 
00544   for (pit = pairs1.begin(); pit != pairs1.end(); ++pit)
00545     merged_verts.insert(*pit);
00546   double np = merged_verts.size();
00547   if (np==0) return pg0;
00548   double dp = vcl_pow(pr0, (np-1.0)/np);
00549   dp *= vcl_pow(pr1, 1.0/np);
00550   float p = static_cast<float>(dp)*p_path;
00551   bbgm_pair_group_feature pgm;
00552   pgm.set_prob(merged_verts, p);
00553   return pgm;
00554 }
00555 
00556 bbgm_pair_group_feature
00557 pair_group_max_union(bbgm_pair_group_feature const& pg0,
00558                      bbgm_pair_group_feature const& pg1)
00559 {
00560   //collect the mask pairs in each group
00561   const vcl_set<bbgm_mask_pair_feature, fless>& pairs0 = pg0.pairs();
00562 
00563   const vcl_set<bbgm_mask_pair_feature, fless>& pairs1 = pg1.pairs();
00564 
00565   //the pairs in the union
00566   vcl_set<bbgm_mask_pair_feature, fless> merged_verts;
00567 
00568   vcl_set<bbgm_mask_pair_feature, fless>::const_iterator pit;
00569 
00570   float pmax = 0.0f;
00571   for (pit = pairs0.begin(); pit != pairs0.end(); ++pit) {
00572     merged_verts.insert(*pit);
00573     if ((*pit)()>pmax)
00574       pmax = (*pit)();
00575   }
00576   for (pit = pairs1.begin(); pit != pairs1.end(); ++pit) {
00577     merged_verts.insert(*pit);
00578     if ((*pit)()>pmax)
00579       pmax = (*pit)();
00580   }
00581   bbgm_pair_group_feature pgm;
00582   pgm.set_prob(merged_verts, pmax);
00583   return pgm;
00584 }