pano_modify.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00013 /*  This program is free software; you can redistribute it and/or
00014  *  modify it under the terms of the GNU General Public
00015  *  License as published by the Free Software Foundation; either
00016  *  version 2 of the License, or (at your option) any later version.
00017  *
00018  *  This software is distributed in the hope that it will be useful,
00019  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00021  *  General Public License for more details.
00022  *
00023  *  You should have received a copy of the GNU General Public
00024  *  License along with this software; if not, write to the Free Software
00025  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026  *
00027  */
00028 
00029 #include <hugin_version.h>
00030 
00031 #include <fstream>
00032 #include <sstream>
00033 #include <getopt.h>
00034 #ifndef WIN32
00035  #include <unistd.h>
00036 #endif
00037 #include <panodata/Panorama.h>
00038 #include <algorithms/nona/CenterHorizontally.h>
00039 #include <algorithms/basic/StraightenPanorama.h>
00040 #include <algorithms/basic/RotatePanorama.h>
00041 #include <algorithms/basic/TranslatePanorama.h>
00042 #include <algorithms/nona/FitPanorama.h>
00043 #include <algorithms/basic/CalculateOptimalScale.h>
00044 #include <algorithms/basic/CalculateOptimalROI.h>
00045 #include <algorithms/basic/LayerStacks.h>
00046 
00047 using namespace std;
00048 using namespace HuginBase;
00049 using namespace AppBase;
00050 
00051 static void usage(const char * name)
00052 {
00053     cout << name << ": change output parameters of project file" << endl
00054          << "pano_modify version " << DISPLAY_VERSION << endl
00055          << endl
00056          << "Usage:  " << name << " [options] input.pto" << endl
00057          << endl
00058          << "  Options:" << endl
00059          << "     -o, --output=file.pto  Output Hugin PTO file. Default: <filename>_mod.pto" << endl
00060          << "     -p, --projection=x     Sets the output projection to number x" << endl
00061          << "     --fov=AUTO|HFOV|HFOVxVFOV   Sets field of view" << endl
00062          << "                                   AUTO: calculates optimal fov" << endl
00063          << "                                   HFOV|HFOVxVFOV: set to given fov" << endl
00064          << "     -s, --straighten       Straightens the panorama" << endl
00065          << "     -c, --center           Centers the panorama" << endl
00066          << "     --canvas=AUTO|num%|WIDTHxHEIGHT  Sets the output canvas size" << endl
00067          << "                                   AUTO: calculate optimal canvas size" << endl
00068          << "                                   num%: scales the optimal size by given percent" << endl
00069          << "                                   WIDTHxHEIGHT: set to given size" << endl
00070          << "     --crop=AUTO|AUTOHDR|left,right,top,bottom  Sets the crop rectangle" << endl
00071          << "                                   AUTO: autocrop panorama" << endl
00072          << "                                   AUTOHDR: autocrop HDR panorama" << endl
00073          << "                                   left,right,top,bottom: to given size" << endl
00074          << "     --rotate=yaw,pitch,roll  Rotates the whole panorama with the given angles" << endl
00075          << "     --translate=x,y,z        Translate the whole panorama with the given values" << endl
00076          << "     -h, --help             Shows this help" << endl
00077          << endl;
00078 }
00079 
00080 // toupper is overloaded in <locale>, but we want to use it as a unary function.
00081 inline char toupper_2(char c)
00082 {
00083     return toupper(c);
00084 }
00085 
00087 std::string strToUpper(const std::string& aString)
00088 {
00089     std::string result(aString);
00090     std::transform(aString.begin(), aString.end(), result.begin(), toupper_2);
00091     return result;
00092 };
00093 
00094 int main(int argc, char *argv[])
00095 {
00096     // parse arguments
00097     const char * optstring = "o:p:sch";
00098 
00099     enum
00100     {
00101         SWITCH_FOV=1000,
00102         SWITCH_CANVAS=1001,
00103         SWITCH_CROP=1002,
00104         SWITCH_ROTATE=1003,
00105         SWITCH_TRANSLATE=1004
00106     };
00107     static struct option longOptions[] = {
00108         {"output", required_argument, NULL, 'o' },
00109         {"projection", required_argument, NULL, 'p' },
00110         {"fov", optional_argument, NULL, SWITCH_FOV },
00111         {"straighten", no_argument, NULL, 's' },
00112         {"center", no_argument, NULL, 'c' },
00113         {"canvas", optional_argument, NULL, SWITCH_CANVAS },
00114         {"crop", optional_argument, NULL, SWITCH_CROP },
00115         {"rotate", required_argument, NULL, SWITCH_ROTATE },
00116         {"translate", required_argument, NULL, SWITCH_TRANSLATE },
00117         {"help", no_argument, NULL, 'h' },
00118         0
00119     };
00120 
00121     int projection=-1;
00122     double newHFOV=-1;
00123     double newVFOV=-1;
00124     int scale=100;
00125     int newWidth=-1;
00126     int newHeight=-1;
00127     vigra::Rect2D newROI(0,0,0,0);
00128     bool doFit=false;
00129     bool doStraighten=false;
00130     bool doCenter=false;
00131     bool doOptimalSize=false;
00132     bool doAutocrop=false;
00133     bool autocropHDR=false;
00134     int c;
00135     int optionIndex = 0;
00136     double yaw = 0;
00137     double pitch = 0;
00138     double roll = 0;
00139     double x = 0;
00140     double y = 0;
00141     double z = 0;
00142     string output;
00143     string param;
00144     while ((c = getopt_long (argc, argv, optstring, longOptions,&optionIndex)) != -1)
00145     {
00146         switch (c) 
00147         {
00148             case 'o':
00149                 output = optarg;
00150                 break;
00151             case 'h':
00152                 usage(argv[0]);
00153                 return 0;
00154             case 'p':
00155                 //projection
00156                 projection=atoi(optarg);
00157                 if((projection==0) && (strcmp(optarg,"0")!=0))
00158                 {
00159                     cerr << "Could not parse projection number.";
00160                     return 1;
00161                 };
00162                 if(projection>=panoProjectionFormatCount())
00163                 {
00164                     cerr << "projection " << projection << " is an invalid projection number.";
00165                     return 1;
00166                 };
00167                 break;
00168             case SWITCH_FOV:
00169                 //field of view
00170                 param=optarg;
00171                 param=strToUpper(param);
00172                 if(param=="AUTO")
00173                 {
00174                     doFit=true;
00175                 }
00176                 else
00177                 {
00178                     int hfov, vfov;
00179                     int n=sscanf(optarg, "%dx%d", &hfov, &vfov);
00180                     if(n==1)
00181                     {
00182                         if(hfov>0)
00183                         {
00184                             newHFOV=hfov;
00185                         }
00186                         else
00187                         {
00188                             cerr << "Invalid field of view" << endl;
00189                             return 1;
00190                         };
00191                     }
00192                     else
00193                     {
00194                         if (n==2)
00195                         {
00196                             if(hfov>0 && vfov>0)
00197                             {
00198                                 newHFOV=hfov;
00199                                 newVFOV=vfov;
00200                             }
00201                             else
00202                             {
00203                                 cerr << "Invalid field of view" << endl;
00204                                 return 1;
00205                             };
00206                         }
00207                         else
00208                         {
00209                             cerr << "Could not parse field of view" << endl;
00210                             return 1;
00211                         };
00212                     };
00213                 };
00214                 break;
00215             case 's':
00216                 doStraighten=true;
00217                 break;
00218             case 'c':
00219                 doCenter=true;
00220                 break;
00221             case SWITCH_CANVAS:
00222                 //canvas size
00223                 param=optarg;
00224                 param=strToUpper(param);
00225                 if(param=="AUTO")
00226                 {
00227                     doOptimalSize=true;
00228                 }
00229                 else
00230                 {
00231                     int pos=param.find("%");
00232                     if(pos!=string::npos)
00233                     {
00234                         param=param.substr(0,pos);
00235                         scale=atoi(param.c_str());
00236                         if(scale==0)
00237                         {
00238                             cerr << "No valid scale factor given." << endl;
00239                             return 1;
00240                         };
00241                         doOptimalSize=true;
00242                     }
00243                     else
00244                     {
00245                         int width, height;
00246                         int n=sscanf(optarg, "%dx%d", &width, &height);
00247                         if (n==2)
00248                         {
00249                             if(width>0 && height>0)
00250                             {
00251                                 newWidth=width;
00252                                 newHeight=height;
00253                             }
00254                             else
00255                             {
00256                                 cerr << "Invalid canvas size" << endl;
00257                                 return 1;
00258                             };
00259                         }
00260                         else
00261                         {
00262                             cerr << "Could not parse canvas size" << endl;
00263                             return 1;
00264                         };
00265                     };
00266                 };
00267                 break;
00268             case SWITCH_CROP:
00269                 //crop
00270                 param=optarg;
00271                 param=strToUpper(param);
00272                 if(param=="AUTO" || param=="AUTOHDR")
00273                 {
00274                     doAutocrop=true;
00275                     if(param=="AUTOHDR")
00276                     {
00277                         autocropHDR=true;
00278                     };
00279                 }
00280                 else
00281                 {
00282                     int left, right, top, bottom;
00283                     int n=sscanf(optarg, "%d,%d,%d,%d", &left, &right, &top, &bottom);
00284                     if (n==4)
00285                     {
00286                         if(right>left && bottom>top && left>=0 && top>=0)
00287                         {
00288                             newROI.setUpperLeft(vigra::Point2D(left,top));
00289                             newROI.setLowerRight(vigra::Point2D(right,bottom));
00290                         }
00291                         else
00292                         {
00293                             cerr << "Invalid crop area" << endl;
00294                             return 1;
00295                         };
00296                     }
00297                     else
00298                     {
00299                         cerr << "Could not parse crop values" << endl;
00300                         return 1;
00301                     };
00302                 };
00303                 break;
00304             case SWITCH_ROTATE:
00305                 {
00306                     int n=sscanf(optarg, "%lf,%lf,%lf", &yaw, &pitch, &roll);
00307                     if(n!=3)
00308                     {
00309                         cerr << "Could not parse rotate angles values. Given: \"" << optarg << "\"" << endl;
00310                         return 1;
00311                     };
00312                 };
00313                 break;
00314             case SWITCH_TRANSLATE:
00315                 {
00316                     int n=sscanf(optarg, "%lf,%lf,%lf", &x, &y, &z);
00317                     if(n!=3)
00318                     {
00319                         cerr << "Could not parse translation values. Given: \"" << optarg << "\"" << endl;
00320                         return 1;
00321                     };
00322                 };
00323                 break;
00324             case ':':
00325                 cerr <<"Option " << longOptions[optionIndex].name << " requires a number" << endl;
00326                 return 1;
00327                 break;
00328             case '?':
00329                 break;
00330             default:
00331                 abort ();
00332         }
00333     }
00334 
00335     if (argc - optind != 1) 
00336     {
00337         cout << "Warning: pano_modify can only work on one project file at one time" << endl << endl;
00338         usage(argv[0]);
00339         return 1;
00340     };
00341     
00342     // set some options which depends on each other
00343     if(doStraighten)
00344     {
00345         doCenter=false;
00346         doFit=true;
00347     };
00348     if(doCenter)
00349     {
00350         doFit=true;
00351     };
00352 
00353     string input=argv[optind];
00354     // read panorama
00355     Panorama pano;
00356     ifstream prjfile(input.c_str());
00357     if (!prjfile.good()) {
00358         cerr << "could not open script : " << input << endl;
00359         return 1;
00360     }
00361     pano.setFilePrefix(hugin_utils::getPathPrefix(input));
00362     DocumentData::ReadWriteError err = pano.readData(prjfile);
00363     if (err != DocumentData::SUCCESSFUL) {
00364         cerr << "error while parsing panos tool script: " << input << endl;
00365         cerr << "DocumentData::ReadWriteError code: " << err << endl;
00366         return 1;
00367     }
00368 
00369     // sets the projection
00370     if(projection!=-1)
00371     {
00372         PanoramaOptions opt=pano.getOptions();
00373         opt.setProjection((PanoramaOptions::ProjectionFormat)projection);
00374         pano_projection_features proj;
00375         if (panoProjectionFeaturesQuery(projection, &proj)) 
00376             cout << "Setting projection to " << proj.name << endl;
00377         pano.setOptions(opt);
00378     };
00379     if(abs(yaw) + abs(pitch) + abs(roll) > 0.0)
00380     {
00381         cout << "Rotate panorama (yaw=" << yaw << ", pitch= " << pitch << ", roll=" << roll << ")" << endl;
00382         RotatePanorama(pano, yaw, pitch, roll).run();
00383     };
00384     if(abs(x) + abs(y) + abs(z) > 0.0)
00385     {
00386         cout << "Translate panorama (x=" << x << ", y=" << y << ", z=" << z << ")" << endl;
00387         TranslatePanorama(pano, x, y, z).run();
00388     };
00389     // straighten
00390     if(doStraighten)
00391     {
00392         cout << "Straighten panorama" << endl;
00393         StraightenPanorama(pano).run();
00394         CenterHorizontally(pano).run();
00395     };
00396     // center
00397     if(doCenter)
00398     {
00399         cout << "Center panorama" << endl;
00400         CenterHorizontally(pano).run();
00401     }
00402     //fit fov
00403     if(doFit)
00404     {
00405         cout << "Fit panorama field of view to best size" << endl;
00406         PanoramaOptions opt=pano.getOptions();
00407         CalculateFitPanorama fitPano = CalculateFitPanorama(pano);
00408         fitPano.run();
00409         opt.setHFOV(fitPano.getResultHorizontalFOV());
00410         opt.setHeight(roundi(fitPano.getResultHeight()));
00411         cout << "Setting field of view to " << opt.getHFOV() << " x " << opt.getVFOV() << endl;
00412         pano.setOptions(opt);
00413     };
00414     //set field of view manually
00415     if(newHFOV>0)
00416     {
00417         PanoramaOptions opt=pano.getOptions();
00418         opt.setHFOV(newHFOV);
00419         if(opt.fovCalcSupported(opt.getProjection()) && newVFOV>0)
00420             opt.setVFOV(newVFOV);
00421         cout << "Setting field of view to " << opt.getHFOV() << " x " << opt.getVFOV() << endl;
00422         pano.setOptions(opt);
00423     };
00424     // calc optimal size
00425     if(doOptimalSize)
00426     {
00427         cout << "Calculate optimal size of panorama" << endl;
00428         double s = CalculateOptimalScale::calcOptimalScale(pano);
00429         PanoramaOptions opt=pano.getOptions();
00430         opt.setWidth(roundi(opt.getWidth()*s*scale/100), true);
00431         cout << "Setting canvas size to " << opt.getWidth() << " x " << opt.getHeight() << endl;
00432         pano.setOptions(opt);
00433     };
00434     // set canvas size
00435     if(newWidth>0 && newHeight>0)
00436     {
00437         PanoramaOptions opt=pano.getOptions();
00438         opt.setWidth(newWidth);
00439         opt.setHeight(newHeight);
00440         cout << "Setting canvas size to " << opt.getWidth() << " x " << opt.getHeight() << endl;
00441         pano.setOptions(opt);
00442     };
00443     // auto crop
00444     if(doAutocrop)
00445     {
00446         cout << "Searching for best crop rectangle" << endl;
00447         CalculateOptimalROI cropPano(pano);
00448         if(autocropHDR)
00449         {
00450             cropPano.setStacks(getHDRStacks(pano,pano.getActiveImages(), pano.getOptions()));
00451         }
00452         cropPano.run();
00453         
00454         vigra::Rect2D roi=cropPano.getResultOptimalROI();
00455         PanoramaOptions opt = pano.getOptions();
00456         //set the ROI - fail if the right/bottom is zero, meaning all zero
00457         if(roi.right() != 0 && roi.bottom() != 0)
00458         {
00459             opt.setROI(roi);
00460             cout << "Set crop size to " << roi.left() << "," << roi.top() << "," << roi.right() << "," << roi.bottom() << endl;
00461             pano.setOptions(opt);
00462         }
00463         else
00464             cout << "Could not find best crop rectangle" << endl;
00465     };
00466     //setting crop rectangle manually
00467     if(newROI.right() != 0 && newROI.bottom() != 0)
00468     {
00469         PanoramaOptions opt = pano.getOptions();
00470         opt.setROI(newROI);
00471         cout << "Set crop size to " << newROI.left() << "," << newROI.right() << "," << newROI.top() << "," << newROI.bottom() << endl;
00472         pano.setOptions(opt);
00473     };
00474 
00475     //write output
00476     OptimizeVector optvec = pano.getOptimizeVector();
00477     UIntSet imgs;
00478     fill_set(imgs,0, pano.getNrOfImages()-1);
00479     // Set output .pto filename if not given
00480     if (output=="")
00481     {
00482         output=input.substr(0,input.length()-4).append("_mod.pto");
00483     }
00484     ofstream of(output.c_str());
00485     pano.printPanoramaScript(of, optvec, pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(input));
00486     
00487     cout << endl << "Written output to " << output << endl;
00488     return 0;
00489 }

Generated on Sat Apr 19 01:25:40 2014 for Hugintrunk by  doxygen 1.3.9.1