32 #include <vigra/imageinfo.hxx>
41 #include <hugin_config.h>
42 #include <mach-o/dyld.h>
47 static void usage(
const char* name)
49 std::cout << name <<
": generate project file from images" << std::endl
52 <<
"Usage: " << name <<
" [options] image1 [...]" << std::endl
54 <<
" Options:" << std::endl
55 <<
" -o, --output=file.pto Output Hugin PTO file." << std::endl
56 <<
" -p, --projection=INT Projection type (default: read from database)" << std::endl
57 <<
" -f, --fov=FLOAT Horizontal field of view of images" << std::endl
58 <<
" default: read from database" << std::endl
59 <<
" --ignore-fov-rectilinear Don't read fov for rectilinear images from" <<std::endl
60 <<
" the database, instead use only the values" << std::endl
61 <<
" from EXIF data" << std::endl
62 <<
" -c, --crop=left,right,top,bottom Sets the crop of input" << std::endl
63 <<
" images (especially for fisheye lenses)" << std::endl
64 <<
" -s, --stacklength=INT Number of images in stack" << std::endl
65 <<
" (default: automatic detection)" << std::endl
66 <<
" -l, --linkstacks Link image positions in stacks" << std::endl
67 <<
" --distortion Try to load distortion information from" << std::endl
68 <<
" lens database" << std::endl
69 <<
" --vignetting Try to load vignetting information from" << std::endl
70 <<
" lens database" << std::endl
71 <<
" --sort Sort the files by name alphanumeric" << std::endl
72 <<
" otherwise the images are processed in the order" << std::endl
73 <<
" given at the command line" << std::endl
74 <<
" -h, --help Shows this help" << std::endl
78 int main(
int argc,
char* argv[])
81 const char* optstring =
"o:p:f:c:s:lh";
84 SWITCH_IGNORE_FOV_RECTILINEAR = 1000,
89 static struct option longOptions[] =
91 {
"output", required_argument, NULL,
'o' },
92 {
"projection", required_argument, NULL,
'p' },
93 {
"fov", required_argument, NULL,
'f' },
94 {
"ignore-fov-rectilinear", no_argument, NULL, SWITCH_IGNORE_FOV_RECTILINEAR},
95 {
"crop", required_argument, NULL,
'c' },
96 {
"stacklength", required_argument, NULL,
's' },
97 {
"linkstacks", no_argument, NULL,
'l' },
98 {
"distortion", no_argument, NULL, SWITCH_DISTORTION },
99 {
"vignetting", no_argument, NULL, SWITCH_VIGNETTING },
100 {
"sort", no_argument, NULL, SWITCH_SORT_FILENAME },
101 {
"help", no_argument, NULL,
'h' },
111 bool linkStacks=
false;
112 vigra::Rect2D cropRect(0,0,0,0);
113 bool ignoreFovRectilinear =
false;
114 bool loadDistortion=
false;
115 bool loadVignetting=
false;
116 bool sortByFilename =
false;
117 while ((c = getopt_long (argc, argv, optstring, longOptions,
nullptr)) != -1)
129 projection=atoi(optarg);
130 if((projection==0) && (strcmp(optarg,
"0")!=0))
156 int left, right, top, bottom;
157 int n=sscanf(optarg,
"%d,%d,%d,%d", &left, &right, &top, &bottom);
160 if(right>left && bottom>top)
162 cropRect.setUpperLeft(vigra::Point2D(left,top));
163 cropRect.setLowerRight(vigra::Point2D(right,bottom));
179 stackLength=atoi(optarg);
180 if ((stackLength == 0) && (strcmp(optarg,
"0") != 0))
189 case SWITCH_DISTORTION:
192 case SWITCH_VIGNETTING:
195 case SWITCH_IGNORE_FOV_RECTILINEAR:
196 ignoreFovRectilinear =
true;
198 case SWITCH_SORT_FILENAME:
199 sortByFilename =
true;
212 if (argc - optind < 1)
218 std::cout <<
"Generating pto file..." << std::endl;
221 std::vector<std::string> filelist;
228 char drive[_MAX_DRIVE];
230 _splitpath(input.c_str(), drive, dir, NULL, NULL);
232 struct _finddata_t finddata;
233 intptr_t findhandle = _findfirst(input.c_str(), &finddata);
234 if (findhandle != -1)
239 if((finddata.attrib & _A_SUBDIR)==0)
241 char fname[_MAX_FNAME];
243 char newFile[_MAX_PATH];
244 _splitpath(finddata.name, NULL, NULL, fname, ext);
245 _makepath(newFile, drive, dir, fname, ext);
247 if(vigra::isImage(newFile))
249 filelist.push_back(std::string(newFile));
253 while (_findnext(findhandle, &finddata) == 0);
254 _findclose(findhandle);
260 if(vigra::isImage(input.c_str()))
282 double redBalanceAnchor = 1.0;
283 double blueBalanceAnchor = 1.0;
284 for(
size_t i=0; i<filelist.size(); i++)
290 std::cerr <<
"Ignoring raw file " << filelist[i] <<
"." << std::endl;
294 std::cout <<
"Reading " << filelist[i] <<
"..." << std::endl;
295 srcImage.setFilename(filelist[i]);
298 vigra::ImageImportInfo
info(filelist[i].c_str());
299 if(info.width()==0 || info.height()==0)
301 std::cerr <<
"ERROR: Could not decode image " << filelist[i] << std::endl
302 <<
"Skipping this image." << std::endl << std::endl;
307 const std::string pixelType=info.getPixelType();
308 if (pixelType ==
"BILEVEL")
310 std::cerr <<
"ERROR: Image " << filelist[i] <<
" is a black/white images." << std::endl
311 <<
" This is not supported. Convert to grayscale image and try again." << std::endl
312 <<
" Skipping this image." << std::endl;
315 if((pixelType==
"UINT8") || (pixelType==
"UINT16") || (pixelType==
"INT16"))
324 catch(std::exception& e)
326 std::cerr <<
"ERROR: caught exception: " << e.what() << std::endl;
327 std::cerr <<
"Could not read image information for file " << filelist[i] << std::endl;
328 std::cerr <<
"Skipping this image." << std::endl << std::endl;
344 srcImage.setHFOV(fov);
345 if(srcImage.getCropFactor()==0)
347 srcImage.setCropFactor(1.0);
355 std::cout <<
"\tNo value for field of view found in EXIF data. " << std::endl
356 <<
"\tAssuming a HFOV of 50 degrees. " << std::endl;
357 srcImage.setHFOV(50);
358 srcImage.setCropFactor(1.0);
361 if(cropRect.width()>0 && cropRect.height()>0)
371 srcImage.setAutoCenterCrop(
false);
372 srcImage.setCropRect(cropRect);
378 std::cout <<
"\tRead distortion data from lens database." << std::endl;
382 std::cout <<
"\tNo valid distortion data found in lens database." << std::endl;
389 std::cout <<
"\tRead vignetting data from lens database." << std::endl;
393 std::cout <<
"\tNo valid vignetting data found in lens database." << std::endl;
398 redBalanceAnchor = srcImage.getExifRedBalance();
399 blueBalanceAnchor = srcImage.getExifBlueBalance();
400 if (fabs(redBalanceAnchor)<1e-2)
402 redBalanceAnchor = 1;
404 if (fabs(blueBalanceAnchor)<1e-2)
406 blueBalanceAnchor = 1;
411 srcImage.setWhiteBalanceRed(srcImage.getExifRedBalance() / redBalanceAnchor);
412 srcImage.setWhiteBalanceBlue(srcImage.getExifBlueBalance() / blueBalanceAnchor);
419 std::cerr <<
"Adding images to project files failed." << std::endl;
434 for(
size_t j=0; j<i; j++)
437 if(srcImg.getHFOV()==compareImg.getHFOV() &&
438 srcImg.getProjection()==compareImg.getProjection() &&
439 srcImg.getExifModel()==compareImg.getExifModel() &&
440 srcImg.getExifMake()==compareImg.getExifMake() &&
441 srcImg.getSize()==compareImg.getSize())
452 std::cout << std::endl <<
"Assigned " << lenses.
getNumberOfParts() <<
" lenses." << std::endl;
455 std::cout <<
"Project contains more than one lens, but you requested to assign" << std::endl
456 <<
"stacks. This is not supported. Therefore stacks will not be" << std::endl
457 <<
"assigned." << std::endl << std::endl;
461 if (stackLength == 0)
473 stackLength = std::min<int>(stackLength, pano.
getNrOfImages());
481 for (
size_t stackNr = 0; stackNr < stackCount; stackNr++)
483 size_t firstImgStack = stackNr*stackLength;
484 for (
size_t i = 0; i < stackLength; i++)
488 pano.linkImageVariableStack(firstImgStack, firstImgStack + i);
491 pano.linkImageVariableYaw(firstImgStack, firstImgStack + i);
492 pano.linkImageVariablePitch(firstImgStack, firstImgStack + i);
493 pano.linkImageVariableRoll(firstImgStack, firstImgStack + i);
494 pano.linkImageVariableX(firstImgStack, firstImgStack + i);
495 pano.linkImageVariableY(firstImgStack, firstImgStack + i);
496 pano.linkImageVariableZ(firstImgStack, firstImgStack + i);
497 pano.linkImageVariableTranslationPlaneYaw(firstImgStack, firstImgStack + i);
498 pano.linkImageVariableTranslationPlanePitch(firstImgStack, firstImgStack + i);
511 std::cout <<
"Assigned " << stackCount <<
" stacks: " << std::endl
512 <<
"\t" << (linkStacks ?
"Linking position of images in stacks" :
"Use individual positions of images in stacks") << std::endl;
534 output=output.append(
".pto");
540 std::cout << std::endl <<
"Written output to " << output << std::endl;
void setCropMode(CropMode val)
Set the crop mode.
bool FileExists(const std::string &filename)
checks if file exists
void updateOptimizeVector()
updates the optimize vector according to master switches
bool applyEXIFValues(bool applyEVValue=true)
apply values found in EXIF data to SrcPanoImage class, call readEXIF() before to initialize some valu...
unsigned int getPartNumber(unsigned int imageNr) const
Get a part number from an image number.
static double calcMeanExposure(const PanoramaData &pano)
bool isCircularCrop() const
returns true, if projection requires cicular crop
ImageVariableGroup & getStacks()
Get the ImageVariableGroup representing the group of stack variables.
void setPhotometricOptimizerSwitch(const int newSwitch)
sets the photometric optimizer master switch
Somewhere to specify what variables belong to what.
Functor class to compare two objects with the "Alphanum Algorithm".
vigra::pair< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImage(const ROIImage< Image, Mask > &img)
void setOptimizerSwitch(const int newSwitch)
set optimizer master switch
static void Clean()
cleanup the static LensDB instance, must be called at the end of the program
bool readProjectionFromDB(const bool ignoreFovRectilinear=true)
tries to read projection and crop area from lens database you need to call SrcPanoImage::readEXIF bef...
class to access Hugins camera and lens database
void linkPossibleStacks(bool linkPosition)
create automatically stacks as indicated by metadata
empirical model of response
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
std::string GetAbsoluteFilename(const std::string &filename)
returns the full absolute filename
some definitions to work with optimizer master switches
std::size_t getNrOfImages() const
number of images.
std::string getExtension(const std::string &basename2)
Get extension of a filename.
ImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
std::string stripExtension(const std::string &basename2)
remove extension of a filename
unsigned int addImage(const SrcPanoImage &img)
the the number for a specific image
Same as above, but use a non const panorama.
bool readVignettingFromDB()
tries to read vignetting data from lens database you need to call SrcPanoImage::readEXIF before to fi...
const PanoramaOptions & getOptions() const
returns the options for this panorama
bool readDistortionFromDB()
tries to read distortion data from lens database you need to call SrcPanoImage::readEXIF before to fi...
bool readEXIF()
try to fill out information about the image, by examining the exif data
void setSize(vigra::Size2D val)
Set the image size in pixels.
std::string GetHuginVersion()
return a string with version numbers
void update()
Update part numbers for each variable group.
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
static void info(const char *fmt,...)
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
void setOptions(const PanoramaOptions &opt)
set new output settings This is not used directly for optimizing/stiching, but it can be feed into ru...
bool IsRawExtension(const std::string testExt)
return true if extension belongs to a raw file
std::size_t getNumberOfParts() const
get the number of parts.
All variables of a source image.
void switchParts(unsigned int ImageNr, unsigned int partNr)
switch a given image to a different part number.
const bool hasPossibleStacks() const
return true, if the metadata indicates that the projects is a bracketet project
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
double outputExposureValue
int main(int argc, char *argv[])