contrib/mul/mfpf/mfpf_searcher.cxx
Go to the documentation of this file.
00001 #include "mfpf_searcher.h"
00002 //:
00003 // \file
00004 // \brief Algorithms to perform global search for multiple matches
00005 // \author Tim Cootes
00006 
00007 #include <vgl/vgl_point_2d.h>
00008 #include <vgl/vgl_vector_2d.h>
00009 
00010 mfpf_searcher::mfpf_searcher()
00011 {
00012   proximity_r_= 3;
00013 }
00014 
00015 //: Find list of poses overlapping given pose
00016 void mfpf_searcher::find_overlaps(mfpf_point_finder& pf,
00017                                   const vcl_vector<mfpf_pose>& poses,
00018                                   const mfpf_pose& pose,
00019                                   vcl_vector<unsigned>& overlaps)
00020 {
00021   overlaps.resize(0);
00022   for (unsigned i=0;i<poses.size();++i)
00023   {
00024     if (pf.overlap(poses[i],pose))
00025       overlaps.push_back(i);
00026   }
00027 }
00028 
00029 //: If pose not near any poses in list, return false
00030 //  If it is near one, and its fit is better, then replace it.
00031 //  Uses pf.overlap() function to check for proximity
00032 bool mfpf_searcher::find_near_pose(mfpf_point_finder& pf,
00033                                    vcl_vector<mfpf_pose>& poses,
00034                                    vcl_vector<double>& fits,
00035                                    const mfpf_pose& pose, double fit)
00036 {
00037   vcl_vector<unsigned> index;
00038   find_overlaps(pf,poses,pose,index);
00039   if (index.size()==0) return false;  // No overlaps
00040 
00041   if (index.size()==1)
00042   {
00043     // Only overlaps with a single pose
00044     // Replace that pose if new one is better
00045     if (fits[index[0]]>fit)
00046     {
00047       poses[index[0]]=pose;
00048       fits[index[0]]=fit;
00049     }
00050     return true;
00051   }
00052 
00053   // More complicated situation
00054   // We have more than one overlapping pose
00055   // If new one is worse than all of them, ignore it.
00056   // If new one is better than all of them, replace them all
00057   // Otherwise we have a potentially ambiguous situation
00058   // eg three overlapping objects in a row A-B-C with A not
00059   // overlapping with C, but f(A)<f(B)<f(C)
00060   // In this case eliminate all overlapping poses except the best one.
00061   // There's a danger that this might loose some weaker local
00062   // minima, so perhaps revise this later.
00063 
00064   // Count the number of overlaps with worse fit
00065   // and record best fit
00066   unsigned n_worse=0;
00067   double best_fit = fit;
00068   unsigned best_i = 0;
00069   for (unsigned i=0;i<index.size();++i)
00070   {
00071     if (fits[index[i]]>fit) { n_worse++;}
00072     if (fits[index[i]]<best_fit)
00073     { best_i=index[i]; best_fit=fits[index[i]]; }
00074   }
00075 
00076   if (n_worse==0) return true; // New pose no better than any existing
00077 
00078   // Have to generate new lists
00079   vcl_vector<mfpf_pose> poses0=poses;
00080   vcl_vector<double> fits0=fits;
00081   unsigned n1 = poses.size()+1-index.size();
00082   poses.resize(n1);
00083   fits.resize(n1);
00084   unsigned j=0;
00085   // First add all poses which don't overlap with new pose
00086   for (unsigned i=0;i<poses0.size();++i)
00087   {
00088     if (!pf.overlap(poses0[i],pose))
00089     {
00090       poses[j]=poses0[i];
00091       fits[j]=fits0[i];
00092       ++j;
00093     }
00094   }
00095   if (n_worse==index.size())
00096   {
00097     // New one better than all overlaps
00098     poses[j]=pose;  fits[j]=fit;
00099   }
00100   else
00101   {
00102     // Retain best fit
00103     poses[j]=poses0[best_i]; fits[j]=best_fit;
00104   }
00105   return true;
00106 }
00107 
00108 void mfpf_searcher::find_refined_matches(mfpf_point_finder& pf,
00109                                          const vimt_image_2d_of<float>& image,
00110                                          const vgl_point_2d<double>& p,
00111                                          const vgl_vector_2d<double>& u,
00112                                          vcl_vector<mfpf_pose>& poses,
00113                                          vcl_vector<double>& fits)
00114 {
00115   vcl_vector<mfpf_pose> poses1;
00116   vcl_vector<double> fits1;
00117   // Exhaustive search at multiple angles and scales
00118   // Returns local minima in (x,y)
00119   // However, single object may return multiple responses,
00120   // one at each angle/scale.
00121   pf.grid_search(image,p,u,poses1,fits1);
00122 vcl_cout<<"N.responses: "<<poses1.size()<<vcl_endl;
00123 
00124 #if 0
00125   double step = pf.step_size();
00126   double r = pf.radius()*step;
00127 
00128   // Two poses assumed similar if within about r/4 of each other
00129   // Or two pixels in the model frame
00130   double r_thresh = vcl_max(0.5*r,2*step);
00131 #endif // 0
00132 
00133   // Refine each one in turn, and add it to list if new
00134   poses.resize(0); fits.resize(0);
00135   for (unsigned i=0;i<poses1.size();++i)
00136   {
00137     mfpf_pose pose=poses1[i];
00138     double f = fits1[i];
00139     pf.refine_match(image,pose.p(),pose.u(),f);
00140     if (f>fits1[i]) vcl_cerr<<"Refinement failed!!!\n";
00141     if (!find_near_pose(pf,poses,fits,pose,f))
00142     {
00143       // Point distinct
00144       poses.push_back(pose);
00145       fits.push_back(f);
00146     }
00147   }
00148 }
00149 
00150 //: For each pose in the set, perform local search+refinement
00151 //  On exit pose_set contains the improved matches.
00152 void mfpf_searcher::search_around_set(mfpf_point_finder& pf,
00153                                       const vimt_image_2d_of<float>& image,
00154                                       mfpf_pose_set& pose_set)
00155 {
00156   if (pose_set.poses.size()==0) return;
00157 
00158   // Record size of search region, so that it can be re-instated later
00159   unsigned search_ni0=pf.search_ni();
00160   unsigned search_nj0=pf.search_nj();
00161 
00162   // Set to perform search over a small region
00163   pf.set_search_area(1,1);
00164   for (unsigned i=0;i<pose_set.poses.size();++i)
00165   {
00166     mfpf_pose pose_i=pose_set.poses[i];
00167     mfpf_pose new_pose;
00168     double f = pf.search(image,pose_i.p(),pose_i.u(),
00169                          new_pose.p(),new_pose.u());
00170 
00171     pf.refine_match(image,new_pose.p(),new_pose.u(),f);
00172     pose_set.poses[i]=new_pose;
00173     pose_set.fits[i] =f;
00174   }
00175 
00176   // Return pf to original state
00177   pf.set_search_area(search_ni0,search_nj0);
00178 }
00179