pto_mask.cpp

Go to the documentation of this file.
00001 // -*- c-basic-offset: 4 -*-
00002 
00011 /*  This program is free software; you can redistribute it and/or
00012  *  modify it under the terms of the GNU General Public
00013  *  License as published by the Free Software Foundation; either
00014  *  version 2 of the License, or (at your option) any later version.
00015  *
00016  *  This software is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *  General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU General Public
00022  *  License along with this software; if not, write to the Free Software
00023  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  */
00026 
00027 #include <hugin_version.h>
00028 
00029 #include <fstream>
00030 #include <sstream>
00031 #include <getopt.h>
00032 #ifndef WIN32
00033 #include <unistd.h>
00034 #endif
00035 #include <panodata/Panorama.h>
00036 
00037 using namespace std;
00038 using namespace HuginBase;
00039 using namespace AppBase;
00040 
00041 struct MaskFiles
00042 {
00043     size_t imageNr;
00044     string maskFile;
00045 };
00046 
00047 // toupper is overloaded in <locale>, but we want to use it as a unary function.
00048 inline char toupper_2(char c)
00049 {
00050     return toupper(c);
00051 }
00052 
00054 std::string strToUpper(const std::string& aString)
00055 {
00056     std::string result(aString);
00057     std::transform(aString.begin(), aString.end(), result.begin(), toupper_2);
00058     return result;
00059 };
00060 
00061 static void usage(const char* name)
00062 {
00063     cout << name << ": add mask to pto project" << endl
00064          << name << " version " << DISPLAY_VERSION << endl
00065          << endl
00066          << "Usage:  " << name << " [options] input.pto" << endl
00067          << endl
00068          << "  Options:" << endl
00069          << "     -o, --output=file.pto  Output Hugin PTO file. Default: <filename>_mask.pto" << endl
00070          << "     --mask=filename@imgNr  Read the mask from the file and" << endl
00071          << "                            assign the mask to given image" << endl
00072          << "     --rotate=CLOCKWISE|90|COUNTERCLOCKWISE|-90" << endl
00073          << "                            Rotates the mask clock- or counterclockwise" << endl
00074          << "     --process==CLIP|SCALE|PROP_SCALE   Specify how the mask should be modified" << endl
00075          << "                            if the mask is create for an image with" << endl
00076          << "                            different size." << endl
00077          << "                            * CLIP: clipping (Default)" << endl
00078          << "                            * SCALE: Scaling width and height individually" << endl
00079          << "                            * PROP_SCALE: Proportional scale" << endl
00080          << "     -h, --help             Shows this help" << endl
00081          << endl;
00082 }
00083 
00084 int main(int argc, char* argv[])
00085 {
00086     // parse arguments
00087     const char* optstring = "o:h";
00088     enum
00089     {
00090         MASK_SWITCH=1000,
00091         ROTATE_SWITCH,
00092         PROC_SWITCH
00093     };
00094     static struct option longOptions[] =
00095     {
00096         {"output", required_argument, NULL, 'o' },
00097         {"mask", required_argument, NULL, MASK_SWITCH },
00098         {"rotate", required_argument, NULL, ROTATE_SWITCH},
00099         {"process", required_argument, NULL, PROC_SWITCH},
00100         {"help", no_argument, NULL, 'h' },
00101         0
00102     };
00103 
00104     int c;
00105     int optionIndex = 0;
00106     std::vector<MaskFiles> maskFiles;
00107     size_t rotate=0;
00108     size_t process=0;
00109     string output;
00110     while ((c = getopt_long (argc, argv, optstring, longOptions,&optionIndex)) != -1)
00111     {
00112         switch (c)
00113         {
00114             case 'o':
00115                 output = optarg;
00116                 break;
00117             case MASK_SWITCH:
00118                 {
00119                     std::string s=optarg;
00120                     size_t found=s.rfind('@');
00121                     MaskFiles mf;
00122                     if(found!=std::string::npos)
00123                     {
00124                         string s2=s.substr(found+1, std::string::npos);
00125                         mf.imageNr=atoi(s2.c_str());
00126                         if(mf.imageNr==0 && s2!="0")
00127                         {
00128                             cerr << "Error: Could not parse image number: \"" << s2 << "\"." << endl;
00129                             return 1;
00130                         };
00131                     }
00132                     else
00133                     {
00134                         cerr << "Error: No image number found in \"" << s << "\"." << endl;
00135                         return 1;
00136                     };
00137                     mf.maskFile=s.substr(0, found);
00138                     if(!hugin_utils::FileExists(mf.maskFile))
00139                     {
00140                         cerr << "Error: File \"" << mf.maskFile << "\" does not exists." << endl;
00141                         return 1;
00142                     };
00143                     maskFiles.push_back(mf);
00144                 };
00145                 break;
00146             case ROTATE_SWITCH:
00147                 {
00148                     string s=optarg;
00149                     s=strToUpper(s);
00150                     if(s=="CLOCKWISE" || s=="90")
00151                     {
00152                         rotate=1;
00153                     }
00154                     else
00155                     {
00156                         if(s=="COUNTERCLOCKWISE" || s=="-90")
00157                         {
00158                             rotate=2;
00159                         }
00160                         else
00161                         {
00162                             cerr << "Error:  Unknown rotate command (" << optarg << ") found." << endl;
00163                             return 1;
00164                         };
00165                     };
00166                 };
00167                 break;
00168             case PROC_SWITCH:
00169                 {
00170                     string s=optarg;
00171                     s=strToUpper(s);
00172                     if(s=="CLIP")
00173                     {
00174                         process=0;
00175                     }
00176                     else
00177                     {
00178                         if(s=="SCALE")
00179                         {
00180                             process=1;
00181                         }
00182                         else
00183                         {
00184                             if(s=="PROP_SCALE")
00185                             {
00186                                 process=2;
00187                             }
00188                             else
00189                             {
00190                                 cerr << "Error: Unknown process command (" << optarg << ") found." << endl;
00191                                 return 1;
00192                             };
00193                         };
00194                     };
00195                 }
00196                 break;
00197             case 'h':
00198                 usage(argv[0]);
00199                 return 0;
00200             case ':':
00201                 cerr <<"Option " << longOptions[optionIndex].name << " requires a parameter" << endl;
00202                 return 1;
00203                 break;
00204             case '?':
00205                 break;
00206             default:
00207                 abort ();
00208         }
00209     }
00210 
00211     if (argc - optind == 0)
00212     {
00213         cout << "Error: No project file given." << endl << endl;
00214         return 1;
00215     };
00216     if (argc - optind != 1)
00217     {
00218         cout << "Error: pto_mask can only work on one project file at one time" << endl << endl;
00219         return 1;
00220     };
00221 
00222     if(maskFiles.size()==0)
00223     {
00224         cerr << "Error: No mask files given." << endl << endl;
00225         return 1;
00226     };
00227 
00228     string input=argv[optind];
00229     // read panorama
00230     Panorama pano;
00231     ifstream prjfile(input.c_str());
00232     if (!prjfile.good())
00233     {
00234         cerr << "Error: could not open script " << input << endl;
00235         return 1;
00236     }
00237     pano.setFilePrefix(hugin_utils::getPathPrefix(input));
00238     DocumentData::ReadWriteError err = pano.readData(prjfile);
00239     if (err != DocumentData::SUCCESSFUL)
00240     {
00241         cerr << "Error while parsing panos tool script: " << input << endl;
00242         cerr << "DocumentData::ReadWriteError code: " << err << endl;
00243         return 1;
00244     }
00245 
00246     if(pano.getNrOfImages()==0)
00247     {
00248         cerr << "Error: project file does not contains any image" << endl;
00249         return 1;
00250     };
00251 
00252     //read masks and apply
00253     for(size_t i=0; i<maskFiles.size(); i++)
00254     {
00255         if(maskFiles[i].imageNr<pano.getNrOfImages())
00256         {
00257             std::ifstream in(maskFiles[i].maskFile.c_str());
00258             vigra::Size2D maskImageSize;
00259             HuginBase::MaskPolygonVector loadedMasks;
00260             LoadMaskFromStream(in, maskImageSize, loadedMasks, maskFiles[i].imageNr);
00261             in.close();
00262             if(maskImageSize.area()==0 || loadedMasks.size()==0)
00263             {
00264                 cerr << "Error: Could not parse mask from file \"" << maskFiles[i].maskFile << "\"." << endl;
00265                 return 1;
00266             };
00267             double maskWidth;
00268             double maskHeight;
00269             if(rotate==0)
00270             {
00271                 maskWidth=maskImageSize.width();
00272                 maskHeight=maskImageSize.height();
00273             }
00274             else
00275             {
00276                 maskWidth=maskImageSize.height();
00277                 maskHeight=maskImageSize.width();
00278                 bool clockwise=(rotate==1);
00279                 for(unsigned int i=0;i<loadedMasks.size();i++)
00280                     loadedMasks[i].rotate90(clockwise, maskImageSize.width(), maskImageSize.height());
00281             };
00282             // compare image size from file with that of current image alert user
00283             // if different.
00284             vigra::Size2D imageSize=pano.getImage(maskFiles[i].imageNr).getSize();
00285             if (maskImageSize != imageSize) 
00286             {
00287                 switch(process)
00288                 {
00289                     case 0:
00290                         // clip mask
00291                         cout << "Clipping mask" << endl;
00292                         for(unsigned int i=0;i<loadedMasks.size();i++)
00293                             loadedMasks[i].clipPolygon(vigra::Rect2D(-0.5*HuginBase::maskOffset, -0.5*HuginBase::maskOffset,
00294                                 imageSize.width()+0.5*HuginBase::maskOffset, imageSize.height()+0.5*HuginBase::maskOffset));
00295                         break;
00296                     case 1:
00297                         // scale mask
00298                         cout << "Scaling mask" << endl;
00299                         for(unsigned int i=0;i<loadedMasks.size();i++)
00300                             loadedMasks[i].scale((double)imageSize.width()/maskWidth,(double)imageSize.height()/maskHeight);
00301                         break;
00302                     case 2:
00303                         // proportional scale mask
00304                         cout << "Propotional scale mask" << endl;
00305                         {
00306                             double factor=std::min((double)imageSize.width()/maskWidth, (double)imageSize.height()/maskHeight);
00307                             for(unsigned int i=0;i<loadedMasks.size();i++)
00308                                 loadedMasks[i].scale(factor);
00309                         };
00310                         break;
00311                 };
00312             };
00313             MaskPolygonVector masks=pano.getImage(maskFiles[i].imageNr).getMasks();
00314             for(size_t j=0; j<loadedMasks.size(); j++)
00315             {
00316                 masks.push_back(loadedMasks[j]);
00317             };
00318             pano.updateMasksForImage(maskFiles[i].imageNr, masks);
00319         }
00320         else
00321         {
00322             cout << "Warning: Invalid image number \"" << maskFiles[i].imageNr << "\"." << endl
00323                  << "         Project contains only " << pano.getNrOfImages()+1 << " images." << endl
00324                  << "         Ignoring this mask." << endl;
00325         };
00326     };
00327 
00328     //write output
00329     UIntSet imgs;
00330     fill_set(imgs, 0, pano.getNrOfImages()-1);
00331     // Set output .pto filename if not given
00332     if (output=="")
00333     {
00334         output=input.substr(0,input.length()-4).append("_mask.pto");
00335     }
00336     ofstream of(output.c_str());
00337     pano.printPanoramaScript(of, pano.getOptimizeVector(), pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(input));
00338 
00339     cout << endl << "Written output to " << output << endl;
00340     return 0;
00341 }

Generated on Fri Aug 1 01:25:42 2014 for Hugintrunk by  doxygen 1.3.9.1