stitcher.cpp
Go to the documentation of this file.
00001 /*
00002  * detector.cpp
00003  *
00004  *  Created on: Nov 17, 2010
00005  *      Author: erublee
00006  */
00007 #include <boost/foreach.hpp>
00008 #include <boost/program_options.hpp>
00009 
00010 #include <opencv2/opencv.hpp>
00011 #include <opencv2/legacy/legacy.hpp>
00012 
00013 #include <iostream>
00014 #include <fstream>
00015 #include <list>
00016 #include <string>
00017 
00018 #include <pano_core/pano_core.h>
00019 #define DONT_USE_ROS 1
00020 #if !DONT_USE_ROS
00021 #include <ros/ros.h>
00022 
00023 #define LOGI ROS_INFO
00024 #define LOGI_STREAM(x) ROS_INFO_STREAM(x)
00025 
00026 #define LOGE ROS_ERROR
00027 #define LOGE_STREAM(x) ROS_ERROR_STREAM(x)
00028 #else
00029 #include <cstdio>
00030 #define  LOG_TAG    "librobotview"
00031 #define  LOGI(...)  printf("info:");printf("%s:",LOG_TAG); printf(__VA_ARGS__);printf("\n");
00032 #define  LOGE(...)  printf("error:");printf(LOG_TAG); printf(__VA_ARGS__);printf("\n");
00033 #define  LOGI_STREAM(x)  {std::stringstream ss; ss << x; LOGI("%s",ss.str().c_str());}
00034 #define  LOGE_STREAM(x)  {std::stringstream ss; ss << x; LOGE("%s",ss.str().c_str());}
00035 #endif
00036 
00037 
00038 using namespace pano;
00039 using namespace std;
00040 using namespace cv;
00041 
00042 #define foreach         BOOST_FOREACH
00043 #define reverse_foreach BOOST_REVERSE_FOREACH
00044 
00045 namespace po = boost::program_options;
00046 
00047 namespace
00048 {
00049 struct Options
00050 {
00051   std::string k_file;
00052   std::string d_file;
00053   std::string directory;
00054   std::string stitch_output;
00055   std::vector<std::string> image_names;
00056 };
00057 list<string> getImageList(istream& input)
00058 {
00059   list<string> imlist;
00060   while (!input.eof() && input.good())
00061   {
00062     string imname;
00063     input >> imname;
00064     if (!input.eof() && input.good())
00065       imlist.push_back(imname);
00066   }
00067   return imlist;
00068 }
00069 }
00070 
00071 int options(int ac, char ** av, Options& opts)
00072 {
00073   // Declare the supported options.
00074   po::options_description desc("Allowed options");
00075   desc.add_options()("help", "Produce help message.");
00076   desc.add_options()("intrinsics,K", po::value<string>(&opts.k_file),
00077                      "The camera intrinsics file, should be yaml and have atleast \"K:...\". Required.");
00078   desc.add_options()("distortion,D", po::value<string>(&opts.d_file)->default_value(""),
00079                      "The camera distortion file, should be yaml and have atleast \"D:...\". optional, no distortion assumed if not given.");
00080   desc.add_options()("directory,d", po::value<string>(&opts.directory)->default_value("./"),
00081                      "The directory that the images to stitch are in");
00082   desc.add_options()("stitch_output,o", po::value<string>(&opts.stitch_output)->default_value("stitched.jpg"),
00083                      "the full path to the final stitch image, should have image extension. (.jpg,.png)");
00084   desc.add_options()("images", po::value<vector<string> >(&opts.image_names), "input images.");
00085   po::positional_options_description p;
00086   p.add("images", -1);
00087   po::variables_map vm;
00088   po::store(po::command_line_parser(ac, av). options(desc).positional(p).run(), vm);
00089   po::notify(vm);
00090 
00091   if (vm.count("help"))
00092   {
00093     cout << desc << "\n";
00094     return 1;
00095   }
00096 
00097   if (!vm.count("intrinsics"))
00098   {
00099     cout << "Must supply a camera calibration file" << "\n";
00100     cout << desc << endl;
00101     return 1;
00102   }
00103 
00104   if (!vm.count("images"))
00105   {
00106     cout << "Must supply a list of input images" << "\n";
00107     cout << desc << endl;
00108     return 1;
00109   }
00110   return 0;
00111 
00112 }
00113 struct CanceledException : public std::exception
00114 {
00115   const char * what() const throw ()
00116   {
00117     return "Canceled!";
00118   }
00119 };
00120 class StitchProgressCallable
00121 {
00122 public:
00123   virtual ~StitchProgressCallable()
00124   {
00125   }
00126   virtual int onProgress(int progress)
00127   {
00128     LOGI_STREAM("Stitch Progress:"<< progress);
00129     return 0;
00130   }
00131 };
00132 
00133 bool solve(const std::string& directory, SVDRSolverParams params, Camera camera, std::vector<std::string> image_names,
00134            StitchProgressCallable* callback = NULL)
00135 {
00136   try
00137   {
00138     Ptr<cv::AdjusterAdapter> adapter;
00139     Ptr<FeatureDetector> detector;
00140 
00141     int levels = 2;
00142     detector = new GriddedDynamicDetectorAdaptor(250, 20, levels, levels, FastAdjuster());
00143 
00144     Ptr<SVDFitter> svdfitter(new SVDFitter(params));
00145 
00146     Ptr<ModelFitter> fitter(reinterpret_cast<const Ptr<ModelFitter>&> (svdfitter));
00147 
00148     MoleculeGlob glob; //the glob stores the pano graph, think of it as the map
00149 
00150     vector<ImageAtom> atoms;
00151     vector<Mat> descriptors;
00152     Images images;
00153 
00154     int i = 0;
00155     int t_s = image_names.size();
00156     Mat img;
00157     camera.initUndistort();
00158     while (image_names.size())
00159     {
00160       string imagename = image_names.back();
00161       string imagename_full = directory + "/" + imagename;
00162       LOGI_STREAM("reading " << imagename_full );
00163 
00164       Extrinsics ext(Mat::eye(3, 3, CV_32F), 200);
00165 
00166       camera.undistort(imread(directory + "/" + imagename), img);
00167       images.load(img, imagename, directory);
00168 
00169       atoms.push_back(ImageAtom(camera, images));
00170 
00171       ImageAtom& atom = atoms.back();
00172       atom.setUid(i++);
00173       atom.extrinsics() = ext;
00174       atom.extrinsics().flag(Extrinsics::ESTIMATED) = false;
00175       atom.extrinsics().val(Extrinsics::CONFIDENCE) = 200;
00176       atom.detect(*detector);
00177       atom.extract(BriefDescriptorExtractor(), BruteForceMatcher<Hamming> ());
00178       //  descriptors.push_back(atom.features().descriptors());
00179       LOGI_STREAM( "found " << atom.features().kpts().size());
00180       glob.addAtomToGlob(fitter, atom)->images().clear();
00181 
00182       LOGI_STREAM( "detected and extracted " << i << "/" << t_s );
00183       if (callback)
00184       {
00185         callback->onProgress(int((float(i) / t_s) * 100));
00186       }
00187       image_names.pop_back();
00188     }
00189 
00190     glob.batchFindAndSetTrinsics();
00191     FileStorage fs(directory + "/glob.yaml.gz", FileStorage::WRITE);
00192     fs << "glob";
00193     glob.serialize(fs);
00194   }
00195   catch (CanceledException e)
00196   {
00197     LOGI("Canceled");
00198     return true;
00199   }
00200   catch (...)
00201   {
00202     LOGE("Fail stitch!");
00203     return false;
00204   }
00205   return true;
00206 
00207 }
00208 struct PairFitterCallback
00209 {
00210   int * i;
00211   int total;
00212   int offset;
00213   StitchProgressCallable* callback_;
00214   PairFitterCallback(StitchProgressCallable* callback, int* i, int total, int offset) :
00215     i(i), total(total), offset(offset), callback_(callback)
00216   {
00217   }
00218   template<typename T>
00219     void operator()(const T&)
00220     {
00221       if (callback_)
00222       {
00223         (*i)++;
00224         int progress = (float(*i) / total) * 100 + offset;
00225         callback_->onProgress(progress);
00226       }
00227     }
00228 };
00229 bool stitch(const std::string& pano_directory_name, const std::string& stitch_name, StitchProgressCallable* callback =
00230     NULL)
00231 {
00232   try
00233   {
00234     CallbackEngine cbengine;
00235     string directory = pano_directory_name;
00236     FileStorage fs(directory + "/glob.yaml.gz", FileStorage::READ);
00237 
00238     if (!fs.isOpened())
00239     {
00240       LOGE_STREAM("failed to open : "+ directory + "/glob.yaml.gz");
00241       return false;
00242     }
00243 
00244     MoleculeGlob glob;
00245     glob.deserialize(fs["glob"]);
00246     glob.overideDirectory(directory);
00247 
00248     if (glob.getMolecules().size() < 1)
00249       return false;
00250     LOGI_STREAM("found - " << glob.getMolecules().size() << " molecules");
00251 
00252     Mat blended(Size(4000, 2000), CV_8UC3);
00253 
00254     Ptr<ImageMolecule> molecule;
00255 
00256     molecule = glob.getBiggestMolecule();
00257 
00258     int atom_idx = 0;
00259     cbengine.addCallback<ImageAtom> (0, PairFitterCallback(callback, &atom_idx, molecule->getAtoms().size(), 100));
00260 
00261     LOGI("simple stitching now");
00262     BlenderSimple blender;
00263     blender.cbe = &cbengine;
00264     blender.BlendMolecule(*molecule, blended);
00265 
00266     cbengine.addCallback<int> (0, PairFitterCallback(callback, &atom_idx, 100, 200));
00267     cbengine.callBack(0, 0);
00268     vector<int> write_params(2);
00269     write_params[0] = CV_IMWRITE_JPEG_QUALITY;
00270     write_params[1] = 85; //need low size for emailing
00271 
00272 
00273     imwrite(stitch_name, blended, write_params);
00274   }
00275   catch (CanceledException e)
00276   {
00277     LOGI("Canceled");
00278   }
00279   return true;
00280 }
00281 
00282 int main(int argc, char *argv[])
00283 {
00284   Options opts;
00285   if (options(argc, argv, opts))
00286     return 1;
00287 
00288   Camera camera;
00289   FileStorage fs(opts.k_file, FileStorage::READ);
00290   Mat K;
00291   fs["K"] >> K;
00292   Mat D;
00293   if (opts.d_file.size())
00294   {
00295     FileStorage dfs(opts.d_file, FileStorage::READ);
00296     dfs["D"] >> D;
00297   }
00298   Size sz;
00299   {
00300     Mat image = imread(opts.directory + "/" + opts.image_names[0]);
00301     sz = image.size();
00302   }
00303   camera.setCameraIntrinsics(K, D, sz);
00304 
00305   SVDRSolverParams params;
00306   params.error_thresh = 6;
00307   params.inliers_thresh = 15;
00308   params.maxiters = 100;
00309   params.nNeeded = 2;
00310 
00311   StitchProgressCallable pc;
00312   solve(opts.directory, params, camera, opts.image_names, &pc);
00313   stitch(opts.directory, opts.stitch_output, &pc);
00314 
00315   return 0;
00316 }


pano_core
Author(s): Ethan Rublee
autogenerated on Mon Mar 14 2016 10:56:54