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

Generated on 30 May 2016 for Hugintrunk by  doxygen 1.4.7