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