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"))
331 catch(std::exception& e)
333 std::cerr <<
"ERROR: caught exception: " << e.what() << std::endl;
334 std::cerr <<
"Could not read image information for file " << filelist[i] << std::endl;
335 std::cerr <<
"Skipping this image." << std::endl << std::endl;
351 srcImage.setHFOV(fov);
352 if(srcImage.getCropFactor()==0)
354 srcImage.setCropFactor(1.0);
362 std::cout <<
"\tNo value for field of view found in EXIF data. " << std::endl
363 <<
"\tAssuming a HFOV of 50 degrees. " << std::endl;
364 srcImage.setHFOV(50);
365 srcImage.setCropFactor(1.0);
368 if(cropRect.width()>0 && cropRect.height()>0)
378 srcImage.setAutoCenterCrop(
false);
379 srcImage.setCropRect(cropRect);
385 std::cout <<
"\tRead distortion data from lens database." << std::endl;
389 std::cout <<
"\tNo valid distortion data found in lens database." << std::endl;
396 std::cout <<
"\tRead vignetting data from lens database." << std::endl;
400 std::cout <<
"\tNo valid vignetting data found in lens database." << std::endl;
405 redBalanceAnchor = srcImage.getExifRedBalance();
406 blueBalanceAnchor = srcImage.getExifBlueBalance();
407 if (fabs(redBalanceAnchor)<1e-2)
409 redBalanceAnchor = 1;
411 if (fabs(blueBalanceAnchor)<1e-2)
413 blueBalanceAnchor = 1;
418 srcImage.setWhiteBalanceRed(srcImage.getExifRedBalance() / redBalanceAnchor);
419 srcImage.setWhiteBalanceBlue(srcImage.getExifBlueBalance() / blueBalanceAnchor);
426 std::cerr <<
"Adding images to project files failed." << std::endl;
441 for(
size_t j=0; j<i; j++)
444 if(srcImg.getHFOV()==compareImg.getHFOV() &&
445 srcImg.getProjection()==compareImg.getProjection() &&
446 srcImg.getExifModel()==compareImg.getExifModel() &&
447 srcImg.getExifMake()==compareImg.getExifMake() &&
448 srcImg.getSize()==compareImg.getSize())
459 std::cout << std::endl <<
"Assigned " << lenses.
getNumberOfParts() <<
" lenses." << std::endl;
462 std::cout <<
"Project contains more than one lens, but you requested to assign" << std::endl
463 <<
"stacks. This is not supported. Therefore stacks will not be" << std::endl
464 <<
"assigned." << std::endl << std::endl;
468 if (stackLength == 0)
480 stackLength = std::min<int>(stackLength, pano.
getNrOfImages());
488 for (
size_t stackNr = 0; stackNr < stackCount; stackNr++)
490 size_t firstImgStack = stackNr*stackLength;
491 for (
size_t i = 0; i < stackLength; i++)
495 pano.linkImageVariableStack(firstImgStack, firstImgStack + i);
498 pano.linkImageVariableYaw(firstImgStack, firstImgStack + i);
499 pano.linkImageVariablePitch(firstImgStack, firstImgStack + i);
500 pano.linkImageVariableRoll(firstImgStack, firstImgStack + i);
501 pano.linkImageVariableX(firstImgStack, firstImgStack + i);
502 pano.linkImageVariableY(firstImgStack, firstImgStack + i);
503 pano.linkImageVariableZ(firstImgStack, firstImgStack + i);
504 pano.linkImageVariableTranslationPlaneYaw(firstImgStack, firstImgStack + i);
505 pano.linkImageVariableTranslationPlanePitch(firstImgStack, firstImgStack + i);
518 std::cout <<
"Assigned " << stackCount <<
" stacks: " << std::endl
519 <<
"\t" << (linkStacks ?
"Linking position of images in stacks" :
"Use individual positions of images in stacks") << std::endl;
541 output=output.append(
".pto");
547 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 IsLinearICCProfile(const vigra::ImageImportInfo::ICCProfile &iccProfile)
return true if icc profile is linear one, otherwise return false
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[])