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

Generated on 2 Sep 2015 for Hugintrunk by  doxygen 1.4.7