contrib/brl/bmvl/bmvv/bmvv_cal_manager.cxx
Go to the documentation of this file.
00001 // This is brl/bmvl/bmvv/bmvv_cal_manager.cxx
00002 #include "bmvv_cal_manager.h"
00003 //:
00004 // \file
00005 // \author J.L. Mundy
00006 
00007 #include <vcl_iostream.h>
00008 #include <vil/vil_image_view.h>
00009 #include <vil/vil_load.h>
00010 #include <vil/vil_save.h>
00011 #include <vil/vil_math.h>
00012 #include <vil/vil_new.h>
00013 #include <vnl/vnl_matrix_fixed.h>
00014 #include <vgl/vgl_vector_3d.h>
00015 #include <vgl/vgl_homg_point_2d.h>
00016 #include <vgl/vgl_homg_point_3d.h>
00017 #include <vgl/algo/vgl_h_matrix_2d.h>
00018 #include <vgl/algo/vgl_p_matrix.h>
00019 #include <vgui/vgui.h>
00020 #include <vgui/vgui_key.h>
00021 #include <vgui/vgui_style.h>
00022 #include <vgui/vgui_macro.h>
00023 #include <vgui/vgui_dialog.h>
00024 #include <vgui/vgui_image_tableau.h>
00025 #include <vgui/vgui_viewer2D_tableau.h>
00026 #include <vgui/vgui_shell_tableau.h>
00027 #include <vgui/vgui_range_map_params.h>
00028 #include <vgui/vgui_projection_inspector.h>
00029 #include <bgui/bgui_image_tableau.h>
00030 #include <bgui/bgui_range_adjuster_tableau.h>
00031 #include <bgui/bgui_vsol_soview2D.h>
00032 #include <bgui/bgui_vtol2D_tableau.h>
00033 #include <bgui/bgui_picker_tableau.h>
00034 #include <brip/brip_vil_float_ops.h>
00035 #include <brct/brct_algos.h>
00036 #include <vsol/vsol_point_2d.h>
00037 #include <vsol/vsol_point_3d.h>
00038 #include <vsol/vsol_polygon_2d.h>
00039 #include <vsol/vsol_polygon_3d.h>
00040 #include <vpgl/vpgl_proj_camera.h>
00041 #include <vpgl/algo/vpgl_camera_compute.h>
00042 #include <vpgl/algo/vpgl_optimize_camera.h>
00043 #include <vcl_cassert.h>
00044 
00045 //static live_video_manager instance
00046 bmvv_cal_manager *bmvv_cal_manager::instance_ = 0;
00047 //===============================================================
00048 
00049 //: The singleton pattern - only one instance of the manager can occur
00050 //==============================================================
00051 bmvv_cal_manager *bmvv_cal_manager::instance()
00052 {
00053   if (!instance_)
00054   {
00055     instance_ = new bmvv_cal_manager();
00056     instance_->init();
00057   }
00058   return bmvv_cal_manager::instance_;
00059 }
00060 
00061 //==================================================================
00062 //: constructors/destructor
00063 //==================================================================
00064 bmvv_cal_manager::
00065 bmvv_cal_manager() : vgui_wrapper_tableau(), cam_(vgl_p_matrix<double>()),
00066                      prev_cam_(vgl_p_matrix<double>())
00067 {
00068   corrs_.resize(0);
00069   corrs_valid_.resize(0);
00070   proj_image_pts_.resize(0);
00071   corr_sovs_.resize(0);
00072 }
00073 
00074 bmvv_cal_manager::~bmvv_cal_manager()
00075 {
00076   delete instance_;
00077 }
00078 
00079 //======================================================================
00080 //: set up the tableaux at each grid cell
00081 //  The vtol2D_tableaux have been initialized in the constructor
00082 //======================================================================
00083 void bmvv_cal_manager::init()
00084 {
00085   itab_ = bgui_image_tableau_new();
00086   btab_ = bgui_vtol2D_tableau_new(itab_);
00087   ptab_ = bgui_picker_tableau_new(btab_);
00088   vgui_viewer2D_tableau_sptr vtab =  vgui_viewer2D_tableau_new(ptab_);
00089   vgui_shell_tableau_sptr shell = vgui_shell_tableau_new(vtab);
00090   this->add_child(shell);
00091   height_ = 0.0;
00092 }
00093 
00094 //=========================================================================
00095 //: make an event handler
00096 // Note that we have to get an adaptor and set the tableau to receive events
00097 // this handler does nothing but is a place holder for future event processing
00098 // For now, just pass the events down to the child tableaux
00099 //=========================================================================
00100 bool bmvv_cal_manager::handle(const vgui_event &e)
00101 {
00102   vgui_projection_inspector proj;
00103   if (e.type == vgui_KEY_PRESS)
00104   {
00105     if (btab_)
00106       if (e.key == 'u')
00107       {
00108         btab_->deselect_all();
00109         return true;
00110       }
00111   }
00112   return this->child.handle(e);
00113 }
00114 
00115 //=========================================================================
00116 //: Quit
00117 //=========================================================================
00118 void bmvv_cal_manager::quit()
00119 {
00120   vgui::quit();
00121 }
00122 
00123 //=========================================================================
00124 //: load an image an put it in the currently selected grid cell
00125 //=========================================================================
00126 void bmvv_cal_manager::load_image_file(vcl_string image_filename, bool /* greyscale */)
00127 {
00128   //add greyscale later
00129   img_ = vil_load_image_resource(image_filename.c_str());
00130   if (!img_)
00131   {
00132     vcl_cout << "Null image resource - couldn't load from "
00133              << image_filename << '\n';
00134     return;
00135   }
00136   vgui_range_map_params_sptr rmps = range_params(img_);
00137   if (itab_)
00138   {
00139     itab_->set_image_resource(img_, rmps);
00140     return;
00141   }
00142   vcl_cout << "In bmvv_cal_manager::load_image_file() - null tableau\n";
00143 }
00144 
00145 void bmvv_cal_manager::add_image(vil_image_resource_sptr const& image,
00146                                  vgui_range_map_params_sptr rmps,
00147                                  bool greyscale)
00148 {
00149   if (greyscale)
00150   {
00151 #if 0// do nothing right now
00152     vil1_memory_image_of<unsigned char> temp1 =
00153     brip_vil1_float_ops::convert_to_grey(image);
00154     img_ = temp1;
00155 #endif
00156   }
00157   else
00158     img_ = image;
00159 
00160   if (itab_)
00161   {
00162     itab_->set_image_resource(img_, rmps);
00163     itab_->post_redraw();
00164     return;
00165   }
00166   vcl_cout << "In bmvv_cal_manager::load_image() - null tableau\n";
00167 }
00168 
00169 //=========================================================================
00170 //: load an image an put it in the currently selected grid cell
00171 //=========================================================================
00172 void bmvv_cal_manager::load_image()
00173 {
00174   static bool greyscale = false;
00175   vgui_dialog load_image_dlg("Load Image");
00176   static vcl_string image_filename = "";
00177   static vcl_string ext = "*.*";
00178   load_image_dlg.file("Image Filename:", ext, image_filename);
00179   load_image_dlg.checkbox("greyscale ", greyscale);
00180   if (!load_image_dlg.ask())
00181     return;
00182   vil_image_resource_sptr temp = vil_load_image_resource(image_filename.c_str());
00183   vgui_range_map_params_sptr rmps = range_params(temp);
00184   this->add_image(temp, rmps, greyscale);
00185 }
00186 
00187 void bmvv_cal_manager::save_image()
00188 {
00189   vgui_dialog file_dialog("Save Image");
00190   static vcl_string image_file;
00191   static vcl_string ext = "tif";
00192   static vcl_string type = "tiff";
00193   static bool byte = false;
00194   file_dialog.file("Image Filename:", ext, image_file);
00195   file_dialog.field("Image Format: ", type);
00196   file_dialog.checkbox("Convert to byte image", byte);
00197   if (!file_dialog.ask())
00198     return;
00199   vil_image_resource_sptr img = itab_->get_image_resource();
00200   if (!img)
00201   {
00202     vcl_cerr << "Null image in bmvv_cal_manager::save_image\n";
00203     return;
00204   }
00205   vil_image_resource_sptr save_image = img;
00206   if (byte)
00207   {
00208     vil_image_view<unsigned char> byte_view = brip_vil_float_ops::convert_to_byte(img);
00209     save_image = vil_new_image_resource_of_view(byte_view);
00210   }
00211   if (!vil_save_image_resource(save_image, image_file.c_str(), type.c_str() ))
00212     vcl_cerr << "bmvv_cal_manager::save_image operation failed\n";
00213 }
00214 
00215 void bmvv_cal_manager::adjust_contrast()
00216 {
00217   if (!itab_)
00218     return;
00219   bgui_range_adjuster_tableau_sptr h= bgui_range_adjuster_tableau_new(itab_);
00220   h->set_hardware(true);
00221   h->update();
00222   vgui_viewer2D_tableau_sptr v = vgui_viewer2D_tableau_new(h);
00223   vgui_shell_tableau_sptr s = vgui_shell_tableau_new(v);
00224   //popup adjuster
00225   vgui_dialog contrast("Histogram Range Adjuster");
00226   contrast.inline_tableau(s, 280, 200);
00227   if (!contrast.ask())
00228     return;
00229 }
00230 
00231 //===================================================================
00232 //: Clear the display
00233 //===================================================================
00234 void bmvv_cal_manager::clear_display()
00235 {
00236   if (btab_)
00237     btab_->clear_all();
00238   else
00239     vcl_cout << "In bmvv_cal_manager::clear_display() - null tableau\n";
00240 }
00241 
00242 //===================================================================
00243 //: clear all selections in both panes
00244 //===================================================================
00245 void bmvv_cal_manager::clear_selected()
00246 {
00247   if (btab_)
00248     btab_->clear_all();
00249 }
00250 
00251 void bmvv_cal_manager::draw_corr_point(const float x, const float y)
00252 {
00253   if (!btab_)
00254     return;
00255   btab_->set_point_radius(5.0f);
00256   btab_->set_foreground(0.0f, 1.0f, 0.0f);
00257   btab_->add_point(x, y);
00258   btab_->post_redraw();
00259 }
00260 
00261 
00262 //: Calculate the range parameters for the input image
00263 vgui_range_map_params_sptr bmvv_cal_manager::
00264 range_params(vil_image_resource_sptr const& image)
00265 {
00266   float gamma = 1.0;
00267   bool invert = false;
00268   bool gl_map = false;
00269   bool cache = true;
00270   unsigned min = 0, max = 255;
00271   if (image->pixel_format()==VIL_PIXEL_FORMAT_BYTE)
00272   {
00273     vil_image_view<unsigned char> temp = image->get_view();
00274     unsigned char vmin=0, vmax=255;
00275     vil_math_value_range<unsigned char>(temp, vmin, vmax);
00276     min = static_cast<unsigned>(vmin);
00277     max = static_cast<unsigned>(vmax);
00278     return  new vgui_range_map_params(min, max, gamma, invert,
00279                                       gl_map, cache);
00280   }
00281   if (image->pixel_format()==VIL_PIXEL_FORMAT_UINT_16)
00282   {
00283     vil_image_view<unsigned short> temp = image->get_view();
00284     unsigned short vmin=0, vmax=60000;
00285     vil_math_value_range<unsigned short>(temp, vmin, vmax);
00286     min = static_cast<unsigned>(vmin);
00287     max = static_cast<unsigned>(vmax);
00288     gl_map = true;
00289     return  new vgui_range_map_params(min, max, gamma, invert,
00290                                       gl_map, cache);
00291   }
00292 vcl_cout << "Image pixel format not handled\n";
00293  return new vgui_range_map_params(0, 255, gamma, invert,
00294                                   gl_map, cache);
00295 }
00296 
00297 void bmvv_cal_manager::set_range_params()
00298 {
00299   if (!itab_||!itab_->get_image_resource())
00300     return;
00301   static double min = 0.0, max = 255;
00302   static float gamma = 1.0;
00303   static bool invert = false;
00304   static bool gl_map = false;
00305   static bool cache = false;
00306   vgui_dialog range_dlg("Set Range Map Params");
00307   range_dlg.field("Range min:", min);
00308   range_dlg.field("Range max:", max);
00309   range_dlg.field("Gamma:", gamma);
00310   range_dlg.checkbox("Invert:", invert);
00311   range_dlg.checkbox("Use GL Mapping", gl_map);
00312   range_dlg.checkbox("Cache Pixels", cache);
00313   if (!range_dlg.ask())
00314     return;
00315   vil_image_resource_sptr img = itab_->get_image_resource();
00316   unsigned n_components = img->nplanes();
00317   vgui_range_map_params_sptr rmps;
00318   if (n_components == 1)
00319     rmps= new vgui_range_map_params(min, max, gamma, invert,
00320                                     gl_map, cache);
00321   else if (n_components == 3)
00322     rmps = new vgui_range_map_params(min, max, min, max, min, max,
00323                                      gamma, gamma, gamma, invert,
00324                                      gl_map, cache);
00325   else
00326     rmps = 0;
00327   itab_->set_mapping(rmps);
00328 }
00329 
00330 void bmvv_cal_manager::load_image_and_camera()
00331 {
00332   static bool greyscale = false;
00333   static vcl_string cam_file = "";
00334   static vcl_string cam_ext = "*.cam";
00335   static vcl_string image_file = "";
00336   static vcl_string ext = "*.*";
00337   vgui_dialog image_cam_dlg("Read Image and Cam");
00338   image_cam_dlg.file("Image Filename:", ext, image_file);
00339   image_cam_dlg.file("Camera File", cam_ext, cam_file);
00340   image_cam_dlg.checkbox("greyscale ", greyscale);
00341   if (!image_cam_dlg.ask())
00342     return;
00343   vil_image_resource_sptr temp = vil_load_image_resource(image_file.c_str());
00344   vgui_range_map_params_sptr rmps = range_params(temp);
00345   this->add_image(temp, rmps, greyscale);
00346   vcl_ifstream cam_istr(cam_file.c_str());
00347   cam_istr >> cam_;
00348   vcl_cout << "Read Camera " << cam_ << '\n';
00349   this->project_world();
00350 }
00351 
00352 void bmvv_cal_manager::load_corrs()
00353 {
00354   vgui_dialog corr_dlg("Load Correspondences");
00355   static vcl_string corr_file = "";
00356   static vcl_string corr_ext = "*.cm";
00357   corr_dlg.file("Correspondence File", corr_ext, corr_file);
00358   if (!corr_dlg.ask())
00359     return;
00360   vcl_ifstream corr_istr(corr_file.c_str());
00361   this->clear_correspondences();
00362   world_.clear();
00363   world_.resize(0);
00364   if (!brct_algos::read_target_corrs(corr_istr, corrs_valid_, corrs_, world_))
00365   {
00366     vcl_cout << "Failed to read correspondences\n";
00367     return ;
00368   }
00369   if (!btab_)
00370     return;
00371   btab_->clear_all();
00372   this->project_world();
00373   //  this->draw_correspondences();
00374 }
00375 
00376 void bmvv_cal_manager::save_corrs()
00377 {
00378   vgui_dialog corr_dlg("Save Correspondences");
00379   static vcl_string corr_file = "";
00380   static vcl_string corr_ext = "*.cm";
00381   corr_dlg.file("Correspondence File", corr_ext, corr_file);
00382   if (!corr_dlg.ask())
00383     return;
00384   vcl_ofstream corr_ostr(corr_file.c_str());
00385   if (!brct_algos::write_corrs(corr_ostr, corrs_valid_, corrs_, world_))
00386   {
00387     vcl_cout << "Failed to write correspondences\n";
00388     return ;
00389   }
00390 }
00391 
00392 void bmvv_cal_manager::save_camera()
00393 {
00394   vgui_dialog cam_dlg("Save Camera");
00395   static vcl_string cam_file = "";
00396   static vcl_string cam_ext = "*.cam";
00397   static bool target = false;
00398   cam_dlg.file("Camera File", cam_ext, cam_file);
00399   cam_dlg.checkbox("Target?", target);
00400   if (!cam_dlg.ask())
00401     return;
00402   vcl_ofstream cam_ostr(cam_file.c_str());
00403   if (!cam_ostr)
00404   {
00405     vcl_cout << "Bad camera file\n";
00406     return;
00407   }
00408   if (!target) {
00409     cam_ostr << cam_;
00410     cam_ostr.close();
00411     return;
00412   }
00413   brct_algos::write_target_camera(cam_ostr, cam_.get_matrix());
00414 }
00415 
00416 void bmvv_cal_manager::set_identity_camera()
00417 {
00418   vnl_matrix_fixed<double,3,4> M;
00419   M[0][0] = 1.0;   M[0][1] = 0.0; M[0][2] = 0.0; M[0][3] = 0.0;
00420   M[1][0] = 0.0;   M[1][1] = 1.0; M[1][2] = 0.0; M[1][3] = 0.0;
00421   M[2][0] = 0.0;   M[2][1] = 0.0; M[2][2] = 0.0; M[2][3] = 1.0;
00422   cam_ = vgl_p_matrix<double>(M);
00423 }
00424 
00425 void bmvv_cal_manager::load_world()
00426 {
00427   vgui_dialog world_dlg("Load World Points3D");
00428   static vcl_string world_file = "";
00429   static vcl_string world_ext = "*.wd";
00430   world_dlg.file("World Point File", world_ext, world_file);
00431   if (!world_dlg.ask())
00432     return;
00433   vcl_ifstream world_istr(world_file.c_str());
00434   this->clear_correspondences();
00435   this->clear_world();
00436   if (!brct_algos::read_world(world_istr, world_, polys_, indexed_face_set_))
00437   {
00438     vcl_cout << "Failed to read world\n";
00439     return ;
00440   }
00441   //add polygons
00442   if (!btab_)
00443     return;
00444   btab_->clear();
00445   //make sure the correspondence point array is the same size as the world
00446   int n = world_.size();
00447   corrs_.resize(n, vgl_point_2d<double>(0,0));
00448   corr_sovs_.resize(n, (vgui_soview2D_point*)0);
00449   corrs_valid_.resize(n, false);
00450   this->project_world();
00451 }
00452 
00453 void bmvv_cal_manager::save_world()
00454 {
00455   vgui_dialog world_dlg("Save World");
00456   static vcl_string world_file = "";
00457   static vcl_string world_ext = "*.wd";
00458   world_dlg.file("World File", world_ext, world_file);
00459   if (!world_dlg.ask())
00460     return;
00461   vcl_ofstream world_ostr(world_file.c_str());
00462   brct_algos::write_world(world_ostr, world_, indexed_face_set_);
00463 }
00464 
00465 void bmvv_cal_manager::save_world_ply2()
00466 {
00467   vgui_dialog world_dlg("Save World Ply2");
00468   static vcl_string world_file = "";
00469   static vcl_string world_ext = "*.ply2";
00470   world_dlg.file("Ply2 File", world_ext, world_file);
00471   if (!world_dlg.ask())
00472     return;
00473   vcl_ofstream world_ostr(world_file.c_str());
00474   brct_algos::write_world_ply2(world_ostr, world_, indexed_face_set_);
00475 }
00476 
00477 bool bmvv_cal_manager::draw_correspondences()
00478 {
00479   if (!btab_)
00480     return false;
00481   btab_->set_point_radius(5.0f);
00482   btab_->set_foreground(0.0f, 1.0f, 1.0f);
00483   unsigned i = 0;
00484   for (vcl_vector<vgl_point_2d<double> >::iterator pit = corrs_.begin();
00485        pit != corrs_.end(); ++pit, ++i)
00486     if (corrs_valid_[i])
00487       corr_sovs_.push_back(btab_->add_point(float((*pit).x()), float((*pit).y())));
00488     else
00489       corr_sovs_.push_back((vgui_soview2D_point*)0);
00490   btab_->post_redraw();
00491   return true;
00492 }
00493 
00494 void bmvv_cal_manager::read_world_ply2()
00495 {
00496   vgui_dialog world_dlg("Read World Ply2");
00497   static vcl_string world_file = "";
00498   static vcl_string world_ext = "*.ply2";
00499   world_dlg.file("Ply2 File", world_ext, world_file);
00500   if (!world_dlg.ask())
00501     return;
00502   vcl_ifstream world_istr(world_file.c_str());
00503   brct_algos::read_world_ply2(world_istr, world_, polys_, indexed_face_set_);
00504   this->project_world();
00505 }
00506 
00507 void bmvv_cal_manager::clear_correspondences()
00508 {
00509   if (!btab_)
00510     return;
00511   btab_->clear_all();
00512   corrs_.clear();
00513   corr_sovs_.clear();
00514   corrs_valid_.clear();
00515   corrs_.resize(0);
00516   corrs_valid_.resize(0);
00517   corr_sovs_.resize(0);
00518 }
00519 
00520 bool bmvv_cal_manager::draw_projected_world_points()
00521 {
00522   if (!btab_)
00523     return false;
00524   int i = 0;
00525   point_3d_map_.clear();
00526   btab_->set_point_radius(5.0f);
00527   btab_->set_foreground(1.0f, 1.0f, 0.2f);
00528   for (vcl_vector<vgl_point_2d<double> >::iterator pit = proj_image_pts_.begin();
00529        pit != proj_image_pts_.end(); pit++, ++i)
00530   {
00531     vgui_soview2D_point* sov = btab_->add_point(float((*pit).x()), float((*pit).y()));
00532     int id = sov->get_id();
00533     point_3d_map_[id]=i;
00534   }
00535   btab_->post_redraw();
00536   return true;
00537 }
00538 
00539 
00540 int  bmvv_cal_manager::get_selected_proj_world_pt(vgl_point_2d<double>&  pt)
00541 {
00542   if (!btab_)
00543     return  -1;
00544   vcl_vector<unsigned> ids = btab_->get_selected();
00545   //take the last selected
00546   int n = ids.size();
00547   if (!n)
00548   {
00549     vcl_cout << "Nothing selected\n";
00550     return -1;
00551   }
00552   unsigned int i = point_3d_map_[ids[n-1]];
00553   if (i<proj_image_pts_.size())
00554   {
00555     pt =  proj_image_pts_[i];
00556     return i;
00557   }
00558   vcl_cout << "Bogus correspondence\n";
00559   return -1;
00560 }
00561 
00562 void bmvv_cal_manager::pick_correspondence()
00563 {
00564   if (!world_.size())
00565   {
00566     vcl_cout << "Can't pick correspondence - null 3D world\n";
00567     return;
00568   }
00569   vgl_point_2d<double> pt;
00570   int id = this->get_selected_proj_world_pt(pt);
00571   if (id<0)
00572     return;
00573   vcl_cout << "Projected world point " << pt << '\n';
00574   if (!ptab_)
00575   {
00576     vcl_cout << "Can't pick correspondence - null picker tableau\n";
00577     return;
00578   }
00579   ptab_->set_color(0.0f, 1.0f, 1.0f);
00580   ptab_->set_line_width(3.0f);
00581   float x, y;
00582   ptab_->anchored_pick_point(float(pt.x()), float(pt.y()), &x, &y);
00583   corrs_[id].set(x, y);
00584   corrs_valid_[id]=true;
00585   ptab_->set_color();//restore defaults
00586   ptab_->set_line_width();
00587 
00588   if (!btab_)
00589     return;
00590   btab_->set_foreground(0.0f, 1.0f, 1.0f);
00591   btab_->set_point_radius(5.0);
00592   if (!corr_sovs_[id])
00593     corr_sovs_[id]=btab_->add_point(x, y);
00594   else {
00595     corr_sovs_[id]->x = x;
00596     corr_sovs_[id]->y = y;
00597   }
00598   btab_->post_redraw();
00599 }
00600 
00601 void bmvv_cal_manager::remove_correspondence()
00602 {
00603   if (!world_.size())
00604   {
00605     vcl_cout << "Can't remove correspondence - null 3D world\n";
00606     return;
00607   }
00608   vgl_point_2d<double> pt;
00609   int id = this->get_selected_proj_world_pt(pt);
00610   if (id<0)
00611     return;
00612   corrs_[id].set(0, 0);
00613   corrs_valid_[id]=false;
00614   corr_sovs_[id]=(vgui_soview2D_point*)0;
00615   if (!btab_)
00616   {
00617     vcl_cout << "Correspondence removal aborted in progress- null btab\n";
00618     return;
00619   }
00620   this->project_world();
00621   //  this->draw_correspondences();
00622 }
00623 
00624 void bmvv_cal_manager::pick_vertical()
00625 {
00626   ptab_->set_color(0.0f, 1.0f, 0.0f);
00627   ptab_->set_line_width(3.0f);
00628   float x1, y1,x2, y2;
00629   ptab_->pick_line(&x1, &y1, &x2, &y2);
00630   vgl_point_2d<double> p1(x1, y1), p2(x2,y2);
00631   vgl_line_segment_2d<double> vertical(p1, p2);
00632   verticals_.push_back(vertical);
00633   ptab_->set_color();//restore defaults
00634   ptab_->set_line_width();
00635   if (!btab_)
00636     return;
00637   btab_->set_foreground(0.0f, 1.0f, 0.0f);
00638   btab_->add_line(x1,y1,x2,y2);
00639   btab_->post_redraw();
00640 }
00641 
00642 void bmvv_cal_manager::project_world()
00643 {
00644   if (!btab_)
00645   {
00646     vcl_cout << "Can't project world - null btab\n";
00647     return;
00648   }
00649   btab_->clear_all();
00650   brct_algos::project(world_, cam_, proj_image_pts_);
00651   this->draw_projected_world_points();
00652   this->draw_polygons_3d(false, 0.0f, 1.0f, 0.0f);
00653   this->draw_correspondences();
00654 }
00655 
00656 namespace
00657 {
00658 //: function to roughly flip the camera around a set of points when the points are behind the camera.
00659 //   Optimization is needed after this operation.
00660 void flip_camera(vpgl_perspective_camera<double> &camera,
00661                  const vcl_vector< vgl_homg_point_3d<double> >& world_hpts)
00662 {
00663   vgl_vector_3d<double> centroid(0.0, 0.0, 0.0);
00664   unsigned int num_behind = 0;
00665   for (unsigned i = 0; i<world_hpts.size(); ++i){
00666     if (camera.is_behind_camera(world_hpts[i])){
00667       vgl_point_3d<double> p(world_hpts[i]);
00668       centroid += vgl_vector_3d<double>(p.x(),p.y(),p.z());
00669       ++num_behind;
00670     }
00671   }
00672   centroid /= num_behind;
00673 
00674   vgl_point_3d<double> C = camera.get_camera_center();
00675   vcl_cout << "initial center: "<< C<<vcl_endl;
00676   C += 2*(vgl_point_3d<double>(centroid.x(),centroid.y(),centroid.z())-C);
00677   camera.set_camera_center(C);
00678   vcl_cout << "new center: " <<C<<vcl_endl;
00679 }
00680 
00681 }; // namespace
00682 
00683 void bmvv_cal_manager::solve_camera()
00684 {
00685   static bool planar = false;
00686   static bool deg_planar = false;
00687   static bool optimize = true;
00688   static bool restore = false;
00689   vgui_dialog read_homg_dlg("Solve Camera");
00690   read_homg_dlg.checkbox("Planar Camera Only? ", planar);
00691   read_homg_dlg.checkbox("Mostly Planar Camera? ", deg_planar);
00692   read_homg_dlg.checkbox("Optimize? ", optimize);
00693   read_homg_dlg.checkbox("Restore Previous Camera? ", restore);
00694   if (!read_homg_dlg.ask())
00695     return;
00696   if (restore)
00697   {
00698     cam_=prev_cam_;
00699     return;
00700   }
00701 
00702   if (planar || deg_planar)
00703   {
00704     vcl_vector<double> image_y;
00705     vcl_vector< vgl_point_2d<double> > zero_Z_image_corr;
00706     vcl_vector< vgl_point_3d<double> > zero_Z_pts;
00707     vcl_vector< vgl_point_3d<double> > non_zero_Z_pts;
00708     unsigned int n = world_.size();
00709     for (unsigned i = 0; i<n; i++)
00710     {
00711       if (!corrs_valid_[i])
00712         continue;
00713       if (vcl_fabs(world_[i].z()) < 0.01) //planar points
00714       {
00715         zero_Z_pts.push_back(world_[i]);
00716         zero_Z_image_corr.push_back(corrs_[i]);
00717       }
00718       else // non-planar point for camera elevation constraint
00719       {
00720         image_y.push_back(corrs_[i].y());
00721         non_zero_Z_pts.push_back(world_[i]);
00722       }
00723     }
00724     vgl_h_matrix_2d<double> H;
00725     if (!brct_algos::homography(zero_Z_pts, zero_Z_image_corr, H, optimize))
00726     {
00727       vcl_cout << "Linear SVD solve for homography failed\n";
00728       return;
00729     }
00730     //protect from bad solution by saving old camera
00731     prev_cam_ = cam_;
00732     if (!planar)
00733       cam_= brct_algos::p_from_h(H,image_y, non_zero_Z_pts);
00734     else
00735       cam_= brct_algos::p_from_h(H);
00736   }
00737   else
00738   {
00739     vcl_vector< vgl_homg_point_2d<double> > image_hpts;
00740     vcl_vector< vgl_homg_point_3d<double> > world_hpts;
00741     unsigned int n = world_.size();
00742     for (unsigned i = 0; i<n; i++)
00743     {
00744       if (!corrs_valid_[i])
00745         continue;
00746       image_hpts.push_back(vgl_homg_point_2d<double>(corrs_[i]));
00747       world_hpts.push_back(vgl_homg_point_3d<double>(world_[i]));
00748     }
00749     vpgl_proj_camera<double> camera;
00750     vpgl_proj_camera_compute::compute(image_hpts,world_hpts,camera);
00751     prev_cam_ = cam_;
00752     cam_ = vgl_p_matrix<double>(camera.get_matrix());
00753 
00754     vpgl_perspective_camera<double> p_camera;
00755     if (optimize && vpgl_perspective_decomposition(camera.get_matrix(),p_camera)){
00756       vcl_vector< vgl_point_2d<double> > image_pts;
00757       unsigned int num_behind = 0;
00758       for (unsigned i = 0; i<image_hpts.size(); i++){
00759         if (p_camera.is_behind_camera(world_hpts[i]))
00760           ++num_behind;
00761         image_pts.push_back(image_hpts[i]);
00762       }
00763       if (num_behind > world_hpts.size()/2){
00764         vcl_cout << "Majority of points behind camera, flipping" << vcl_endl;
00765         flip_camera(p_camera, world_hpts);
00766       }
00767       p_camera = vpgl_optimize_camera::opt_orient_pos_cal(p_camera, world_hpts, image_pts);
00768       cam_ = vgl_p_matrix<double>(p_camera.get_matrix());
00769     }
00770   }
00771 
00772   if (!btab_)
00773     return;
00774   btab_->clear_all();
00775   this->project_world();
00776   //this->draw_correspondences();
00777 }
00778 
00779 
00780 void bmvv_cal_manager::
00781 draw_vsol_points(const int cam, vcl_vector<vsol_point_2d_sptr> const & points,
00782                  bool clear, const float r, const float g, const float b)
00783 {
00784   if (!btab_)
00785   {
00786     vcl_cout << "In bmvv_cal_manager::draw_vsol_points(..) -"
00787              << " null btol tableau for pane " << cam << vcl_endl;
00788     return;
00789   }
00790   if (clear)
00791     btab_->clear_all();
00792   vgui_style_sptr style = vgui_style::new_style(r, g, b, 3, 0);
00793   for (vcl_vector<vsol_point_2d_sptr>::const_iterator pit = points.begin();
00794        pit != points.end(); pit++)
00795     btab_->add_vsol_point_2d(*pit, style);
00796 }
00797 
00798 void bmvv_cal_manager::
00799 draw_vsol_point(const int cam, vsol_point_2d_sptr const & point,
00800                 bool clear, const float r, const float g, const float b)
00801 {
00802   if (!btab_)
00803   {
00804     vcl_cout << "In bmvv_cal_manager::draw_vsol_point(..) -"
00805              << " null btol tableau for pane " << cam << vcl_endl;
00806     return;
00807   }
00808   if (clear)
00809     btab_->clear_all();
00810   vgui_style_sptr style = vgui_style::new_style(r, g, b, 3, 0);
00811   btab_->add_vsol_point_2d(point,style);
00812 }
00813 
00814 
00815 void bmvv_cal_manager::compute_ransac_homography()
00816 {
00817   vgui_dialog read_homg_dlg("Read Correspondence File");
00818   static vcl_string corr_filename = "";
00819   static vcl_string corr_ext = "*.cm";
00820   static vcl_string cam_filename = "";
00821   static vcl_string cam_ext = "*.cam";
00822   static bool show_projected_points = true;
00823   static bool optimize = true;
00824   vcl_vector<vcl_string> choices;
00825   static int choice=0;
00826   choices.push_back("Linear SVD");
00827   choices.push_back("RANSAC");
00828   choices.push_back("MUSE");
00829   read_homg_dlg.file("TargetJr correspondence file", corr_ext, corr_filename);
00830   read_homg_dlg.file("TargetJr camera file", cam_ext, cam_filename);
00831   read_homg_dlg.checkbox("Show Projected Points ",show_projected_points);
00832   read_homg_dlg.choice("Homography Algo.", choices, choice);
00833   read_homg_dlg.checkbox("Optimize? ", optimize);
00834   if (!read_homg_dlg.ask())
00835     return;
00836   if (corr_filename == ""||cam_filename == "")
00837   {
00838     vcl_cout << "Need a file name\n";
00839     return;
00840   }
00841 
00842   this->clear_display();
00843   vcl_ifstream istr(corr_filename.c_str());
00844   vcl_ofstream ostr(cam_filename.c_str());
00845   vcl_string target_file = cam_filename + "-target";
00846   vcl_ofstream ostr_tar(target_file.c_str());
00847   vcl_vector<bool> valid;
00848   vcl_vector<vgl_point_2d<double> > image_points;
00849   vcl_vector<vgl_point_3d<double> > world_points;
00850   if (!brct_algos::read_target_corrs(istr, valid, image_points, world_points))
00851   {
00852     vcl_cout << "Failed to read correspondences\n";
00853     return;
00854   }
00855   bool show = show_projected_points;
00856   // compute the homography using ransac
00857   vgl_h_matrix_2d<double> H;
00858   switch (choice)
00859   {
00860    case 0:
00861     if (!brct_algos::homography(world_points, image_points, H, optimize))
00862       show = false;
00863     break;
00864    case 1:
00865     if (!brct_algos::homography_ransac(world_points, image_points, H, optimize))
00866       show = false;
00867     break;
00868    case 2:
00869     if (!brct_algos::homography_muse(world_points, image_points, H, optimize))
00870       show = false;
00871     break;
00872    default:
00873     assert(!"choice should be one of 0, 1, or 2");
00874   }
00875   vcl_vector<vgl_point_2d<double> > proj_image_points;
00876   vgl_p_matrix<double> P =  brct_algos::p_from_h(H);
00877   brct_algos::project(world_points, P, proj_image_points);
00878 
00879   if (!btab_)
00880     return;
00881   vgui_style_sptr r_style = vgui_style::new_style(1.0, 0.0, 0.0, 5, 0);
00882   vgui_style_sptr g_style = vgui_style::new_style(0.0, 1.0, 0.0, 5, 0);
00883   for (unsigned int i = 0; i<world_points.size(); i++)
00884   {
00885     vgl_point_2d<double> ip = image_points[i];
00886     vgl_point_2d<double> pip = proj_image_points[i];
00887     vsol_point_2d_sptr vip = new vsol_point_2d(ip.x(),ip.y());
00888     vsol_point_2d_sptr vpip = new vsol_point_2d(pip.x(),pip.y());
00889     vcl_cout << ip << " == " << pip << vcl_endl;
00890     btab_->add_vsol_point_2d(vip,r_style);
00891     if (show) btab_->add_vsol_point_2d(vpip,g_style);
00892   }
00893   btab_->post_redraw();
00894 
00895   //write out the camera
00896   ostr << P;
00897   //Also as a target camera for interest sake
00898   brct_algos::write_target_camera(ostr_tar, P.get_matrix());
00899 }
00900 
00901 //map the image back to cartesian world coordinates
00902 void bmvv_cal_manager::map_image_to_world()
00903 {
00904   vil_image_resource_sptr img = itab_->get_image_resource();
00905   if (!img)
00906     return;
00907   vil_image_resource_sptr world_image =
00908     brct_algos::map_image_to_world(img, cam_);
00909   if (world_image)
00910   {
00911     vgui_range_map_params_sptr rmps = range_params(world_image);
00912     this->add_image(world_image, rmps);
00913   }
00914 }
00915 
00916 void bmvv_cal_manager::save_constraints()
00917 {
00918   vgui_dialog cnst_dlg("Save Constraints");
00919   static vcl_string con_file = "";
00920   static vcl_string con_ext = "*.con";
00921   cnst_dlg.file("Constraint File", con_ext, con_file);
00922   if (!cnst_dlg.ask())
00923     return;
00924   vcl_ofstream con_ostr(con_file.c_str());
00925   if (!con_ostr)
00926   {
00927     vcl_cout << "Bad constraint file\n";
00928     return;
00929   }
00930   if (!brct_algos::save_constraint_file(corrs_, corrs_valid_, world_, verticals_, con_ostr))
00931   {
00932     vcl_cout << "Couldn't save constraints\n";
00933     return;
00934   }
00935 }
00936 
00937 // add polygon vertices as world points to enable correspondence for
00938 // additional camera constraints.
00939 void bmvv_cal_manager::add_poly_vertices_to_world_pts(vsol_polygon_3d_sptr const& poly)
00940 {
00941   unsigned nv = poly->size();
00942   vcl_vector<unsigned> vert_indices(nv);
00943   for (unsigned i = 0; i<nv; ++i)
00944   {
00945     vsol_point_3d_sptr v3d = poly->vertex(i);
00946     vgl_point_3d<double> p(v3d->x(), v3d->y(), v3d->z());
00947     world_.push_back(p);
00948     vert_indices[i]=world_.size()-1;
00949   }
00950   indexed_face_set_.push_back(vert_indices);
00951 }
00952 
00953 // Add the most recently created polygon to the world
00954 void bmvv_cal_manager::confirm_polygon()
00955 {
00956   if (!new_poly_)
00957     return;
00958   add_poly_vertices_to_world_pts(new_poly_);
00959   polys_.push_back(new_poly_);
00960   this->project_world();
00961 }
00962 
00963 void bmvv_cal_manager::pick_polygon()
00964 {
00965   vsol_polygon_2d_sptr poly;
00966   ptab_->pick_polygon(poly);
00967   new_poly_ = brct_algos::back_project(poly, cam_, height_);
00968   this->draw_vsol_polygon_3d(new_poly_, false, 1.0f, 0.0f, 1.0f);
00969   btab_->post_redraw();
00970 }
00971 
00972 void bmvv_cal_manager::draw_vsol_polygon_3d(vsol_polygon_3d_sptr const & poly,
00973                                             bool clear,
00974                                             const float r,
00975                                             const float g,
00976                                             const float b)
00977 {
00978   if (!btab_)
00979   {
00980     vcl_cerr << "In bmvv_cal_manager::draw_vsol_polygon() - null btol tableau\n";
00981     return;
00982   }
00983   if (clear)
00984     btab_->clear_all();
00985   vsol_polygon_2d_sptr poly_2d = brct_algos::project(poly,cam_);
00986   vgui_style_sptr style = vgui_style::new_style(r, g, b, 1, 3);
00987   bgui_vsol_soview2D_polygon* sov =  btab_->add_vsol_polygon_2d(poly_2d,style);
00988   sov->set_selectable(false);
00989 }
00990 
00991 void bmvv_cal_manager::draw_polygons_3d(bool clear,
00992                                         const float r,
00993                                         const float g,
00994                                         const float b)
00995 {
00996   if (clear)
00997     btab_->clear_all();
00998   for (vcl_vector<vsol_polygon_3d_sptr>::iterator pit = polys_.begin();
00999        pit != polys_.end(); ++pit)
01000     this->draw_vsol_polygon_3d(*pit, false, r, g, b);
01001 }
01002 
01003 //Create a box in the world from three top face corner points
01004 void bmvv_cal_manager::create_box()
01005 {
01006   //the polygon must have exactly 3 vertices
01007   vsol_polygon_2d_sptr poly;
01008   ptab_->pick_polygon(poly);
01009   if (!poly||poly->size()!=3)
01010   {
01011     vcl_cout << "bad box corner pick\n";
01012     return;
01013   }
01014   vsol_polygon_3d_sptr top = brct_algos::back_project(poly, cam_, height_);
01015   vsol_point_3d_sptr p0=top->vertex(0), p1=top->vertex(1), p2=top->vertex(2);
01016   vgl_point_3d<double> c0(p0->x(), p0->y(), p0->z());
01017   vgl_point_3d<double> c1(p1->x(), p1->y(), p1->z());
01018   vgl_point_3d<double> c2(p2->x(), p2->y(), p2->z());
01019 
01020   vcl_vector<vgl_point_3d<double> > points;
01021   vcl_vector<vsol_polygon_3d_sptr> polys;
01022   vcl_vector<vcl_vector<unsigned> > indexed_face_set;
01023   brct_algos::box_3d(c0, c1, c2, points, polys, indexed_face_set);
01024 
01025   unsigned vi0 = world_.size();//starting index for new points
01026   for (vcl_vector<vgl_point_3d<double> >::iterator pt = points.begin();
01027        pt != points.end(); ++pt)
01028     world_.push_back(*pt);
01029 
01030   for (vcl_vector<vsol_polygon_3d_sptr>::iterator pl = polys.begin();
01031        pl != polys.end(); ++pl)
01032     polys_.push_back(*pl);
01033 
01034   for (vcl_vector<vcl_vector<unsigned> >::iterator ifs=indexed_face_set.begin();
01035        ifs != indexed_face_set.end(); ++ifs)
01036   {
01037     vcl_vector<unsigned> vi = *ifs;
01038     vcl_vector<unsigned> index(4);
01039     for (unsigned i = 0; i<4; ++i)
01040       index[i] = vi[i]+vi0;
01041     indexed_face_set_.push_back(index);
01042   }
01043   this->project_world();
01044 }
01045 
01046 //Convert boxes in a merged indexed face set to individual boxes in VRML
01047 void bmvv_cal_manager::ply2_to_vrml()
01048 {
01049   static float r = 0.0, g = 0.8f, b = 0.2f;
01050   vgui_dialog trans_dlg("Ply2 to VRML2.0");
01051   static vcl_string ply2_file = "";
01052   static vcl_string ply2_ext = "*.ply2";
01053   trans_dlg.file("Ply2 File", ply2_ext, ply2_file);
01054   static vcl_string vrml_file = "";
01055   static vcl_string vrml_ext = "*.wrl";
01056   trans_dlg.file("VRML File", vrml_ext, vrml_file);
01057   trans_dlg.field("r ", r);
01058   trans_dlg.field("g ", g);
01059   trans_dlg.field("b ", b);
01060   if (!trans_dlg.ask())
01061     return;
01062   vcl_ifstream istr(ply2_file.c_str());
01063   vcl_ofstream ostr(vrml_file.c_str());
01064   if (!brct_algos::translate_ply2_to_vrml(istr, ostr, r, g, b))
01065     vcl_cout << "Convert Ply to VRML Failed\n";
01066 }
01067 
01068 //Set the height of the X-Y create plane
01069 void bmvv_cal_manager::set_height()
01070 {
01071   static double height = 0.0;
01072   vgui_dialog box_dlg("Create Plane Z");
01073   box_dlg.field("Plane Z", height);
01074   if (!box_dlg.ask())
01075     return;
01076   height_ = height;
01077 }
01078 
01079 void bmvv_cal_manager::clear_world()
01080 {
01081   world_.clear();
01082   world_.resize(0);
01083   polys_.clear();
01084   polys_.resize(0);
01085   indexed_face_set_.clear();
01086   indexed_face_set_.resize(0);
01087   this->project_world();
01088 }