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

Generated on 3 Dec 2016 for Hugintrunk by  doxygen 1.4.7