pto_gen.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 <getopt.h>
00031 #ifdef _WINDOWS
00032 #include <io.h>
00033 #endif
00034 #include <panodata/Panorama.h>
00035 #include <panodata/StandardImageVariableGroups.h>
00036 #include <panodata/OptimizerSwitches.h>
00037 #include <algorithms/basic/CalculateMeanExposure.h>
00038 #include "hugin_utils/alphanum.h"
00039 #include <vigra/impex.hxx>
00040 #include <lensdb/LensDB.h>
00041 
00042 #ifdef __APPLE__
00043 #include <hugin_config.h>
00044 #include <mach-o/dyld.h>    /* _NSGetExecutablePath */
00045 #include <limits.h>         /* PATH_MAX */
00046 #include <libgen.h>         /* dirname */
00047 #endif
00048 
00049 using namespace std;
00050 using namespace HuginBase;
00051 
00052 static void usage(const char* name)
00053 {
00054     cout << name << ": generate project file from images" << endl
00055          << name << " version " << DISPLAY_VERSION << endl
00056          << endl
00057          << "Usage:  " << name << " [options] image1 [...]" << endl
00058          << endl
00059          << "  Options:" << endl
00060          << "     -o, --output=file.pto  Output Hugin PTO file." << endl
00061          << "     -p, --projection=INT   Projection type (default: 0)" << endl
00062          << "     -f, --fov=FLOAT        Horizontal field of view of images (default: 50)" << endl
00063          << "     -c, --crop=left,right,top,bottom        Sets the crop of input" << endl
00064          << "                            images (especially for fisheye lenses)" << endl
00065          << "     -s, --stacklength=INT  Number of images in stack" << endl
00066          << "                            (default: 1, no stacks)" << endl
00067          << "     -l, --linkstacks       Link image positions in stacks" << endl
00068          << "     --distortion           Try to load distortion information from" << endl
00069          << "                            lensfun database" << endl
00070          << "     --vignetting           Try to load vignetting information from" << endl
00071          << "                            lensfun database" << endl
00072          << "     -h, --help             Shows this help" << endl
00073          << endl;
00074 }
00075 
00076 void InitLensDB()
00077 {
00078 #ifdef _WINDOWS
00079     char buffer[MAX_PATH];//always use MAX_PATH for filepaths
00080     GetModuleFileName(NULL,buffer,sizeof(buffer));
00081     string working_path=string(buffer);
00082     //remove filename
00083     std::string::size_type pos=working_path.rfind("\\");
00084     if(pos!=std::string::npos)
00085     {
00086         working_path.erase(pos);
00087         //remove last dir: should be bin
00088         pos=working_path.rfind("\\");
00089         if(pos!=std::string::npos)
00090         {
00091             working_path.erase(pos);
00092             //append path delimiter and path
00093             working_path.append("\\share\\lensfun\\");
00094             HuginBase::LensDB::LensDB::GetSingleton().SetMainDBPath(working_path);
00095         }
00096     }
00097 #elif defined MAC_SELF_CONTAINED_BUNDLE
00098     char path[PATH_MAX + 1];
00099     uint32_t size = sizeof(path);
00100     string install_path_lensfun("");
00101     if (_NSGetExecutablePath(path, &size) == 0)
00102     {
00103         install_path_lensfun=dirname(path);
00104         install_path_lensfun.append("/../Resources/lensfun/");
00105         HuginBase::LensDB::LensDB::GetSingleton().SetMainDBPath(install_path_lensfun);
00106     }
00107 #endif
00108 };
00109 
00110 int main(int argc, char* argv[])
00111 {
00112     // parse arguments
00113     const char* optstring = "o:p:f:c:s:lh";
00114 
00115     static struct option longOptions[] =
00116     {
00117         {"output", required_argument, NULL, 'o' },
00118         {"projection", required_argument, NULL, 'p' },
00119         {"fov", required_argument, NULL, 'f' },
00120         {"crop", required_argument, NULL, 'c' },
00121         {"stacklength", required_argument, NULL, 's' },
00122         {"linkstacks", no_argument, NULL, 'l' },
00123         {"distortion", no_argument, NULL, 300 },
00124         {"vignetting", no_argument, NULL, 301 },
00125         {"help", no_argument, NULL, 'h' },
00126 
00127         0
00128     };
00129 
00130     int c;
00131     int optionIndex = 0;
00132     string output;
00133     int projection=-1;
00134     float fov=-1;
00135     int stackLength=1;
00136     bool linkStacks=false;
00137     vigra::Rect2D cropRect(0,0,0,0);
00138     bool loadDistortion=false;
00139     bool loadVignetting=false;
00140     while ((c = getopt_long (argc, argv, optstring, longOptions,&optionIndex)) != -1)
00141     {
00142         switch (c)
00143         {
00144             case 'o':
00145                 output = optarg;
00146                 break;
00147             case 'h':
00148                 usage(argv[0]);
00149                 return 0;
00150             case 'p':
00151                 {
00152                     projection=atoi(optarg);
00153                     if((projection==0) && (strcmp(optarg,"0")!=0))
00154                     {
00155                         cerr << "Could not parse image number.";
00156                         return 1;
00157                     };
00158                     if(projection<0)
00159                     {
00160                         cerr << "Invalid projection number." << endl;
00161                         return 1;
00162                     };
00163                 };
00164                 break;
00165             case 'f':
00166                 fov=atof(optarg);
00167                 if(fov<1 || fov>360)
00168                 {
00169                     cerr << "Invalid field of view";
00170                     return 1;
00171                 };
00172                 break;
00173             case 'c':
00174                 {
00175                     int left, right, top, bottom;
00176                     int n=sscanf(optarg, "%d,%d,%d,%d", &left, &right, &top, &bottom);
00177                     if (n==4)
00178                     {
00179                         if(right>left && bottom>top)
00180                         {
00181                             cropRect.setUpperLeft(vigra::Point2D(left,top));
00182                             cropRect.setLowerRight(vigra::Point2D(right,bottom));
00183                         }
00184                         else
00185                         {
00186                             cerr << "Invalid crop area" << endl;
00187                             return 1;
00188                         };
00189                     }
00190                     else
00191                     {
00192                         cerr << "Could not parse crop values" << endl;
00193                         return 1;
00194                     };
00195                 };
00196                 break;
00197             case 's':
00198                 stackLength=atoi(optarg);
00199                 if(stackLength<1)
00200                 {
00201                     cerr << "Could not parse stack length." << endl;
00202                     return 1;
00203                 };
00204                 break;
00205             case 'l':
00206                 linkStacks=true;
00207                 break;
00208             case 300:
00209                 loadDistortion=true;
00210                 break;
00211             case 301:
00212                 loadVignetting=true;
00213                 break;
00214             case ':':
00215                 cerr <<"Option " << longOptions[optionIndex].name << " requires a number" << endl;
00216                 return 1;
00217                 break;
00218             case '?':
00219                 break;
00220             default:
00221                 abort ();
00222         }
00223     }
00224 
00225     if (argc - optind < 1)
00226     {
00227         usage(argv[0]);
00228         return 1;
00229     };
00230 
00231     cout << "Generating pto file..." << endl;
00232     cout.flush();
00233 
00234     std::vector<string> filelist;
00235     while(optind<argc)
00236     {
00237         string input;
00238 #ifdef _WINDOWS
00239         //do globbing
00240         input=GetAbsoluteFilename(argv[optind]);
00241         char drive[_MAX_DRIVE];
00242         char dir[_MAX_DIR];
00243         char fname[_MAX_FNAME];
00244         char ext[_MAX_EXT];
00245         char newFile[_MAX_PATH];
00246 
00247         _splitpath(input.c_str(), drive, dir, NULL, NULL);
00248 
00249         struct _finddata_t finddata;
00250         intptr_t findhandle = _findfirst(input.c_str(), &finddata);
00251         if (findhandle != -1)
00252         {
00253             do
00254             {
00255                 //ignore folder, can be happen when using *.*
00256                 if((finddata.attrib & _A_SUBDIR)==0)
00257                 {
00258                     _splitpath(finddata.name, NULL, NULL, fname, ext);
00259                     _makepath(newFile, drive, dir, fname, ext);
00260                     //check if valid image file
00261                     if(vigra::isImage(newFile))
00262                     {
00263                         filelist.push_back(std::string(newFile));
00264                     };
00265                 };
00266             }
00267             while (_findnext(findhandle, &finddata) == 0);
00268             _findclose(findhandle);
00269         }
00270 #else
00271         input=argv[optind];
00272         if(hugin_utils::FileExists(input))
00273         {
00274             if(vigra::isImage(input.c_str()))
00275             {
00276                 filelist.push_back(GetAbsoluteFilename(input));
00277             };
00278         };
00279 #endif
00280         optind++;
00281     };
00282 
00283     if(filelist.size()==0)
00284     {
00285         cerr << "No valid image files given." << endl;
00286         return 1;
00287     };
00288 
00289     //sort filenames
00290     sort(filelist.begin(),filelist.end(),doj::alphanum_less());
00291 
00292     if(projection<0)
00293     {
00294         InitLensDB();
00295     };
00296 
00297     Panorama pano;
00298     for(size_t i=0; i<filelist.size();i++)
00299     {
00300         SrcPanoImage srcImage(filelist[i]);
00301         cout << "Reading " << filelist[i] << "..." << endl;
00302         if(projection>=0)
00303         {
00304             srcImage.setProjection((HuginBase::BaseSrcPanoImage::Projection)projection);
00305         }
00306         else
00307         {
00308             srcImage.readProjectionFromDB();
00309         };
00310         if(fov>0)
00311         {
00312             srcImage.setHFOV(fov);
00313             if(!srcImage.hasEXIFread())
00314             {
00315                 srcImage.setExifCropFactor(1.0);
00316             };
00317         }
00318         else
00319         {
00320             //set plausible default value if they could not read from exif
00321             if(!srcImage.hasEXIFread())
00322             {
00323                 cout << "\tNo value for field of view found in EXIF data. " << endl
00324                      << "\tAssuming a HFOV of 50 degrees. " << endl;
00325                 srcImage.setHFOV(50);
00326                 srcImage.setExifCropFactor(1.0);
00327             };
00328         };
00329         if(cropRect.width()>0 && cropRect.height()>0)
00330         {
00331             if(srcImage.isCircularCrop())
00332             {
00333                 srcImage.setCropMode(SrcPanoImage::CROP_CIRCLE);
00334             }
00335             else
00336             {
00337                 srcImage.setCropMode(SrcPanoImage::CROP_RECTANGLE);
00338             };
00339             srcImage.setAutoCenterCrop(false);
00340             srcImage.setCropRect(cropRect);
00341         };
00342         try
00343         {
00344             vigra::ImageImportInfo info(filelist[i].c_str());
00345             std::string pixelType=info.getPixelType();
00346             if((pixelType=="UINT8") || (pixelType=="UINT16") || (pixelType=="INT16"))
00347             {
00348                 srcImage.setResponseType(HuginBase::SrcPanoImage::RESPONSE_EMOR);
00349             }
00350             else
00351             {
00352                 srcImage.setResponseType(HuginBase::SrcPanoImage::RESPONSE_LINEAR);
00353             };
00354         }
00355         catch(std::exception & e)
00356         {
00357             cerr << "ERROR: caught exception: " << e.what() << std::endl;
00358             cerr << "Could not get pixel type for file " << filelist[i] << std::endl;
00359         };
00360         if(loadDistortion)
00361         {
00362             if(srcImage.readDistortionFromDB())
00363             {
00364                 cout << "\tRead distortion data from lensfun database." << endl;
00365             }
00366             else
00367             {
00368                 cout << "\tNo valid distortion data found in lensfun database." << endl;
00369             };
00370         };
00371         if(loadVignetting)
00372         {
00373             if(srcImage.readVignettingFromDB())
00374             {
00375                 cout << "\tRead vignetting data from lensfun database." << endl;
00376             }
00377             else
00378             {
00379                 cout << "\tNo valid vignetting data found in lensfun database." << endl;
00380             };
00381         };
00382 
00383         pano.addImage(srcImage);
00384     };
00385 
00386     if(pano.getNrOfImages()==0)
00387     {
00388         cerr << "Adding images to project files failed." << endl;
00389         HuginBase::LensDB::LensDB::Clean();
00390         return 1;
00391     };
00392 
00393     //link lenses
00394     if(pano.getNrOfImages()>1)
00395     {
00396         StandardImageVariableGroups variable_groups(pano);
00397         ImageVariableGroup& lenses = variable_groups.getLenses();
00398 
00399         for(size_t i=1;i<pano.getNrOfImages();i++)
00400         {
00401             int image=-1;
00402             const SrcPanoImage & srcImg=pano.getImage(i);
00403             for(size_t j=0;j<i;j++)
00404             {
00405                 const SrcPanoImage & compareImg=pano.getImage(j);
00406                 if(srcImg.getHFOV()==compareImg.getHFOV() &&
00407                     srcImg.getProjection()==compareImg.getProjection() &&
00408                     srcImg.getExifModel()==compareImg.getExifModel() &&
00409                     srcImg.getExifMake()==compareImg.getExifMake() &&
00410                     srcImg.getSize()==compareImg.getSize())
00411                 {
00412                     image=j;
00413                     break;
00414                 };
00415             };
00416             if(image!=-1)
00417             {
00418                 SrcPanoImage img=pano.getSrcImage(i);
00419                 double ev=img.getExposureValue();
00420                 lenses.switchParts(i,lenses.getPartNumber(image));
00421                 lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_ExposureValue, i);
00422                 img.setExposureValue(ev);
00423                 lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceRed, i);
00424                 lenses.unlinkVariableImage(HuginBase::ImageVariableGroup::IVE_WhiteBalanceBlue, i);
00425                 img.setWhiteBalanceRed(1);
00426                 img.setWhiteBalanceBlue(1);
00427                 pano.setSrcImage(i, img);
00428             };
00429         };
00430         cout << endl << "Assigned " << lenses.getNumberOfParts() << " lenses." << endl;
00431         if(lenses.getNumberOfParts()>1 && stackLength>1)
00432         {
00433             cout << "Project contains more than one lens, but you requested to assign" << endl
00434                  << "stacks. This is not supported. Therefore stacks will not be" << endl
00435                  << "assigned." << endl << endl;
00436             stackLength=1;
00437         };
00438     };
00439 
00440     //link stacks
00441     if(pano.getNrOfImages()>1 && stackLength>1)
00442     {
00443         stackLength=std::min<int>(stackLength,pano.getNrOfImages());
00444         int stackCount=pano.getNrOfImages() / stackLength;
00445         if(pano.getNrOfImages() % stackLength > 0)
00446         {
00447             stackCount++;
00448         };
00449         if(stackCount<pano.getNrOfImages())
00450         {
00451             for(size_t stackNr=0;stackNr<stackCount;stackNr++)
00452             {
00453                 size_t firstImgStack=stackNr*stackLength;
00454                 for(size_t i=0;i<stackLength;i++)
00455                 {
00456                     if(firstImgStack+i<pano.getNrOfImages())
00457                     {
00458                         pano.linkImageVariableStack(firstImgStack,firstImgStack+i);
00459                         if(linkStacks)
00460                         {
00461                             pano.linkImageVariableYaw(firstImgStack,firstImgStack+i);
00462                             pano.linkImageVariablePitch(firstImgStack,firstImgStack+i);
00463                             pano.linkImageVariableRoll(firstImgStack,firstImgStack+i);
00464                         };
00465                     };
00466                 };
00467             };
00468             cout << "Assigned " << stackCount << " stacks." << endl;
00469         };
00470     };
00471 
00472     //set output exposure value
00473     PanoramaOptions opt = pano.getOptions();
00474     opt.outputExposureValue = CalculateMeanExposure::calcMeanExposure(pano);
00475     pano.setOptions(opt);
00476     // set optimizer switches
00477     pano.setOptimizerSwitch(HuginBase::OPT_PAIR);
00478     pano.setPhotometricOptimizerSwitch(HuginBase::OPT_EXPOSURE | HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE);
00479 
00480     //output
00481     if(output=="")
00482     {
00483         output=hugin_utils::stripExtension(pano.getImage(0).getFilename());
00484         if(pano.getNrOfImages()>1)
00485         {
00486             output.append("-");
00487             output.append(hugin_utils::stripExtension(hugin_utils::stripPath(pano.getImage(pano.getNrOfImages()-1).getFilename())));
00488         };
00489         output=output.append(".pto");
00490     };
00491     output=GetAbsoluteFilename(output);
00492     //write output
00493     UIntSet imgs;
00494     fill_set(imgs,0, pano.getNrOfImages()-1);
00495     ofstream of(output.c_str());
00496     pano.printPanoramaScript(of, pano.getOptimizeVector(), pano.getOptions(), imgs, false, hugin_utils::getPathPrefix(output));
00497 
00498     cout << endl << "Written output to " << output << endl;
00499     HuginBase::LensDB::LensDB::Clean();
00500     return 0;
00501 }

Generated on 31 Oct 2014 for Hugintrunk by  doxygen 1.4.7