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

Generated on 24 May 2016 for Hugintrunk by  doxygen 1.4.7