contrib/gel/vifa/vifa_int_faces_attr.cxx
Go to the documentation of this file.
00001 // This is gel/vifa/vifa_int_faces_attr.cxx
00002 #include "vifa_int_faces_attr.h"
00003 //:
00004 // \file
00005 #include <vcl_algorithm.h>
00006 #include <vcl_cmath.h>
00007 #include <vcl_map.h>
00008 #include <vcl_utility.h>
00009 #include <vtol/vtol_edge.h>
00010 #include <vifa/vifa_incr_var.h>
00011 #include <vifa/vifa_parallel.h>
00012 
00013 
00014 // Establish the attribute vector for histogrammed attributes.  These
00015 // are vifa_int_face_attr methods to get an attribute val for one face.  Each
00016 // attribute type is histogrammed in this class.  Length must be
00017 // NUM_HIST_ATTRIBUTES.
00018 AttrFuncPtr vifa_int_faces_attr::
00019 attr_get_funcs[] =
00020 {
00021   &vifa_int_face_attr::IntMax,    // region intensity maxima
00022   &vifa_int_face_attr::IntMin,    // region intensity minima
00023   &vifa_int_face_attr::IntMean,    // region intensities
00024   &vifa_int_face_attr::IntVar,    // region intensity variances
00025   &vifa_int_face_attr::Area,      // region area
00026   &vifa_int_face_attr::AspectRatio,
00027   &vifa_int_face_attr::PerimeterLength,
00028   &vifa_int_face_attr::WeightedPerimeterLength,
00029   &vifa_int_face_attr::Complexity,
00030   &vifa_int_face_attr::WeightedComplexity,
00031   &vifa_int_face_attr_common::StrongParallelSal,
00032   &vifa_int_face_attr_common::WeakParallelSal,
00033   &vifa_int_face_attr::TwoPeakParallel,
00034   &vifa_int_face_attr::FourPeakParallel,
00035   &vifa_int_face_attr::EightyPercentParallel
00036 };
00037 
00038 const char* const vifa_int_faces_attr::
00039 attr_names[] =
00040 {
00041   "IntMax",
00042   "IntMin",
00043   "IntMean",
00044   "IntVar",
00045   "Area",
00046   "AspectRatio",
00047   "PerimeterLength",
00048   "WeightedPerimeterLength",
00049   "Complexity",
00050   "WeightedComplexity",
00051   "StrongParallel",
00052   "WeakParallel",
00053   "TwoPeakParallel",
00054   "FourPeakParallel",
00055   "EightyPercentParallel"
00056 };
00057 
00058 // Set some minimum values
00059 
00060 float vifa_int_faces_attr::
00061 attr_min_vals[] = {
00062   0.0039f,      // 1/255
00063   0.0039f,
00064   0.0039f,
00065   0.0001f,      //... not sure what the minimum variance should be
00066   1.0f,         // min area
00067   1.0f,         // min aspect ratio
00068   1.0f,         // min perimeter
00069   1.0f,         // min weighted perimeter
00070   1.0f,         // min complexity
00071   1.0f,         // min weighted complexity
00072   0.05f,        // min strong parallel
00073   0.05f,        // min weak parallel
00074   1e-5f,
00075   1e-5f,
00076   1e-5f
00077 };
00078 
00079 void vifa_int_faces_attr::
00080 init()
00081 {
00082   centroid_.reserve(2);
00083   centroid_[0] = -1;
00084   centroid_[1] = -1;
00085   perimeter_ = -1;
00086   weighted_perimeter_ = -1;
00087   // attr_map_ is allocated in ComputeSingleFaceAttributes.
00088 
00089   cached_2_parallel_ = -1;
00090   cached_4_parallel_ = -1;
00091   cached_80_parallel_ = -1;
00092 
00093   npobj_ = 0;
00094 
00095   attr_vec_.reserve(NumHistAttributes());
00096   for (int i=0; i < NumHistAttributes(); i++)
00097   {
00098     // can't do it below; garbage values trap in unref
00099     attr_vec_.push_back(NULL);
00100   }
00101 
00102   perimeter_ = -1.f;
00103 }
00104 
00105 vifa_int_faces_attr::
00106 vifa_int_faces_attr(vdgl_fit_lines_params*    fitter_params,
00107                     vifa_group_pgram_params*  gpp_s,
00108                     vifa_group_pgram_params*  gpp_w,
00109                     vifa_coll_lines_params*    cpp,
00110                     vifa_norm_params*      np,
00111                     vifa_int_face_attr_factory*  factory)
00112   : vifa_int_face_attr_common(fitter_params, gpp_s, gpp_w, cpp, np)
00113 {
00114   this->init();
00115   factory_ = factory;
00116 }
00117 
00118 vifa_int_faces_attr::
00119 vifa_int_faces_attr(iface_list&          v,
00120                     vdgl_fit_lines_params*      fitter_params,
00121                     vifa_group_pgram_params*    gpp_s,
00122                     vifa_group_pgram_params*    gpp_w,
00123                     vifa_coll_lines_params*     cpp,
00124                     vifa_norm_params*           np,
00125                     vifa_int_face_attr_factory* factory)
00126   : vifa_int_face_attr_common(fitter_params, gpp_s, gpp_w, cpp, np),
00127     faces_(v)
00128 {
00129   this->init();
00130   factory_ = factory;
00131   attributes_valid_ = this->ComputeAttributes();
00132 }
00133 
00134 vifa_int_faces_attr::
00135 ~vifa_int_faces_attr()
00136 {
00137   delete npobj_;
00138 }
00139 
00140 // ----------------------------------------------------------------
00141 // Data access for non-attributes
00142 // ---
00143 
00144 
00145 float vifa_int_faces_attr::
00146 CallAttrFunction(vifa_int_face_attr* seed_attr,int i)
00147 {
00148   return (seed_attr->*(attr_get_funcs[i]))();
00149 }
00150 
00151 void vifa_int_faces_attr::
00152 SetFaces(iface_list& v)
00153 {
00154   // Save the new faces
00155   faces_ = v;
00156 
00157   // Reset everything
00158   delete npobj_;
00159   this->init();
00160 
00161   // Recompute the attributes
00162   attributes_valid_ = this->ComputeAttributes();
00163 }
00164 
00165 edge_2d_list& vifa_int_faces_attr::
00166 GetEdges()
00167 {
00168   // don't compute again if already there
00169   if (!edges_.empty())
00170     return edges_;
00171 
00172   if (faces_.empty())
00173   {
00174     vcl_cerr << "vifa_int_faces_attr::GetEdges: faces_ is not set\n";
00175     return edges_;
00176   }
00177 
00178   // Get edges from all faces, remove duplicates
00179   for (iface_iterator f = faces_.begin(); f != faces_.end(); ++f)
00180   {
00181     edge_list fedges; (*f)->edges(fedges);
00182     edge_2d_iterator  edges_pos_;
00183     for (edge_iterator ei = fedges.begin(); ei != fedges.end(); ei++)
00184     {
00185       vtol_edge_2d*  e_ptr = (*ei)->cast_to_edge_2d();
00186 
00187       if (e_ptr)
00188       {
00189         vtol_edge_2d_sptr  e = vtol_edge_2d_sptr(e_ptr);
00190 
00191         edges_pos_ = vcl_find(edges_.begin(), edges_.end(), e);
00192         if (edges_pos_ == edges_.end())
00193           edges_.push_back(e);
00194       }
00195     }
00196   }
00197 
00198   return edges_;
00199 }
00200 
00201 
00202 // Compute centroid as the area-weighted mean of face centroids
00203 // (center of mass).
00204 void vifa_int_faces_attr::
00205 ComputeCentroid()
00206 {
00207   if ((centroid_[0] < 0) && !attr_map_.empty())
00208   {
00209     float  area_sum = 0;
00210     float  x_area_sum = 0;
00211     float  y_area_sum = 0;
00212 
00213     for (attr_iterator ai = attr_map_.begin();
00214          ai != attr_map_.end(); ++ai)
00215     {
00216       float  area = (*ai)->Area();
00217       area_sum += area;
00218       x_area_sum += area * (*ai)->Xo();
00219       y_area_sum += area * (*ai)->Yo();
00220     }
00221 
00222     if (!area_sum)
00223       return;
00224 
00225     centroid_[0] = x_area_sum / area_sum;
00226     centroid_[1] = y_area_sum / area_sum;
00227   }
00228 }
00229 
00230 // Compute X coord of centroid of all regions
00231 float vifa_int_faces_attr::
00232 Xo()
00233 {
00234   if ((centroid_[0] < 0) && !attr_map_.empty())
00235     this->ComputeCentroid();
00236 
00237   return centroid_[0];
00238 }
00239 
00240 // Compute Y coord of centroid of all regions
00241 float vifa_int_faces_attr::
00242 Yo()
00243 {
00244   if ((centroid_[1] < 0) && !attr_map_.empty())
00245     this->ComputeCentroid();
00246 
00247   return centroid_[1];
00248 }
00249 
00250 // ------------------------------------------------------------
00251 // Attribute computation
00252 //
00253 
00254 // Compute single-face attributes (vifa_int_face_attr objects) for each
00255 // individual face.
00256 bool vifa_int_faces_attr::
00257 ComputeSingleFaceAttributes(bool forceP)
00258 {
00259   if (!forceP && attributes_valid_)
00260     return true;
00261 
00262   attr_map_.clear();
00263   for (iface_iterator f = faces_.begin(); f != faces_.end(); ++f)
00264   {
00265     vifa_int_face_attr_sptr fattr = factory_new_attr(*f);
00266 
00267     if (!(fattr->valid_p()))
00268       return false;
00269 
00270     attr_map_.push_back(fattr);
00271   }
00272 
00273   return true;
00274 }
00275 
00276 bool vifa_int_faces_attr::
00277 ComputeAttributes()
00278 {
00279   if (!this->ComputeSingleFaceAttributes(true))
00280     attributes_valid_ = false;
00281   else
00282   {
00283     // Compute histogrammed attributes, including generation of
00284     // histograms
00285     for (int i = 0; i < NumHistAttributes(); i++)
00286       this->GetMeanAttr(i);
00287 
00288     attributes_valid_ = true;
00289   }
00290 
00291   return valid_p();
00292 }
00293 
00294 // Populate a vector containing all attributes, including inherited ones.
00295 bool vifa_int_faces_attr::
00296 GetAttributes(vcl_vector<float>& attrs)
00297 {
00298   // No inherited attributes. The class qualifier is necessary to
00299   // prevent this call from going to children that define this method
00300   // also.
00301   return this->vifa_int_faces_attr::GetNativeAttributes(attrs);
00302 }
00303 
00304 // Populate a vector containing attributes native to this class (not
00305 // inherited).
00306 bool vifa_int_faces_attr::
00307 GetNativeAttributes(vcl_vector<float>& attrs)
00308 {
00309   if (!this->ComputeAttributes())
00310   {
00311     vcl_cerr << "Couldn't compute group attributes?\n";
00312     return false;
00313   }
00314 
00315   attrs.push_back(this->Area());
00316   attrs.push_back(this->PerimeterLength());
00317   attrs.push_back(this->WeightedPerimeterLength());
00318   attrs.push_back(this->Complexity());
00319   attrs.push_back(this->WeightedComplexity());
00320   attrs.push_back(this->StrongParallelSal());
00321   attrs.push_back(this->WeakParallelSal());
00322   attrs.push_back(this->TwoPeakParallel());
00323   attrs.push_back(this->FourPeakParallel());
00324   attrs.push_back(this->EightyPercentParallel());
00325 
00326   for (int i = 0; i < this->NumHistAttributes(); i++)
00327     attrs.push_back(this->GetMeanAttr(i));
00328 
00329   for (int i = 0; i < this->NumHistAttributes(); i++)
00330     attrs.push_back(this->GetSDAttr(i));
00331 
00332   return true;
00333 }
00334 
00335 // KEEP IN SYNC WITH GETNATIVEATTRIBUTES
00336 
00337 void vifa_int_faces_attr::
00338 GetAttributeNames(vcl_vector<vcl_string>& names)
00339 {
00340   names.push_back("gArea");
00341   names.push_back("gPerimeterLength");
00342   names.push_back("gWeightedPerimeterLength");
00343   names.push_back("gComplexity");
00344   names.push_back("gWeightedComplexity");
00345   names.push_back("gStrongParallel");
00346   names.push_back("gWeakParallel");
00347   names.push_back("gTwoPeakParallel");
00348   names.push_back("gFourPeakParallel");
00349   names.push_back("gEightyPercentParallel");
00350 
00351   for (int i = 0; i < NUM_HIST_ATTRIBUTES; i++)
00352   {
00353     vcl_string  name(attr_names[i]);
00354     names.push_back("mean" + name);
00355   }
00356 
00357   for (int i = 0; i < NUM_HIST_ATTRIBUTES; i++)
00358   {
00359     vcl_string  name(attr_names[i]);
00360     names.push_back("sd" + name);
00361   }
00362 }
00363 
00364 const char* vifa_int_faces_attr::
00365 GetBaseAttrName(int i)
00366 {
00367   return vifa_int_faces_attr::attr_names[i];
00368 }
00369 
00370 
00371 // Create a histogram of attribute values from the supplied list of
00372 // values.  This histogram must be deleted by the caller when done!
00373 vifa_histogram_sptr vifa_int_faces_attr::
00374 MakeAttrHist(vcl_vector<float>& attr_vals)
00375 {
00376   this->ComputeSingleFaceAttributes(false);
00377 
00378   // Set the number of bins as sqrt(n), with a minimum of 20
00379   int    num_bins = vcl_max(20, (int)vcl_sqrt( static_cast<float>(attr_vals.size()) ));
00380 
00381   // Get value range
00382   float  max_val = 0;
00383   float  min_val = 1000000;
00384   for (vcl_vector<float>::iterator vali = attr_vals.begin();
00385        vali != attr_vals.end(); ++vali)
00386   {
00387     float val = *vali;
00388 
00389     if (val > max_val)
00390       max_val = val;
00391 
00392     if (val < min_val)
00393       min_val = val;
00394   }
00395 
00396   // Create empty histogram
00397   vifa_histogram_sptr val_hist = new vifa_histogram(num_bins,
00398                                                     min_val,
00399                                                     max_val);
00400 
00401   // Populate histogram
00402   for (vcl_vector<float>::iterator vali = attr_vals.begin();
00403        vali != attr_vals.end(); ++vali)
00404     val_hist->UpCount(*vali);
00405 
00406   return val_hist;
00407 }
00408 
00409 // Get or compute mean value of a vifa_int_face_attr attribute.  Computes
00410 // histogram if necessary.  Not weighted by area.
00411 float vifa_int_faces_attr::
00412 GetMeanAttr(int attr_index)
00413 {
00414   if (!attr_map_.empty())
00415   {
00416     if (!(attr_vec_[attr_index].ptr()))
00417     {
00418       attr_vec_[attr_index] = new vifa_incr_var;
00419 
00420       // Create list of attr vals and attr histogram
00421       vcl_vector<float>  vals(attr_map_.size());
00422       int          index = 0;
00423       for (attr_iterator ai = attr_map_.begin();
00424            ai != attr_map_.end(); ++ai, ++index)
00425       {
00426         vifa_int_face_attr_sptr  attr_ptr = *ai;
00427         vals[index] = CallAttrFunction(attr_ptr.ptr(), attr_index);
00428         attr_vec_[attr_index]->add_sample(vals[index]);
00429       }
00430     }
00431 
00432     return float(attr_vec_[attr_index]->get_mean());
00433   }
00434   else
00435   {
00436     // If no faces in neighborhood...
00437     return -1.f;
00438   }
00439 }
00440 
00441 // Get or compute standard deviation of a vifa_int_face_attr attribute.
00442 // Computes histogram if necessary.  Not weighted by area.
00443 float vifa_int_faces_attr::
00444 GetSDAttr(int attr_index)
00445 {
00446   if (!attr_map_.empty())
00447   {
00448     if (!attr_vec_[attr_index].ptr())
00449     {
00450       // Create attr histogram by side effect
00451       this->GetMeanAttr(attr_index);
00452     }
00453 
00454     return (float)vcl_sqrt(attr_vec_[attr_index]->get_var());
00455   }
00456   else
00457   {
00458     // If there are no faces in neighborhood...
00459     return -1;
00460   }
00461 }
00462 
00463 // Get or compute min value of a vifa_int_face_attr attribute.
00464 // Computes histogram if necessary.  Not weighted by area.
00465 float vifa_int_faces_attr::
00466 GetMinAttr(int attr_index)
00467 {
00468   if (!attr_map_.empty())
00469   {
00470     if (!attr_vec_[attr_index].ptr())
00471     {
00472       // Create attr histogram by side effect
00473       this->GetMeanAttr(attr_index);
00474     }
00475 
00476     return float(attr_vec_[attr_index]->get_min());
00477   }
00478   else
00479     return -1.f;
00480 }
00481 
00482 // Get or compute max value of a vifa_int_face_attr attribute.
00483 // Computes histogram if necessary.  Not weighted by area.
00484 float vifa_int_faces_attr::
00485 GetMaxAttr(int attr_index)
00486 {
00487   if (!attr_map_.empty())
00488   {
00489     if (!attr_vec_[attr_index].ptr())
00490     {
00491       // Create attr histogram by side effect
00492       this->GetMeanAttr(attr_index);
00493     }
00494 
00495     return float(attr_vec_[attr_index]->get_max());
00496   }
00497   else
00498     return -1.f;
00499 }
00500 
00501 // ---------------------------------------------------------------------
00502 // Non-histogrammed attributes.  One value per vifa_int_faces_attr.
00503 
00504 // area of all faces
00505 float vifa_int_faces_attr::
00506 Area()
00507 {
00508   if (!attr_map_.empty())
00509   {
00510     area_ = 0;
00511     for (attr_iterator ai = attr_map_.begin(); ai != attr_map_.end(); ++ai)
00512       area_ += (*ai)->Area();
00513 
00514     return area_;
00515   }
00516   else
00517     return 0.f;
00518 }
00519 
00520 // ratio of major moments of union of all faces
00521 float vifa_int_faces_attr::
00522 AspectRatio()
00523 {
00524   return 0.f;
00525 }
00526 
00527 // a helper function
00528 edge_list* vifa_int_faces_attr::
00529 GetPerimeterEdges()
00530 {
00531   edge_list*  p_edges = new edge_list;
00532 
00533   if (faces_.empty())
00534   {
00535     vcl_cerr << "no faces to calculate perimeter!\n";
00536     return p_edges;
00537   }
00538 
00539   // Maps edgeID to # of appearances
00540   vcl_map<int, int>      edge_count;
00541   vcl_map<int, int>::iterator  edge_count_pos;
00542 
00543   int  edge_index = 0;
00544   for (iface_iterator f = faces_.begin(); f != faces_.end(); ++f)
00545   {
00546     edge_list edges; (*f)->edges(edges);
00547 
00548     for (edge_iterator ei = edges.begin(); ei != edges.end(); ei++)
00549     {
00550       vtol_edge_sptr  e = *ei;
00551       int        e_id = e->get_id();
00552 
00553       if (e_id == 0)
00554       {
00555         e_id = ++edge_index;
00556         e->set_id(e_id);
00557       }
00558 
00559       int  count;
00560       edge_count_pos = edge_count.find(e_id);
00561       if (edge_count_pos == edge_count.end())
00562         count = 1;
00563       else
00564         count = edge_count_pos->second + 1;
00565 
00566       edge_count.insert(vcl_pair<int, int>(e_id, count));
00567     }
00568   }
00569 
00570   int  unique_count = 0;
00571   for (iface_iterator f = faces_.begin(); f != faces_.end(); ++f)
00572   {
00573     edge_list edges; (*f)->edges(edges);
00574     for (edge_iterator ei = edges.begin(); ei != edges.end(); ei++)
00575     {
00576       vtol_edge_sptr  e = *ei;
00577       int        count;
00578 
00579       edge_count_pos = edge_count.find(e->get_id());
00580       if (edge_count_pos == edge_count.end())
00581       {
00582         vcl_cerr << "Inconsistency in vifa_int_faces_attr::perimeter()?\n";
00583         continue;
00584       }
00585       else
00586         count = edge_count_pos->second;
00587 
00588       if (count == 1)
00589       {
00590         unique_count++;
00591         p_edges->push_back(e);
00592       }
00593     }
00594   }
00595 
00596   return p_edges;
00597 }
00598 
00599 
00600 // length of boundary of face group, in pixels.  Includes hole boundaries.
00601 float vifa_int_faces_attr::
00602 PerimeterLength()
00603 {
00604   if (perimeter_ >= 0)
00605   {
00606     // Wary of "if ... == -1.0f"
00607     return perimeter_;
00608   }
00609 
00610   perimeter_ = 0;
00611 
00612   edge_list*  p_edges = this->GetPerimeterEdges();
00613   if (p_edges)
00614   {
00615     for (edge_iterator eit = p_edges->begin(); eit != p_edges->end(); ++eit)
00616     {
00617       vtol_edge_2d*  e = (*eit)->cast_to_edge_2d();
00618 
00619       if (e)
00620         perimeter_ += float(e->curve()->length());
00621     }
00622 
00623     delete p_edges;
00624   }
00625 
00626   return perimeter_;
00627 }
00628 
00629 float vifa_int_faces_attr::
00630 WeightedPerimeterLength()
00631 {
00632   if (weighted_perimeter_ >= 0)
00633     return weighted_perimeter_;
00634 
00635 //  vcl_cout << "In vifsa::WeightedPerimeterSum()...\n";
00636 
00637   weighted_perimeter_ = 0;
00638 
00639   edge_list*  p_edges = this->GetPerimeterEdges();
00640   if (p_edges)
00641   {
00642     // uh-oh, we've lost the face information for defining
00643     // "the other face"...
00644 
00645     float  weighted_perimeter_sum = 0;
00646     float  contrast_sum = 0;
00647     for (edge_iterator eit = p_edges->begin(); eit != p_edges->end(); ++eit)
00648     {
00649       vtol_edge_2d*  e = (*eit)->cast_to_edge_2d();
00650 
00651       if (e)
00652       {
00653         face_list edge_faces; e->faces(edge_faces);
00654         iface_list  in_faces;
00655         iface_list  out_faces;
00656 
00657 //        vcl_cout << edge_faces->size() << " faces found" << endl;
00658 
00659         for (face_iterator fi=edge_faces.begin(); fi != edge_faces.end(); ++fi)
00660         {
00661           vtol_intensity_face*  int_f = (*fi)->cast_to_intensity_face();
00662 
00663           if (!int_f)
00664           {
00665             vcl_cerr << "vifa_int_faces_attr::WeightedPerimeterLength() -"
00666                      << " Face is not an intensity face\n";
00667             continue;
00668           }
00669 
00670           bool in_face = false;
00671           for (iface_iterator f = faces_.begin(); f != faces_.end(); ++f)
00672           {
00673             if (**f == *int_f)
00674             {
00675               in_face = true;
00676               in_faces.push_back(int_f);
00677               break;
00678             }
00679           }
00680 
00681           if (!in_face)
00682             out_faces.push_back(int_f);
00683         }
00684 
00685 //        vcl_cout << in_faces.size() << " in_faces, " << out_faces.size()
00686 //                 << " out_faces\n";
00687 
00688         //  this might emphasize large, high-gradient faces too much...
00689 
00690         float  i_intensity_sum = 0;
00691         float  i_area_sum = 0;
00692         for (iface_iterator f = in_faces.begin(); f != in_faces.end(); ++f)
00693         {
00694           i_intensity_sum += ((*f)->Io() * (*f)->Npix());
00695           i_area_sum += (*f)->Npix();
00696         }
00697 
00698 //        vcl_cout << "i_intensity_sum = " << i_intensity_sum
00699 //                 << ", i_area_sum = " << i_area_sum << vcl_endl;
00700 
00701         float  i_intensity = (i_area_sum > 0) ?  i_intensity_sum / i_area_sum : 0.f;
00702 
00703         float  o_intensity_sum = 0;
00704         float  o_area_sum = 0;
00705         for (iface_iterator f = out_faces.begin();
00706              f != out_faces.end(); ++f)
00707         {
00708           o_intensity_sum += ((*f)->Io() * (*f)->Npix());
00709           o_area_sum += (*f)->Npix();
00710         }
00711 
00712 //        vcl_cout << "o_intensity_sum = " << o_intensity_sum
00713 //                 << ", o_area_sum = " << o_area_sum << vcl_endl;
00714 
00715         float  o_intensity = (o_area_sum > 0) ?  o_intensity_sum / o_area_sum : 0.f;
00716 
00717         float  intensity_gradient = vcl_fabs(i_intensity - o_intensity);
00718 
00719 //        vcl_cout << "intensity_gradient = " << intensity_gradient
00720 //                 << ", curve length = " << e->curve()->length() << vcl_endl;
00721 
00722         weighted_perimeter_sum +=
00723           float(e->curve()->length()) * intensity_gradient;
00724         contrast_sum += intensity_gradient;
00725       }
00726       else
00727         vcl_cerr << "(*eit)->cast_to_edge_2d() returned NULL\n";
00728     }
00729 
00730 //    vcl_cout << "weighted_perimeter_sum = " << weighted_perimeter_sum
00731 //             << ", contrast_sum = " << contrast_sum << vcl_endl;
00732 
00733     weighted_perimeter_ = weighted_perimeter_sum / contrast_sum;
00734     delete p_edges;
00735   }
00736 
00737 //  vcl_cout << "Leaving vifsa::WeightedPerimeterSum()\n";
00738 
00739   return weighted_perimeter_;
00740 }
00741 
00742 // edge length^2 / detection area
00743 float vifa_int_faces_attr::
00744 Complexity()
00745 {
00746   if (this->Area() <= 0)
00747     return 0.f;
00748 
00749   float  p = this->PerimeterLength();
00750   return p * p / this->Area();
00751 }
00752 
00753 
00754 float vifa_int_faces_attr::
00755 WeightedComplexity()
00756 {
00757   if (this->Area() <= 0)
00758     return 0.f;
00759 
00760   float  wp = this->WeightedPerimeterLength();
00761   return wp * wp / this->Area();
00762 }
00763 
00764 void vifa_int_faces_attr::
00765 SetNP()
00766 {
00767   if (npobj_)
00768     npobj_->reset();
00769   else
00770     npobj_ = new vifa_parallel(faces_, true);
00771 }
00772 
00773 float vifa_int_faces_attr::
00774 TwoPeakParallel()
00775 {
00776   if (cached_2_parallel_ < 0)
00777   {
00778     SetNP();
00779     float  max_angle;
00780     float  std_dev;
00781     float  scale;
00782 
00783     for (int i=0; i<1; i++)
00784     {
00785       npobj_->map_gaussian(max_angle, std_dev, scale);
00786       npobj_->remove_gaussian(max_angle, std_dev, scale);
00787     }
00788 
00789     cached_2_parallel_ = npobj_->area();
00790   }
00791 
00792   return cached_2_parallel_;
00793 }
00794 
00795 float vifa_int_faces_attr::
00796 FourPeakParallel()
00797 {
00798   if (cached_4_parallel_ < 0)
00799   {
00800     SetNP();
00801     float  max_angle;
00802     float  std_dev;
00803     float  scale;
00804 
00805     for (int i=0; i<3; i++)
00806     {
00807       npobj_->map_gaussian(max_angle, std_dev, scale);
00808       npobj_->remove_gaussian(max_angle, std_dev, scale);
00809     }
00810 
00811     cached_4_parallel_ = npobj_->area();
00812   }
00813 
00814   return cached_4_parallel_;
00815 }
00816 
00817 float vifa_int_faces_attr::
00818 EightyPercentParallel()
00819 {
00820   if (cached_80_parallel_ < 0)
00821   {
00822     SetNP();
00823 
00824     for (int i=0; i < 20 && npobj_->area() > 0.3f; ++i)
00825     {
00826       float  max_angle, std_dev, scale;
00827       npobj_->map_gaussian(max_angle, std_dev, scale);
00828       npobj_->remove_gaussian(max_angle, std_dev, scale);
00829       cached_80_parallel_ = float(i);
00830     }
00831   }
00832 
00833   return cached_80_parallel_;
00834 }
00835 
00836 vifa_int_face_attr_sptr vifa_int_faces_attr::
00837 factory_new_attr(vtol_intensity_face_sptr face)
00838 {
00839   if (factory_)
00840     return factory_->obtain_int_face_attr(face,
00841                                           fitter_params_.ptr(),
00842                                           gpp_s_.ptr(),
00843                                           gpp_w_.ptr(),
00844                                           np_.ptr());
00845   else
00846     return new vifa_int_face_attr(face,
00847                                   fitter_params_.ptr(),
00848                                   gpp_s_.ptr(),
00849                                   gpp_w_.ptr(),
00850                                   np_.ptr());
00851 }