Hugin trunk 0.1
Loading...
Searching...
No Matches
pto_gen.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
2
11/* This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
15 *
16 * This software is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public
22 * License along with this software. If not, see
23 * <http://www.gnu.org/licenses/>.
24 *
25 */
26
27#include <fstream>
28#include <getopt.h>
29#ifdef _WIN32
30#include <io.h>
31#endif
32#include <vigra/imageinfo.hxx>
33#include <panodata/Panorama.h>
38#include <lensdb/LensDB.h>
39
40#ifdef __APPLE__
41#include <hugin_config.h>
42#include <mach-o/dyld.h> /* _NSGetExecutablePath */
43#include <limits.h> /* PATH_MAX */
44#include <libgen.h> /* dirname */
45#endif
46
47static void usage(const char* name)
48{
49 std::cout << name << ": generate project file from images" << std::endl
50 << name << " version " << hugin_utils::GetHuginVersion() << std::endl
51 << std::endl
52 << "Usage: " << name << " [options] image1 [...]" << std::endl
53 << 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
75 << std::endl;
76}
77
78int main(int argc, char* argv[])
79{
80 // parse arguments
81 const char* optstring = "o:p:f:c:s:lh";
82
83 enum {
88 };
89 static struct option longOptions[] =
90 {
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 },
101 {"help", no_argument, NULL, 'h' },
102
103 0
104 };
105
106 int c;
107 std::string output;
108 int projection=-1;
109 float fov=-1;
110 int stackLength=0;
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)
118 {
119 switch (c)
120 {
121 case 'o':
122 output = optarg;
123 break;
124 case 'h':
126 return 0;
127 case 'p':
128 {
129 projection=atoi(optarg);
130 if((projection==0) && (strcmp(optarg,"0")!=0))
131 {
132 std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse image number." << std::endl;
133 return 1;
134 };
135 if(projection<0)
136 {
137 std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid projection number." << std::endl;
138 return 1;
139 };
140 };
141 break;
142 case 'f':
143 fov=atof(optarg);
144 // normally fov should be <=360
145 // but for some multi-lens cameras/one shot panoramic cameras these images can also
146 // have a fov>360 because the fisheye projections covers only a small portion of the
147 // the whole image
148 if(fov<1 || fov>500)
149 {
150 std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid field of view" << std::endl;
151 return 1;
152 };
153 break;
154 case 'c':
155 {
156 int left, right, top, bottom;
157 int n=sscanf(optarg, "%d,%d,%d,%d", &left, &right, &top, &bottom);
158 if (n==4)
159 {
160 if(right>left && bottom>top)
161 {
162 cropRect.setUpperLeft(vigra::Point2D(left,top));
163 cropRect.setLowerRight(vigra::Point2D(right,bottom));
164 }
165 else
166 {
167 std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid crop area" << std::endl;
168 return 1;
169 };
170 }
171 else
172 {
173 std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse crop values" << std::endl;
174 return 1;
175 };
176 };
177 break;
178 case 's':
180 if ((stackLength == 0) && (strcmp(optarg, "0") != 0))
181 {
182 std::cerr << hugin_utils::stripPath(argv[0]) << ": Could not parse stack length." << std::endl;
183 return 1;
184 };
185 break;
186 case 'l':
187 linkStacks=true;
188 break;
190 loadDistortion=true;
191 break;
193 loadVignetting=true;
194 break;
197 break;
199 sortByFilename = true;
200 break;
201 case ':':
202 case '?':
203 // missing argument or invalid switch
204 return 1;
205 break;
206 default:
207 // this should not happen
208 abort ();
209 }
210 }
211
212 if (argc - optind < 1)
213 {
214 std::cerr << hugin_utils::stripPath(argv[0]) << ": No image files given." << std::endl;
215 return 1;
216 };
217
218 std::cout << "Generating pto file..." << std::endl;
219 std::cout.flush();
220
221 std::vector<std::string> filelist;
222 while(optind<argc)
223 {
224 std::string input;
225#ifdef _WIN32
226 //do globbing
228 char drive[_MAX_DRIVE];
229 char dir[_MAX_DIR];
230 _splitpath(input.c_str(), drive, dir, NULL, NULL);
231
232 struct _finddata_t finddata;
234 if (findhandle != -1)
235 {
236 do
237 {
238 //ignore folder, can be happen when using *.*
239 if((finddata.attrib & _A_SUBDIR)==0)
240 {
241 char fname[_MAX_FNAME];
242 char ext[_MAX_EXT];
243 char newFile[_MAX_PATH];
246 //check if valid image file
247 if(vigra::isImage(newFile))
248 {
249 filelist.push_back(std::string(newFile));
250 };
251 };
252 }
253 while (_findnext(findhandle, &finddata) == 0);
255 }
256#else
259 {
260 if(vigra::isImage(input.c_str()))
261 {
263 };
264 };
265#endif
266 optind++;
267 };
268
269 if(filelist.empty())
270 {
271 std::cerr << hugin_utils::stripPath(argv[0]) << ": No valid image files given." << std::endl;
272 return 1;
273 };
274
275 //sort filenames if requested
276 if (sortByFilename)
277 {
278 sort(filelist.begin(), filelist.end(), doj::alphanum_less());
279 };
280
282 double redBalanceAnchor = 1.0;
283 double blueBalanceAnchor = 1.0;
284 for(size_t i=0; i<filelist.size(); i++)
285 {
286 const std::string ext = hugin_utils::getExtension(filelist[i]);
287 // check that extension does not belong to a raw file
289 {
290 std::cerr << "Ignoring raw file " << filelist[i] << "." << std::endl;
291 continue;
292 };
294 std::cout << "Reading " << filelist[i] << "..." << std::endl;
295 srcImage.setFilename(filelist[i]);
296 try
297 {
298 vigra::ImageImportInfo info(filelist[i].c_str());
299 if(info.width()==0 || info.height()==0)
300 {
301 std::cerr << "ERROR: Could not decode image " << filelist[i] << std::endl
302 << "Skipping this image." << std::endl << std::endl;
303 continue;
304 }
305 srcImage.setSize(info.size());
306 // check for black/white images
307 const std::string pixelType=info.getPixelType();
308 if (pixelType == "BILEVEL")
309 {
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;
313 continue;
314 }
315 if((pixelType=="UINT8") || (pixelType=="UINT16") || (pixelType=="INT16"))
316 {
317 if (hugin_utils::IsLinearICCProfile(info.getICCProfile()))
318 {
319 srcImage.setResponseType(HuginBase::SrcPanoImage::RESPONSE_LINEAR);
320 }
321 else
322 {
323 srcImage.setResponseType(HuginBase::SrcPanoImage::RESPONSE_EMOR);
324 }
325 }
326 else
327 {
328 srcImage.setResponseType(HuginBase::SrcPanoImage::RESPONSE_LINEAR);
329 };
330 }
331 catch(std::exception& e)
332 {
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;
336 continue;
337 };
338
339 srcImage.readEXIF();
340 bool fovOk=srcImage.applyEXIFValues();
341 if(projection>=0)
342 {
343 srcImage.setProjection((HuginBase::BaseSrcPanoImage::Projection)projection);
344 }
345 else
346 {
347 srcImage.readProjectionFromDB(ignoreFovRectilinear);
348 };
349 if(fov>0)
350 {
351 srcImage.setHFOV(fov);
352 if(srcImage.getCropFactor()==0)
353 {
354 srcImage.setCropFactor(1.0);
355 };
356 }
357 else
358 {
359 //set plausible default value if they could not read from exif
360 if(!fovOk)
361 {
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);
366 };
367 };
368 if(cropRect.width()>0 && cropRect.height()>0)
369 {
370 if(srcImage.isCircularCrop())
371 {
372 srcImage.setCropMode(HuginBase::SrcPanoImage::CROP_CIRCLE);
373 }
374 else
375 {
376 srcImage.setCropMode(HuginBase::SrcPanoImage::CROP_RECTANGLE);
377 };
378 srcImage.setAutoCenterCrop(false);
379 srcImage.setCropRect(cropRect);
380 };
381 if(loadDistortion)
382 {
383 if(srcImage.readDistortionFromDB())
384 {
385 std::cout << "\tRead distortion data from lens database." << std::endl;
386 }
387 else
388 {
389 std::cout << "\tNo valid distortion data found in lens database." << std::endl;
390 };
391 };
393 {
394 if(srcImage.readVignettingFromDB())
395 {
396 std::cout << "\tRead vignetting data from lens database." << std::endl;
397 }
398 else
399 {
400 std::cout << "\tNo valid vignetting data found in lens database." << std::endl;
401 };
402 };
403 if (pano.getNrOfImages() == 0)
404 {
405 redBalanceAnchor = srcImage.getExifRedBalance();
406 blueBalanceAnchor = srcImage.getExifBlueBalance();
407 if (fabs(redBalanceAnchor)<1e-2)
408 {
410 };
411 if (fabs(blueBalanceAnchor)<1e-2)
412 {
414 };
415 }
416 else
417 {
418 srcImage.setWhiteBalanceRed(srcImage.getExifRedBalance() / redBalanceAnchor);
419 srcImage.setWhiteBalanceBlue(srcImage.getExifBlueBalance() / blueBalanceAnchor);
420 };
421 pano.addImage(srcImage);
422 };
423
424 if(pano.getNrOfImages()==0)
425 {
426 std::cerr << "Adding images to project files failed." << std::endl;
428 return 1;
429 };
430
431 //link lenses
432 if(pano.getNrOfImages()>1)
433 {
436
437 for(size_t i=1; i<pano.getNrOfImages(); i++)
438 {
439 int image=-1;
441 for(size_t j=0; j<i; j++)
442 {
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())
449 {
450 image=j;
451 break;
452 };
453 };
454 if(image!=-1)
455 {
456 lenses.switchParts(i,lenses.getPartNumber(image));
457 };
458 };
459 std::cout << std::endl << "Assigned " << lenses.getNumberOfParts() << " lenses." << std::endl;
460 if(lenses.getNumberOfParts()>1 && stackLength!=1)
461 {
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;
465 stackLength=1;
466 };
467
468 if (stackLength == 0)
469 {
470 // automatic detection
471 if (pano.hasPossibleStacks())
472 {
474 };
475 }
476 else
477 {
478 if (stackLength > 1)
479 {
480 stackLength = std::min<int>(stackLength, pano.getNrOfImages());
481 int stackCount = pano.getNrOfImages() / stackLength;
482 if (pano.getNrOfImages() % stackLength > 0)
483 {
484 stackCount++;
485 };
486 if (stackCount < pano.getNrOfImages())
487 {
488 for (size_t stackNr = 0; stackNr < stackCount; stackNr++)
489 {
491 for (size_t i = 0; i < stackLength; i++)
492 {
493 if (firstImgStack + i < pano.getNrOfImages())
494 {
495 pano.linkImageVariableStack(firstImgStack, firstImgStack + i);
496 if (linkStacks)
497 {
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);
506 };
507 };
508 };
509 };
510 };
511 };
512 };
513
514 variable_groups.update();
515 const size_t stackCount = variable_groups.getStacks().getNumberOfParts();
516 if (stackCount != pano.getNrOfImages())
517 {
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;
520 };
521 };
522
523 //set output exposure value
526 pano.setOptions(opt);
527 // set optimizer switches
531
532 //output
533 if(output=="")
534 {
535 output=hugin_utils::stripExtension(pano.getImage(0).getFilename());
536 if(pano.getNrOfImages()>1)
537 {
538 output.append("-");
540 };
541 output=output.append(".pto");
542 };
544 //write output
546 {
547 std::cout << std::endl << "Written output to " << output << std::endl;
548 };
549
551 return 0;
552}
class to access Hugins camera and lens database
static void usage()
Definition Main.cpp:32
some definitions to work with optimizer master switches
Somewhere to specify what variables belong to what.
@ RESPONSE_LINEAR
linear response
@ RESPONSE_EMOR
empirical model of response
static double calcMeanExposure(const PanoramaData &pano)
Same as above, but use a non const panorama.
static void Clean()
cleanup the static LensDB instance, must be called at the end of the program
Definition LensDB.cpp:2010
Panorama image options.
Model for a panorama.
Definition Panorama.h:153
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition Panorama.h:211
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition Panorama.h:481
const bool hasPossibleStacks() const
return true, if the metadata indicates that the projects is a bracketet project
void updateOptimizeVector()
updates the optimize vector according to master switches
unsigned int addImage(const SrcPanoImage &img)
the the number for a specific image
Definition Panorama.cpp:319
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 WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
void setPhotometricOptimizerSwitch(const int newSwitch)
sets the photometric optimizer master switch
Definition Panorama.cpp:311
void linkPossibleStacks(bool linkPosition)
create automatically stacks as indicated by metadata
void setOptimizerSwitch(const int newSwitch)
set optimizer master switch
Definition Panorama.cpp:303
std::size_t getNrOfImages() const
number of images.
Definition Panorama.h:205
All variables of a source image.
std::string GetAbsoluteFilename(const std::string &filename)
returns the full absolute filename
Definition utils.cpp:368
std::string stripExtension(const std::string &basename2)
remove extension of a filename
Definition utils.cpp:130
bool IsLinearICCProfile(const vigra::ImageImportInfo::ICCProfile &iccProfile)
return true if icc profile is linear one, otherwise return false
Definition utils.cpp:940
std::string getExtension(const std::string &basename2)
Get extension of a filename.
Definition utils.cpp:99
bool IsRawExtension(const std::string testExt)
return true if extension belongs to a raw file
Definition utils.cpp:970
std::string GetHuginVersion()
return a string with version numbers
Definition utils.cpp:907
bool FileExists(const std::string &filename)
checks if file exists
Definition utils.cpp:362
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
Definition utils.cpp:160
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
Definition utils.cpp:184
int main(int argc, char *argv[])
Definition pto_gen.cpp:78
Functor class to compare two objects with the "Alphanum Algorithm".
Definition alphanum.h:66
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41