00001
00002
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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>
00045 #include <limits.h>
00046 #include <libgen.h>
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];
00080 GetModuleFileName(NULL,buffer,sizeof(buffer));
00081 string working_path=string(buffer);
00082
00083 std::string::size_type pos=working_path.rfind("\\");
00084 if(pos!=std::string::npos)
00085 {
00086 working_path.erase(pos);
00087
00088 pos=working_path.rfind("\\");
00089 if(pos!=std::string::npos)
00090 {
00091 working_path.erase(pos);
00092
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
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
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
00256 if((finddata.attrib & _A_SUBDIR)==0)
00257 {
00258 _splitpath(finddata.name, NULL, NULL, fname, ext);
00259 _makepath(newFile, drive, dir, fname, ext);
00260
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
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
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
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
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
00473 PanoramaOptions opt = pano.getOptions();
00474 opt.outputExposureValue = CalculateMeanExposure::calcMeanExposure(pano);
00475 pano.setOptions(opt);
00476
00477 pano.setOptimizerSwitch(HuginBase::OPT_PAIR);
00478 pano.setPhotometricOptimizerSwitch(HuginBase::OPT_EXPOSURE | HuginBase::OPT_VIGNETTING | HuginBase::OPT_RESPONSE);
00479
00480
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
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 }