Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members

find_matches.cxx

Go to the documentation of this file.
00001 //:
00002 // \file
00003 // \author Tim Cootes
00004 // \brief Example program using F&H method to locate matches on a pair of images
00005 
00006 #include <vcl_cassert.h>
00007 #include <vul/vul_arg.h>
00008 #include <vimt/vimt_image_2d_of.h>
00009 #include <vimt/vimt_gaussian_pyramid_builder_2d.h>
00010 #include <vimt/vimt_image_pyramid.h>
00011 #include <vil/algo/vil_corners.h>
00012 #include <vil/algo/vil_find_peaks.h>
00013 #include <vil/vil_load.h>
00014 #include <vil/vil_save.h>
00015 #include <vil/vil_fill.h>
00016 #include <vil/vil_crop.h>
00017 #include <vil/vil_math.h>
00018 #include <vil/vil_convert.h>
00019 #include <mbl/mbl_index_sort.h>
00020 #include <fhs/fhs_searcher.h>
00021 #include <vimt/algo/vimt_normalised_correlation_2d.h>
00022 #include <mbl/mbl_minimum_spanning_tree.h>
00023 #include <mbl/mbl_draw_line.h>
00024 
00025 void print_usage()
00026 {
00027   vcl_cout<<"find_matches -i1 image1.jpg -i2 image2.jpg -L 2"<<vcl_endl
00028           <<"Loads in image1 and image2."<<vcl_endl
00029           <<"Locates a set of interesting features (corners) on level L of image1."<<vcl_endl
00030           <<"Constructs a model of their relative positions."<<vcl_endl
00031           <<"Uses normalised correllation and this model to locate"<<vcl_endl
00032           <<"equivalent points on the same level of the second image."<<vcl_endl;
00033   vul_arg_display_usage_and_exit();
00034 }
00035 
00036 //: Write tree into the image
00037 // Draw disks at each point, and lines between linked points
00038 void draw_tree(vil_image_view<vxl_byte>& image,
00039                const vcl_vector<vgl_point_2d<double> >& pts,
00040                const vcl_vector<vcl_pair<int,int> >& pairs)
00041 {
00042   // Draw tree into image for display purposes
00043   for (unsigned i=0;i<pairs.size();++i)
00044     mbl_draw_line(image,
00045                   pts[pairs[i].first],
00046                   pts[pairs[i].second],vxl_byte(255));
00047 
00048   // Write position of selected points into the original image
00049   // for display purposes.
00050   for (unsigned i=0;i<pts.size();++i)
00051   {
00052     vil_fill_disk(image,pts[i].x(),pts[i].y(),4,vxl_byte(255));
00053   }
00054 }
00055 
00056 int main( int argc, char* argv[] )
00057 {
00058   vul_arg<vcl_string> image1_path("-i1","Input image 1");
00059   vul_arg<vcl_string> image2_path("-i2","Input image 2");
00060   vul_arg<vcl_string> output_image1_path("-o1","Output image 1","output1.png");
00061   vul_arg<vcl_string> output_image2_path("-o2","Output image 1","output2.png");
00062   vul_arg<unsigned> level("-L","Image pyramid level to work on",2);
00063   vul_arg<unsigned> nc("-n","Number of points to select",10);
00064   vul_arg<unsigned> w("-w","Half width of filters",7);
00065   vul_arg<double> f("-f","Relative strength of intensity vs shape",0.1);
00066 
00067   vul_arg_parse(argc, argv);
00068 
00069   if (image1_path()=="" || image2_path()=="")
00070   {
00071     print_usage();
00072     return 0;
00073   }
00074 
00075   // ============================================
00076   // Attempt to load in images
00077   // ============================================
00078 
00079   vimt_image_2d_of<vxl_byte> image1,image2;
00080   image1.image() = vil_load(image1_path().c_str());
00081   if (image1.image().size()==0)
00082   {
00083     vcl_cerr<<"Unable to read in image from "<<image1_path()<<vcl_endl;
00084     return 1;
00085   }
00086   image2.image() = vil_load(image2_path().c_str());
00087   if (image2.image().size()==0)
00088   {
00089     vcl_cerr<<"Unable to read in image from "<<image2_path()<<vcl_endl;
00090     return 1;
00091   }
00092 
00093   // ============================================
00094   // Build image pyramids and select chosen level
00095   // ============================================
00096   vimt_gaussian_pyramid_builder_2d<vxl_byte> pyr_builder;
00097   vimt_image_pyramid image_pyr1,image_pyr2;
00098   pyr_builder.build(image_pyr1,image1);
00099   pyr_builder.build(image_pyr2,image2);
00100 
00101   const vimt_image_2d_of<vxl_byte>& image1_L = static_cast<const vimt_image_2d_of<vxl_byte>&>(image_pyr1(level()));
00102   const vimt_image_2d_of<vxl_byte>& image2_L = static_cast<const vimt_image_2d_of<vxl_byte>&>(image_pyr2(level()));
00103 
00104   // ====================================================
00105   // Apply corner operator to image1_L and select corners
00106   // ====================================================
00107 
00108   vimt_image_2d_of<float> corner_im;
00109   corner_im.set_world2im(image1_L.world2im());
00110   vil_corners(image1_L.image(),corner_im.image());
00111 
00112   vcl_vector<unsigned> pi,pj;
00113   float threshold = 4.0f;
00114   vil_find_peaks_3x3(pi,pj,corner_im.image(),threshold);
00115 
00116   // Evaluate corner strength at each point (pi[i],pj[i])
00117   unsigned n = pi.size();
00118   vcl_vector<float> corner_str(n);
00119   for (unsigned i=0;i<n;++i)
00120     corner_str[i] = corner_im.image()(pi[i],pj[i]);
00121 
00122   // Sort and generate a list of image points and equivalent world points
00123   vcl_vector<unsigned> index;
00124   mbl_index_sort(corner_str,index);
00125 
00126   unsigned n_c = vcl_min(nc(),n);
00127   vcl_vector<vgl_point_2d<int> > im_pts(n_c);
00128   vcl_vector<vgl_point_2d<double> > w_pts(n_c);
00129   vimt_transform_2d im2w = image1_L.world2im().inverse();
00130   for (unsigned i=0;i<n_c;++i)
00131   {
00132     im_pts[i] = vgl_point_2d<int>(pi[index[n-1-i]],pj[index[n-1-i]]);
00133     w_pts[i]  = im2w(pi[index[n-1-i]],pj[index[n-1-i]]);
00134   }
00135 
00136 
00137   // ========================================================
00138   // Extract patches around each selected point and normalise
00139   // ========================================================
00140   vcl_vector<vil_image_view<float> > patch(n_c);
00141   vcl_vector<vgl_point_2d<double> > patch_ref(n_c);  // Reference point
00142   int ni = image1.image().ni();
00143   int nj = image1.image().nj();
00144   for (unsigned i=0;i<n_c;++i)
00145   {
00146     // Select region around point, allowing for image edges.
00147     int ilo = vcl_max(0,int(im_pts[i].x()-w()));
00148     int ihi = vcl_min(ni-1,int(im_pts[i].x()+w()));
00149     int jlo = vcl_max(0,int(im_pts[i].y()-w()));
00150     int jhi = vcl_min(nj-1,int(im_pts[i].y()+w()));
00151 
00152     // Compute position of reference point relative to corner
00153     int kx = im_pts[i].x()-ilo;
00154     int ky = im_pts[i].y()-jlo;
00155     patch_ref[i] =vgl_point_2d<double>(kx,ky);
00156     vil_convert_cast(vil_crop(image1_L.image(),ilo,1+ihi-ilo, jlo,1+jhi-jlo),
00157                      patch[i]);
00158     vil_math_normalise(patch[i]);
00159   }
00160 
00161   // Construct tree structure for points
00162   vcl_vector<vcl_pair<int,int> > pairs;
00163   mbl_minimum_spanning_tree(w_pts,pairs);
00164 
00165   assert(pairs.size()==n_c-1);
00166 
00167   // Draw tree into image for display purposes
00168   draw_tree(image1.image(),w_pts,pairs);
00169 
00170   if (vil_save(image1.image(),output_image1_path().c_str()))
00171   {
00172     vcl_cout<<"Saved output image 1 to "<<output_image1_path()<<vcl_endl;
00173   }
00174 
00175   // =================================================
00176   // Construct the arc model from the points and pairs
00177   // =================================================
00178 
00179   vcl_vector<fhs_arc> arcs(n_c-1);
00180   int root_node = pairs[0].first;
00181   for (unsigned i=0;i<pairs.size();++i)
00182   {
00183     int i1 = pairs[i].first;
00184     int i2 = pairs[i].second;
00185     vgl_vector_2d<double> dp = w_pts[i2]-w_pts[i1];
00186     double sd_x = vcl_max(0.1*ni,0.2*dp.length());
00187     double sd_y = vcl_max(0.1*nj,0.2*dp.length());
00188     arcs[i]=fhs_arc(i1,i2,dp.x(),dp.y(),sd_x*sd_x,sd_y*sd_y);
00189   }
00190 
00191   // =================================================
00192   // Apply filters to image2 (initially to whole image)
00193   // =================================================
00194   vcl_vector<vimt_image_2d_of<float> > feature_response(n_c);
00195   for (unsigned i=0;i<n_c;++i)
00196   {
00197     // Apply to whole image in first instance
00198     // Ideally would crop a region around expected position
00199     vimt_normalised_correlation_2d(image2_L,feature_response[i],
00200                                    patch[i],patch_ref[i],float());
00201 
00202     // Need good values to be small, not large, so apply -ve factor
00203     vil_math_scale_values(feature_response[i].image(),-f());
00204   }
00205 
00206   // ======================================================
00207   // Use fhs_searcher to locate equivalent points on image2
00208   // ======================================================
00209 
00210   fhs_searcher searcher;
00211   searcher.set_tree(arcs,root_node);
00212   searcher.search(feature_response);
00213   vcl_vector<vgl_point_2d<double> > pts2;
00214   searcher.best_points(pts2);
00215 
00216   // Draw tree into image for display purposes
00217   draw_tree(image2.image(),pts2,pairs);
00218 
00219   if (vil_save(image2.image(),output_image2_path().c_str()))
00220   {
00221     vcl_cout<<"Saved output image 2 to "<<output_image2_path()<<vcl_endl;
00222   }
00223 
00224   return 0;
00225 }

Generated on Thu Jan 10 14:44:46 2008 for contrib/mul/fhs by  doxygen 1.4.4