00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <vul/vul_arg.h>
00021 #include <vimt/vimt_image_2d_of.h>
00022 #include <vimt/vimt_gaussian_pyramid_builder_2d.h>
00023 #include <vimt/vimt_image_pyramid.h>
00024 #include <vimt/vimt_crop.h>
00025 #include <mbl/mbl_read_props.h>
00026 #include <vil/vil_load.h>
00027 #include <vul/vul_string.h>
00028 #include <vcl_algorithm.h>
00029 #include <vil/vil_save.h>
00030 #include <vil/vil_fill.h>
00031 #include <vil/vil_crop.h>
00032 #include <vil/vil_math.h>
00033 #include <vil/vil_convert.h>
00034 #include <vil/vil_resample_bilin.h>
00035 #include <vnl/vnl_math.h>
00036 #include <vgl/vgl_point_2d.h>
00037 #include <vgl/vgl_vector_2d.h>
00038 #include <fhs/fhs_searcher.h>
00039 #include <vimt/algo/vimt_normalised_correlation_2d.h>
00040 #include <mbl/mbl_draw_line.h>
00041
00042 void print_usage()
00043 {
00044 vcl_cout<<"fhs_match_tree_model -p param_file\n"
00045 <<"Loads in parameter file, which defines images,\n"
00046 <<"points, the arcs defining a tree and related details.\n"
00047 <<"Constructs a tree model from the first image.\n"
00048 <<"Uses normalised correlation and this model to locate\n"
00049 <<"equivalent points on the second image."<<vcl_endl;
00050 vul_arg_display_usage_and_exit();
00051 }
00052
00053 class fhs_model_params
00054 {
00055 public:
00056 vcl_string image1_path;
00057 vcl_string image2_path;
00058 vcl_string points_path;
00059 vcl_string arcs_path;
00060 vcl_string output_image1_path;
00061 vcl_string output_image2_path;
00062 int L_lo,L_hi;
00063 int half_width;
00064 double response_scale;
00065 };
00066
00067 bool parse_param_file(const vcl_string& param_path,
00068 fhs_model_params& params)
00069 {
00070
00071
00072
00073 vcl_ifstream ifs(param_path.c_str());
00074 if (!ifs)
00075 {
00076 vcl_cerr<<"Failed to open parameter file: "<<param_path<<'\n';
00077 return false;
00078 }
00079
00080 mbl_read_props_type props = mbl_read_props_ws(ifs);
00081
00082 if (props.find("image1_path")!=props.end())
00083 params.image1_path = props["image1_path"];
00084 else {vcl_cerr<<"No image1_path: specified.\n"; return false; }
00085
00086 if (props.find("image2_path")!=props.end())
00087 params.image2_path = props["image2_path"];
00088 else {vcl_cerr<<"No image2_path: specified.\n"; return false; }
00089
00090 if (props.find("output_image1_path")!=props.end())
00091 params.output_image1_path = props["output_image1_path"];
00092 else {vcl_cerr<<"No output_image1_path: specified.\n"; return false; }
00093
00094 if (props.find("output_image2_path")!=props.end())
00095 params.output_image2_path = props["output_image2_path"];
00096 else {vcl_cerr<<"No output_image2_path: specified.\n"; return false; }
00097
00098 if (props.find("points_path")!=props.end())
00099 params.points_path = props["points_path"];
00100 else {vcl_cerr<<"No points_path: specified.\n"; return false; }
00101
00102 if (props.find("arcs_path")!=props.end())
00103 params.arcs_path = props["arcs_path"];
00104 else {vcl_cerr<<"No arcs2_path: specified.\n"; return false; }
00105
00106 if (props.find("L_lo")!=props.end())
00107 params.L_lo = vul_string_atoi(props["L_lo"]);
00108 else {vcl_cerr<<"No L_lo: specified.\n"; return false; }
00109
00110 if (props.find("half_width")!=props.end())
00111 params.half_width = vul_string_atoi(props["half_width"]);
00112 else {vcl_cerr<<"No half_width: specified.\n"; return false; }
00113
00114 if (props.find("L_hi")!=props.end())
00115 params.L_hi = vul_string_atoi(props["L_hi"]);
00116 else {vcl_cerr<<"No L_hi: specified.\n"; return false; }
00117
00118 params.response_scale=0.1;
00119 if (props.find("response_scale")!=props.end())
00120 params.response_scale = vul_string_atof(props["response_scale"]);
00121
00122 return true;
00123 }
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 bool fhs_load_points(const vcl_string& path,
00134 vcl_vector<vgl_point_2d<double> >& pts)
00135 {
00136 vcl_ifstream ifs( path.c_str(), vcl_ios_in );
00137 if (!ifs)
00138 { vcl_cerr<<"Failed to load in points from "<<path<<'\n'; return false; }
00139 vcl_string label;
00140
00141
00142 int image_nx, image_ny, image_nz;
00143 int n = -1;
00144
00145 ifs >> label;
00146 while (!ifs.eof() && label != "}")
00147 {
00148 if (label.size()>=2 && label[0]=='/' && label[1]=='/')
00149 {
00150
00151 char buf[256];
00152 ifs.get(buf,256);
00153 }
00154 else
00155 if (label=="version:")
00156 ifs>>label;
00157 else if (label=="image_size_x:")
00158 ifs>>image_nx;
00159 else if (label=="image_size_y:")
00160 ifs>>image_ny;
00161 else if (label=="image_size_z:")
00162 ifs>>image_nz;
00163 else if (label=="n_points:")
00164 ifs>>n;
00165 else if (label=="{")
00166 {
00167 pts.resize(n);
00168 for (int i=0;i<n;++i)
00169 {
00170 double x,y;
00171 ifs>>x>>y;
00172 pts[i]=vgl_point_2d<double>(x,y);
00173 }
00174 ifs>>label;
00175 if (label!="}")
00176 {
00177 vcl_cerr<<"Expecting }, got "<<label<<'\n';
00178 return false;
00179 }
00180 }
00181 else
00182 {
00183 vcl_cerr<<"Unexpected label: <"<<label<<">\n";
00184 return false;
00185 }
00186 ifs>>label;
00187 }
00188 return true;
00189 }
00190
00191
00192
00193 bool fhs_load_arcs(const vcl_string& path,
00194 vcl_vector<vcl_pair<int,int> >& pairs)
00195 {
00196 vcl_vector<int> v;
00197 vcl_ifstream ifs( path.c_str(), vcl_ios_in );
00198 if (!ifs)
00199 { vcl_cerr<<"Failed to load in arc links from "<<path<<'\n'; return false; }
00200
00201 int x;
00202 ifs>>vcl_ws;
00203 while (!ifs.eof())
00204 {
00205 ifs>>x>>vcl_ws;
00206 v.push_back(x);
00207 }
00208
00209 if (v.size()%2==1)
00210 {
00211 vcl_cerr<<"Odd number of indices supplied in "<<path<<'\n';
00212 return false;
00213 }
00214
00215 pairs.resize(v.size()/2);
00216 for (unsigned i=0;i<pairs.size();++i)
00217 pairs[i] = vcl_pair<int,int>(v[2*i],v[2*i+1]);
00218 return true;
00219 }
00220
00221
00222
00223
00224
00225 void extract_normalised_patches(const vimt_image& image,
00226 const vcl_vector<vgl_point_2d<double> >& pts,
00227 int half_width,
00228 vcl_vector<vil_image_view<float> >& patch,
00229 vcl_vector<vgl_point_2d<double> >& ref_pts)
00230 {
00231 const vimt_image_2d_of<vxl_byte>& byte_im =
00232 static_cast<const vimt_image_2d_of<vxl_byte>&>(image);
00233 int ni = byte_im.image().ni();
00234 int nj = byte_im.image().nj();
00235 unsigned n=pts.size();
00236 for (unsigned i=0;i<n;++i)
00237 {
00238 vgl_point_2d<double> im_p = byte_im.world2im()(pts[i]);
00239 int px = vnl_math_rnd(im_p.x()+0.5);
00240 int py = vnl_math_rnd(im_p.y()+0.5);
00241
00242
00243 int ilo = vcl_max(0,px-half_width);
00244 int ihi = vcl_min(ni-1,px+half_width);
00245 int jlo = vcl_max(0,py-half_width);
00246 int jhi = vcl_min(nj-1,py+half_width);
00247
00248
00249 int kx = px-ilo;
00250 int ky = py-jlo;
00251 ref_pts.push_back(vgl_point_2d<double>(kx,ky));
00252 vil_image_view<float> patch1;
00253 vil_convert_cast(vil_crop(byte_im.image(),ilo,1+ihi-ilo, jlo,1+jhi-jlo),
00254 patch1);
00255 vil_math_normalise(patch1);
00256 patch.push_back(patch1);
00257 }
00258 }
00259
00260 void draw_tree(vil_image_view<vxl_byte>& image,
00261 const vcl_vector<vgl_point_2d<double> >& pts,
00262 const vcl_vector<vcl_pair<int,int> >& pairs)
00263 {
00264
00265 for (unsigned i=0;i<pairs.size();++i)
00266 mbl_draw_line(image,
00267 pts[pairs[i].first],
00268 pts[pairs[i].second],vxl_byte(255));
00269
00270
00271
00272 for (unsigned i=0;i<pts.size();++i)
00273 {
00274 vil_fill_disk(image,pts[i].x(),pts[i].y(),4,vxl_byte(255));
00275 }
00276 }
00277
00278
00279
00280 void vimt_resample(const vimt_image_2d_of<float>& src_im, int src_L,
00281 vimt_image_2d_of<float>& dest_im, int dest_L)
00282 {
00283 if (dest_L<=src_L)
00284 {
00285 dest_im=src_im;
00286 return;
00287 }
00288 unsigned ni = src_im.image().ni();
00289 unsigned nj = src_im.image().nj();
00290 unsigned s=1;
00291 for (int L=dest_L;L>=src_L;--L) s*=2;
00292
00293 vil_resample_bilin(src_im.image(),dest_im.image(),1+s*(ni-1),1+s*(nj-1));
00294 vimt_transform_2d scale;
00295 scale.set_zoom_only(s,s,0.0,0.0);
00296 dest_im.set_world2im(scale*src_im.world2im());
00297 }
00298
00299
00300 int main( int argc, char* argv[] )
00301 {
00302 vul_arg<vcl_string> param_path("-p","Parameter file path");
00303
00304 vul_arg_parse(argc, argv);
00305
00306 if (param_path()=="")
00307 {
00308 print_usage();
00309 return 0;
00310 }
00311
00312 fhs_model_params params;
00313 if (!parse_param_file(param_path(),params)) return 1;
00314
00315
00316
00317
00318
00319 vimt_image_2d_of<vxl_byte> image1,image2;
00320 image1.image() = vil_load(params.image1_path.c_str());
00321 if (image1.image().size()==0)
00322 {
00323 vcl_cerr<<"Unable to read in image from "<<params.image1_path<<'\n';
00324 return 1;
00325 }
00326 image2.image() = vil_load(params.image2_path.c_str());
00327 if (image2.image().size()==0)
00328 {
00329 vcl_cerr<<"Unable to read in image from "<<params.image2_path<<'\n';
00330 return 1;
00331 }
00332
00333
00334
00335
00336 vimt_gaussian_pyramid_builder_2d<vxl_byte> pyr_builder;
00337 vimt_image_pyramid image_pyr1,image_pyr2;
00338 pyr_builder.build(image_pyr1,image1);
00339 pyr_builder.build(image_pyr2,image2);
00340
00341 int max_L = vcl_min(image_pyr1.hi(),image_pyr2.hi());
00342 if (params.L_lo<0 || params.L_lo>max_L || params.L_hi<params.L_lo)
00343 {
00344 vcl_cerr<<"Levels must be in range [0,"<<max_L<<"], with lo<=hi\n";
00345 return 2;
00346 }
00347
00348
00349
00350
00351
00352 vcl_vector<vgl_point_2d<double> > ref_pts;
00353 if (!fhs_load_points(params.points_path,ref_pts)) return 3;
00354
00355 vcl_vector<unsigned> im_level(ref_pts.size());
00356 for (unsigned i=0;i<ref_pts.size();++i) im_level[i]=params.L_hi;
00357
00358
00359
00360
00361 vcl_vector<vcl_pair<int,int> > pairs;
00362 if (!fhs_load_arcs(params.arcs_path,pairs)) return 4;
00363
00364
00365 for (unsigned i=0;i<pairs.size();++i)
00366 {
00367 if (pairs[i].first<0 || (unsigned int)(pairs[i].first)>=ref_pts.size())
00368 { vcl_cerr<<"Invalid point index "<<pairs[i].first<<'\n'; return 5; }
00369 if (pairs[i].second<0 || (unsigned int)(pairs[i].second)>=ref_pts.size())
00370 { vcl_cerr<<"Invalid point index "<<pairs[i].second<<'\n'; return 5; }
00371 }
00372
00373
00374
00375
00376
00377 vcl_vector<vil_image_view<float> > patch;
00378 vcl_vector<vgl_point_2d<double> > patch_ref;
00379
00380
00381 extract_normalised_patches(image_pyr1(params.L_hi),ref_pts,
00382 params.half_width,patch,patch_ref);
00383
00384
00385
00386
00387
00388
00389 vcl_vector<fhs_arc> arcs(pairs.size());
00390 int root_node = pairs[0].first;
00391 for (unsigned i=0;i<pairs.size();++i)
00392 {
00393 int i1 = pairs[i].first;
00394 int i2 = pairs[i].second;
00395 vgl_vector_2d<double> dp = ref_pts[i2]-ref_pts[i1];
00396 double sd_x = vcl_max(double(1 << im_level[i]),0.2*dp.length());
00397 double sd_y = vcl_max(double(1 << im_level[i]),0.2*dp.length());
00398 arcs[i]=fhs_arc(i1,i2,dp.x(),dp.y(),sd_x*sd_x,sd_y*sd_y);
00399 }
00400
00401
00402
00403
00404
00405 vcl_vector<vimt_image_2d_of<float> > feature_response(ref_pts.size());
00406 for (unsigned i=0;i<ref_pts.size();++i)
00407 {
00408 const vimt_image_2d_of<vxl_byte>& byte_im =
00409 static_cast<const vimt_image_2d_of<vxl_byte>&>(image_pyr2(im_level[i]));
00410
00411
00412 int ni=byte_im.image().ni();
00413 int xw = ni/8+1+params.half_width;
00414 int nj=byte_im.image().nj();
00415 int yw = nj/8+1+params.half_width;
00416 vgl_point_2d<double> im_p = byte_im.world2im()(ref_pts[i]);
00417 int xc = int(0.5+im_p.x());
00418 int yc = int(0.5+im_p.y());
00419 int ilo = vcl_max(0,xc-xw);
00420 int ihi = vcl_min(ni-1,xc+xw);
00421 int jlo = vcl_max(0,yc-yw);
00422 int jhi = vcl_min(nj-1,yc+yw);
00423 vimt_image_2d_of<vxl_byte> cropped_im = vimt_crop(byte_im,
00424 ilo, 1+ihi-ilo,
00425 jlo, 1+jhi-jlo);
00426
00427
00428
00429 vimt_normalised_correlation_2d(cropped_im,feature_response[i],
00430 patch[i],patch_ref[i],float());
00431 if (int(im_level[i])!=params.L_lo)
00432 {
00433
00434 vimt_image_2d_of<float> fr;
00435 fr.deep_copy(feature_response[i]);
00436 vimt_resample(fr,im_level[i], feature_response[i],params.L_lo);
00437 }
00438
00439 vil_math_scale_values(feature_response[i].image(),-params.response_scale);
00440 }
00441
00442
00443
00444
00445
00446 fhs_searcher searcher;
00447 searcher.set_tree(arcs,root_node);
00448 searcher.search(feature_response);
00449 vcl_vector<vgl_point_2d<double> > pts2;
00450 searcher.best_points(pts2);
00451
00452
00453 draw_tree(image1.image(),ref_pts,pairs);
00454
00455 if (vil_save(image1.image(),params.output_image1_path.c_str()))
00456 {
00457 vcl_cout<<"Saved output image 1 to "<<params.output_image1_path<<vcl_endl;
00458 }
00459
00460
00461 draw_tree(image2.image(),pts2,pairs);
00462
00463 if (vil_save(image2.image(),params.output_image2_path.c_str()))
00464 {
00465 vcl_cout<<"Saved output image 2 to "<<params.output_image2_path<<vcl_endl;
00466 }
00467
00468
00469 return 0;
00470 }