contrib/gel/vifa/vifa_int_face_attr_common.cxx
Go to the documentation of this file.
00001 // This is gel/vifa/vifa_int_face_attr_common.cxx
00002 #include "vifa_int_face_attr_common.h"
00003 //:
00004 // \file
00005 
00006 #include <vdgl/vdgl_fit_lines.h>
00007 #include <vtol/vtol_intensity_face.h>
00008 #include <vgl/vgl_point_2d.h>
00009 #include <vsol/vsol_line_2d.h>
00010 #include <vtol/vtol_vertex_sptr.h>
00011 #include <vifa/vifa_group_pgram.h>
00012 #include <vcl_cmath.h> // fabs()
00013 
00014 vifa_int_face_attr_common::
00015 vifa_int_face_attr_common(vdgl_fit_lines_params*    fitter_params,
00016                           vifa_group_pgram_params*  gpp_s,
00017                           vifa_group_pgram_params*  gpp_w,
00018                           vifa_coll_lines_params*   cpp,
00019                           vifa_norm_params*         np) :
00020   vifa_int_face_attr_common_params(fitter_params, gpp_s, gpp_w, cpp, np)
00021 {
00022   this->init();
00023 }
00024 
00025 vifa_int_face_attr_common::~vifa_int_face_attr_common()
00026 {
00027 }
00028 
00029 
00030 // ------------------------------------------------------------
00031 // Data access & computation for non-attributes
00032 //
00033 
00034 
00035 edge_2d_list& vifa_int_face_attr_common::
00036 GetFittedEdges()
00037 {
00038   if (!fitted_edges_.size())
00039     this->fit_lines();
00040 
00041   return fitted_edges_;
00042 }
00043 
00044 coll_list& vifa_int_face_attr_common::
00045 get_collinear_lines()
00046 {
00047   if (!cpp_)
00048     cpp_ = new vifa_coll_lines_params;
00049 
00050   if (!collinear_lines_.size())
00051     this->find_collinear_lines();
00052 
00053   return collinear_lines_;
00054 }
00055 
00056 double vifa_int_face_attr_common::
00057 col_collapse()
00058 {
00059   double  collapsed_count = 0;
00060   double  total_count = 0;
00061 
00062   for (coll_iterator c = collinear_lines_.begin();
00063        c != collinear_lines_.end(); ++c)
00064   {
00065     total_count++;
00066 
00067     if ((*c)->get_discard_flag())
00068       collapsed_count++;
00069   }
00070 
00071   if (total_count == 0)
00072     return 0;
00073 
00074   return collapsed_count / total_count;
00075 }
00076 
00077 double vifa_int_face_attr_common::
00078 get_contrast_across_edge(vtol_edge_sptr  e, double dflt_cont)
00079 {
00080   double    cont = dflt_cont;
00081   face_list faces; e->faces(faces);
00082 
00083   // Expect only one or two intensity faces for 2-D case
00084   if (faces.size() == 2)
00085   {
00086     vtol_intensity_face*  f1 = faces[0]->cast_to_intensity_face();
00087     vtol_intensity_face*  f2 = faces[1]->cast_to_intensity_face();
00088 
00089     if (f1 && f2)
00090       cont = vcl_fabs(f1->Io() - f2->Io());
00091   }
00092   return cont;
00093 }
00094 
00095 vifa_coll_lines_sptr vifa_int_face_attr_common::
00096 get_line_along_edge(vtol_edge* edge)
00097 {
00098   vifa_coll_lines_sptr  ret(0);
00099   vtol_vertex_sptr    ev1 = edge->v1();
00100   vtol_vertex_sptr    ev2 = edge->v2();
00101 
00102   for (coll_iterator c = collinear_lines_.begin();
00103        c != collinear_lines_.end(); ++c)
00104   {
00105     edge_2d_list&  c_edges = (*c)->get_contributors();
00106 
00107     for (edge_2d_iterator e = c_edges.begin(); e != c_edges.end(); ++e)
00108     {
00109       vtol_vertex_sptr  v1 = (*e)->v1();
00110       vtol_vertex_sptr  v2 = (*e)->v2();
00111 
00112       if (((*ev1 == *v1) && (*ev2 == *v2)) ||
00113           ((*ev1 == *v2) && (*ev2 == *v1)))
00114         ret = *c;
00115     }
00116   }
00117 
00118   return ret;
00119 }
00120 
00121 
00122 // ------------------------------------------------------------
00123 // Individual attribute computation
00124 //
00125 
00126 
00127 // Compute measure of projective parallelism, ratio of edges that have some
00128 // projective overlap to total edge length.  Computes fitted_edges_ if needed.
00129 float vifa_int_face_attr_common::
00130 StrongParallelSal()
00131 {
00132   if (para_sal_strong_ < 0)
00133   {
00134     if (!gpp_s_.ptr())
00135     {
00136       const float  angle_increment = 5.f;
00137       gpp_s_ = new vifa_group_pgram_params(angle_increment);
00138     }
00139 
00140     para_sal_strong_ = this->compute_parallel_sal(gpp_s_);
00141   }
00142 
00143   return para_sal_strong_;
00144 }
00145 
00146 float vifa_int_face_attr_common::
00147 WeakParallelSal()
00148 {
00149   if (para_sal_weak_ < 0)
00150   {
00151     if (!gpp_w_.ptr())
00152     {
00153       const float  angle_increment = 20.f;
00154       gpp_w_ = new vifa_group_pgram_params(angle_increment);
00155     }
00156 
00157     para_sal_weak_ = this->compute_parallel_sal(gpp_w_);
00158   }
00159 
00160   return para_sal_weak_;
00161 }
00162 
00163 
00164 // ------------------------------------------------------------
00165 // Protected methods
00166 //
00167 
00168 
00169 void vifa_int_face_attr_common::
00170 init()
00171 {
00172   attributes_valid_    = false;
00173   complexity_        = -1;
00174   weighted_complexity_  = -1;
00175   aspect_ratio_      = -1;
00176   peri_length_      = -1;
00177   weighted_peri_length_  = -1;
00178   para_sal_weak_      = -1;
00179   para_sal_strong_    = -1;
00180 }
00181 
00182 // Fit edges of face_ with straight lines, but only if cached versions
00183 // are not available.  Sets fitter_params_ with defaults if empty.
00184 // Results are added to fitted_edges_.
00185 void vifa_int_face_attr_common::
00186 fit_lines()
00187 {
00188   edge_2d_list  edges_in_vect = this->GetEdges();
00189 
00190 #ifdef DEBUG
00191     vcl_cout << "ifac::fit_lines(): " << edges_in_vect.size()
00192              << " edges available\n";
00193 #endif
00194 
00195   if (!edges_in_vect.size())
00196   {
00197     vcl_cerr << "vifa_int_face_attr_common::fit_lines: face_ is not set\n";
00198     return;
00199   }
00200 
00201   vcl_vector<vdgl_digital_curve_sptr>  curves_in;
00202   for (edge_2d_iterator ei = edges_in_vect.begin();
00203        ei != edges_in_vect.end(); ei++)
00204   {
00205     vsol_curve_2d_sptr c = (*ei)->curve();
00206     vdgl_digital_curve_sptr dc = c->cast_to_vdgl_digital_curve();
00207     if (!dc)
00208       continue;
00209     curves_in.push_back(dc);
00210   }
00211 
00212   if (!fitter_params_.ptr())
00213   {
00214     const int  fit_length = 6;
00215     fitter_params_ = new vdgl_fit_lines_params(fit_length);
00216   }
00217 
00218   // Call the line fitting routine (thanks Joe!)
00219   vdgl_fit_lines  fitter(*(fitter_params_.ptr()));
00220   fitter.set_curves(curves_in);
00221   vcl_vector<vsol_line_2d_sptr>&  segs = fitter.get_line_segs();
00222 
00223 #ifdef DEBUG
00224     vcl_cout << "ifac::fit_lines(): " << segs.size() << " segments from fitter\n";
00225 #endif
00226 
00227   // Convert fitter output to edges & update statistics
00228   vcl_vector<vsol_line_2d_sptr>::iterator  segi = segs.begin();
00229   for (; segi != segs.end(); segi++)
00230   {
00231     vsol_line_2d_sptr  seg = *segi;
00232     vtol_vertex_2d_sptr  v1 = new vtol_vertex_2d(*(seg->p0()));
00233     vtol_vertex_2d_sptr  v2 = new vtol_vertex_2d(*(seg->p1()));
00234     vtol_edge_2d_sptr  e = new vtol_edge_2d(v1, v2);
00235     fitted_edges_.push_back(e);
00236 
00237     // Update statistics
00238     fitted_edges_stats_.add_sample(seg->length());
00239   }
00240 }
00241 
00242 void vifa_int_face_attr_common::
00243 find_collinear_lines()
00244 {
00245   // sort fitted edges by length into f_edges
00246   edge_2d_list  unsorted_edges = this->GetFittedEdges();
00247   edge_2d_list  f_edges;
00248   for (edge_2d_iterator e = unsorted_edges.begin();
00249        e != unsorted_edges.end(); ++e)
00250   {
00251     double        len = (*e)->curve()->length();
00252     edge_2d_iterator  slot = f_edges.begin();
00253     for (; slot != f_edges.end(); ++slot)
00254       if ((*slot)->curve()->length() < len)
00255       {
00256         f_edges.insert(slot, *e);
00257         break;
00258       }
00259   }
00260 
00261   // build up a list of collinear line buckets
00262   coll_list    unfiltered_lines;
00263   coll_iterator  match;
00264 
00265 #ifdef DEBUG
00266   vcl_cout << "Collineating: ";
00267 #endif
00268   for (edge_2d_iterator e = f_edges.begin(); e != f_edges.end(); ++e)
00269   {
00270 #ifdef DEBUG
00271     vcl_cout << '.';
00272 #endif
00273 
00274     if ((*e)->curve()->length() == 0)
00275       continue;
00276 
00277     bool  match_flag = find_collinear_match(*e,
00278                                             unfiltered_lines,
00279                                             cpp_->midpt_distance(),
00280                                             match);
00281 
00282     if (!match_flag)
00283     {
00284       vifa_coll_lines_sptr  cl(new vifa_coll_lines(*e, cpp_->angle_tolerance()));
00285 
00286       unfiltered_lines.push_back(cl);
00287     }
00288     else
00289       (*match)->add_and_update(*e);
00290   }
00291 
00292 #ifdef DEBUG
00293   vcl_cout << vcl_endl;
00294 #endif
00295 
00296   // remove lines whose support is too low
00297   for (coll_iterator c = unfiltered_lines.begin();
00298        c != unfiltered_lines.end(); ++c)
00299   {
00300     double  span = (*c)->spanning_length();
00301     double  support = (*c)->support_length();
00302 
00303     if ((support/span) >= cpp_->discard_threshold())
00304     {
00305       collinear_lines_.push_back(*c);
00306       col_span_.add_sample(span);
00307       col_support_.add_sample(support);
00308       col_contrib_.add_sample((*c)->get_contributors().size());
00309     }
00310     else
00311     {
00312       // Unwind the unsupported line
00313       edge_2d_list&  contrib = (*c)->get_contributors();
00314       for (edge_2d_iterator e = contrib.begin(); e != contrib.end(); ++e)
00315       {
00316         vifa_coll_lines_sptr  cl(new vifa_coll_lines(*e,
00317                                                      cpp_->angle_tolerance(),
00318                                                      cpp_->endpt_distance(),
00319                                                      true));
00320 
00321         collinear_lines_.push_back(cl);
00322 
00323         double  span = cl->spanning_length();
00324         double  support = cl->support_length();
00325 
00326         col_span_.add_sample(span);
00327         col_support_.add_sample(support);
00328         col_contrib_.add_sample(cl->get_contributors().size());
00329       }
00330     }
00331   }
00332 
00333 #ifdef DEBUG
00334   vcl_cout << unfiltered_lines.size() << " raw collinear lines; "
00335            << collinear_lines_.size() << " lines above discard threshold "
00336            << cpp_->discard_threshold_ << vcl_endl;
00337 #endif
00338 }
00339 
00340 bool vifa_int_face_attr_common::
00341 find_collinear_match(vtol_edge_2d_sptr edge,
00342                      coll_list&        lines,
00343                      double            dist_threshold,
00344                      coll_iterator&    result)
00345 {
00346   double      min_dist = dist_threshold;
00347   coll_iterator  match = lines.end();
00348   for (coll_iterator c = lines.begin(); c != lines.end(); ++c)
00349   {
00350     double  dist = (*c)->get_measure(edge);
00351     if ((dist < dist_threshold) && (dist < min_dist))
00352     {
00353       min_dist = dist;
00354       match = c;
00355     }
00356   }
00357 
00358   if (match == lines.end())
00359   {
00360     return false;
00361   }
00362 
00363   result = match;
00364   return true;
00365 }
00366 
00367 float vifa_int_face_attr_common::
00368 compute_parallel_sal(vifa_group_pgram_params_sptr  gpp)
00369 {
00370   float      sal = 0.f;
00371   edge_2d_list  fedges = this->GetFittedEdges();
00372 
00373 #ifdef DEBUG
00374   vcl_cout << "ifac::compute_parallel_sal(): " << fedges.size()
00375            << " edges found\n";
00376 #endif
00377 
00378   if (fedges.size())
00379   {
00380 #ifdef DEBUG
00381     vcl_cout << (*fitter_params_);
00382 #endif
00383 
00384     float    total_len = 0.f;
00385     int      nlines = 0;
00386     imp_line_list    lg_filtered;
00387     for (edge_2d_iterator ei = fedges.begin(); ei != fedges.end(); ++ei)
00388     {
00389       vsol_curve_2d_sptr  cur = (*ei)->curve();
00390       float        len = float(cur->length());
00391       total_len += len;
00392 
00393       if (len >= fitter_params_->min_fit_length_)
00394       {
00395         const vgl_point_2d<double>&  p1 = cur->p0()->get_p();
00396         const vgl_point_2d<double>&  p2 = cur->p1()->get_p();
00397         imp_line_sptr        filt_line  = new imp_line(p1, p2);
00398 
00399         lg_filtered.push_back(filt_line);
00400         nlines++;
00401       }
00402     }
00403 
00404 #ifdef DEBUG
00405     vcl_cout << "ifac::compute_parallel_sal(): " << nlines
00406              << " lines after filtering, total_len = " << total_len << vcl_endl;
00407 #endif
00408 
00409     // compute the score for the set of fitted lines
00410     if (nlines > 2)
00411     {
00412       // Insert the lines into the parallellogram orientation index
00413       vifa_group_pgram  gp(lg_filtered, *gpp);
00414       gp.SetTemp1(total_len);
00415 
00416       // Get the resultant value
00417       sal = float(gp.norm_parallel_line_length());
00418     }
00419   }
00420 
00421   return sal;
00422 }