Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
align_image_stack.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
2 
27 #include <hugin_config.h>
28 #include <fstream>
29 #include <sstream>
30 #include <iostream>
31 
32 #include <vigra/error.hxx>
33 #include <vigra/cornerdetection.hxx>
34 #include <vigra/localminmax.hxx>
35 #include <hugin_utils/utils.h>
36 
37 #include <vigra_ext/Pyramid.h>
38 #include <vigra_ext/Correlation.h>
40 #include <vigra_ext/impexalpha.hxx>
41 
42 #include <panodata/Panorama.h>
46 #include <nona/Stitcher.h>
48 #include <lensdb/LensDB.h>
49 
50 #include <getopt.h>
51 
53 #include <tiff.h>
54 
55 #ifdef __APPLE__
56 #include <hugin_config.h>
57 #include <mach-o/dyld.h> /* _NSGetExecutablePath */
58 #include <limits.h> /* PATH_MAX */
59 #include <libgen.h> /* dirname */
60 #endif
61 
62 int g_verbose = 0;
63 
64 static void usage(const char* name)
65 {
66  std::cout << name << ": align overlapping images for HDR creation" << std::endl
67  << "align_image_stack version " << hugin_utils::GetHuginVersion() << std::endl
68  << std::endl
69  << "Usage: " << name << " [options] input files" << std::endl
70  << "Valid options are:" << std::endl
71  << " Modes of operation:" << std::endl
72  << " -p file Output .pto file (useful for debugging, or further refinement)" << std::endl
73  << " -a prefix align images, output as prefix_xxxx.tif" << std::endl
74  << " -o output merge images to HDR, generate output.hdr" << std::endl
75  << " Modifiers" << std::endl
76  << " -v Verbose, print progress messages. Repeat for higher verbosity" << std::endl
77  << " -e Assume input images are full frame fish eye (default: rectilinear)" << std::endl
78  << " -t num Remove all control points with an error higher than num pixels" << std::endl
79  << " (default: 3)" << std::endl
80  << " --corr=num Correlation threshold for identifing control points" << std::endl
81  << " (default: 0.9)" << std::endl
82  << " -f HFOV approximate horizontal field of view of input images," << std::endl
83  << " use if EXIF info not complete" << std::endl
84  << " -m Optimize field of view for all images, except for first." << std::endl
85  << " Useful for aligning focus stacks with slightly" << std::endl
86  << " different magnification." << std::endl
87  << " -d Optimize radial distortion for all images, except for first." << std::endl
88  << " -i Optimize image center shift for all images, except for first." << std::endl
89  << " -x Optimize X coordinate of the camera position." << std::endl
90  << " -y Optimize Y coordinate of the camera position." << std::endl
91  << " -z Optimize Z coordinate of the camera position." << std::endl
92  << " Useful for aligning more distorted images." << std::endl
93  << " -S Assume stereo images - allow horizontal shift of control points." << std::endl
94  << " -A Align stereo window - assumes -S." << std::endl
95  << " -P Align stereo window with pop-out effect - assumes -S." << std::endl
96  << " -C Auto crop the image to the area covered by all images." << std::endl
97  << " -c num number of control points (per grid) to create" << std::endl
98  << " between adjacent images (default: 8)" << std::endl
99  << " -l Assume linear input files" << std::endl
100  << " -s scale Scale down image by 2^scale (default: 1 [2x downsampling])" << std::endl
101  << " -g gsize Break image into a rectangular grid (gsize x gsize) and attempt" << std::endl
102  << " to find num control points in each section" << std::endl
103  << " (default: 5 [5x5 grid] )" << std::endl
104  << " --distortion Try to load distortion information from lens database" << std::endl
105  << " --use-given-order Use the image order as given from command line" << std::endl
106  << " (By default images will be sorted by exposure values.)" << std::endl
107  << " --align-to-first Align all images to the first one. By default" << std::endl
108  << " align_image_stack matches all image pairs" << std::endl
109  << " consecutive." << std::endl
110  << " This implies also the --use-given-order option" << std::endl
111  << " --dont-remap-ref Don't output the remapped reference image" << std::endl
112  << " --gpu Use GPU for remapping" << std::endl
113  << " -h Display help (this text)" << std::endl
114  << std::endl;
115 }
116 
117 typedef std::multimap<double, vigra::Diff2D> MapPoints;
119 
120 namespace detail
121 {
122  template <class ImageType>
123  vigra_ext::CorrelationResult FineTunePoint(const ImageType& leftImg, const vigra::Diff2D templPos, const int templSize,
124  const ImageType& rightImg, const vigra::Diff2D searchPos, const int searchWidth, vigra::VigraTrueType)
125  {
126  return vigra_ext::PointFineTune(leftImg, leftImg.accessor(),
127  templPos, templSize,
128  rightImg, rightImg.accessor(),
129  searchPos, searchWidth);
130  };
131 
132  template <class ImageType>
133  vigra_ext::CorrelationResult FineTunePoint(const ImageType& leftImg, const vigra::Diff2D templPos, const int templSize,
134  const ImageType& rightImg, const vigra::Diff2D searchPos, const int searchWidth, vigra::VigraFalseType)
135  {
136  return vigra_ext::PointFineTune(leftImg,
137  vigra::RGBToGrayAccessor<typename ImageType::value_type>(),
138  templPos, templSize,
139  rightImg, vigra::RGBToGrayAccessor<typename ImageType::value_type>(),
140  searchPos, searchWidth);
141  };
142 }
143 template <class ImageType>
145  int img1, const ImageType& leftImg, const ImageType& leftImgOrig,
146  int img2, const ImageType& rightImg, const ImageType& rightImgOrig,
147  const MapPoints& points, unsigned nPoints, int pyrLevel, int templWidth, int sWidth, double scaleFactor, double corrThresh, bool stereo)
148 {
149  typedef typename ImageType::value_type ImageValueType;
150  typedef typename vigra::NumericTraits<ImageValueType>::isScalar is_scalar;
151 
152  unsigned nGood = 0;
153  // loop over all points, starting with the highest corner score
154  for (MapPoints::const_reverse_iterator it = points.rbegin(); it != points.rend(); ++it)
155  {
156  if (nGood >= nPoints)
157  {
158  // we have enough points, stop
159  break;
160  }
161 
162  vigra_ext::CorrelationResult res = detail::FineTunePoint(leftImg, it->second, templWidth,
163  rightImg, it->second, sWidth, is_scalar());
164  if (g_verbose > 2)
165  {
166  std::ostringstream buf;
167  buf << "I :" << (*it).second.x* scaleFactor << "," << (*it).second.y* scaleFactor << " -> "
168  << res.maxpos.x* scaleFactor << "," << res.maxpos.y* scaleFactor << ": corr coeff: " << res.maxi
169  << " curv:" << res.curv.x << " " << res.curv.y << std::endl;
170  std::cout << buf.str();
171  }
172  if (res.maxi < corrThresh)
173  {
174  DEBUG_DEBUG("low correlation: " << res.maxi << " curv: " << res.curv);
175  continue;
176  }
177 
178  if (pyrLevel > 0)
179  {
180  res = detail::FineTunePoint(leftImgOrig, vigra::Diff2D((*it).second.x * scaleFactor, (*it).second.y * scaleFactor),
181  templWidth, rightImgOrig, vigra::Diff2D(res.maxpos.x * scaleFactor, res.maxpos.y * scaleFactor),
182  scaleFactor, is_scalar());
183 
184  if (g_verbose > 2)
185  {
186  std::ostringstream buf;
187  buf << "II>" << (*it).second.x* scaleFactor << "," << (*it).second.y* scaleFactor << " -> "
188  << res.maxpos.x << "," << res.maxpos.y << ": corr coeff: " << res.maxi
189  << " curv:" << res.curv.x << " " << res.curv.y << std::endl;
190  std::cout << buf.str();
191  }
192  if (res.maxi < corrThresh)
193  {
194  DEBUG_DEBUG("low correlation in pass 2: " << res.maxi << " curv: " << res.curv);
195  continue;
196  }
197  }
198 
199  nGood++;
200  // add control point
201  HuginBase::ControlPoint p(img1, (*it).second.x * scaleFactor,
202  (*it).second.y * scaleFactor,
203  img2, res.maxpos.x,
204  res.maxpos.y,
206  {
207  hugin_omp::ScopedLock sl(lock);
208  pano.addCtrlPoint(p);
209  };
210  }
211  if (g_verbose > 0)
212  {
213  std::ostringstream buf;
214  buf << "Number of good matches: " << nGood << ", bad matches: " << points.size() - nGood << std::endl;
215  std::cout << buf.str();
216  }
217 };
218 
219 namespace detail
220 {
221  template <class ImageType>
222  void FindInterestPointsPartial(const ImageType& image, const vigra::Rect2D& rect, double scale,
223  unsigned nPoints, std::multimap<double, vigra::Diff2D> &points, vigra::VigraTrueType)
224  {
225  vigra_ext::findInterestPointsPartial(vigra::srcImageRange(image), rect, scale, nPoints, points);
226  };
227 
228  template <class ImageType>
229  void FindInterestPointsPartial(const ImageType& image, const vigra::Rect2D& rect, double scale,
230  unsigned nPoints, std::multimap<double, vigra::Diff2D> &points, vigra::VigraFalseType)
231  {
232  typedef typename ImageType::value_type ImageValueType;
233  vigra_ext::findInterestPointsPartial(vigra::srcImageRange(image, vigra::RGBToGrayAccessor<ImageValueType>()), rect, scale, nPoints, points);
234  };
235 };
236 
237 template <class ImageType>
238 void createCtrlPoints(HuginBase::Panorama& pano, int img1, const ImageType& leftImg, const ImageType& leftImgOrig, int img2, const ImageType& rightImg, const ImageType& rightImgOrig, int pyrLevel, double scale, unsigned nPoints, unsigned grid, double corrThresh = 0.9, bool stereo = false)
239 {
240  typedef typename ImageType::value_type ImageValueType;
241  typedef typename vigra::NumericTraits<ImageValueType>::isScalar is_scalar;
242 
244  // find interesting corners using harris corner detector
245  if (stereo)
246  {
247  // add one vertical control point to keep the images aligned vertically
248  HuginBase::ControlPoint p(img1, 0, 0, img2, 0, 0, HuginBase::ControlPoint::X);
249  pano.addCtrlPoint(p);
250  }
251 
252  if (g_verbose > 0)
253  {
254  std::cout << "Trying to find " << nPoints << " corners... " << std::endl;
255  }
256 
257  vigra::Size2D size(leftImg.width(), leftImg.height());
258  std::vector<vigra::Rect2D> rects;
259  for (unsigned party = 0; party < grid; party++)
260  {
261  for (unsigned partx = 0; partx < grid; partx++)
262  {
263  // run corner detector only in current sub-region (saves a lot of memory for big images)
264  vigra::Rect2D rect(partx*size.x / grid, party*size.y / grid,
265  (partx + 1)*size.x / grid, (party + 1)*size.y / grid);
266  rect &= vigra::Rect2D(size);
267  if (rect.width()>0 && rect.height()>0)
268  {
269  rects.push_back(rect);
270  };
271  };
272  };
273 
274  const double scaleFactor = 1 << pyrLevel;
275  const long templWidth = 20;
276  const long sWidth = 100;
277 
278  #pragma omp parallel for schedule(dynamic)
279  for (int i = 0; i < rects.size(); ++i)
280  {
281  MapPoints points;
282  vigra::Rect2D rect(rects[i]);
283  detail::FindInterestPointsPartial(leftImg, rect, scale, 5 * nPoints, points, is_scalar());
284  FineTuneInterestPoints(pano, img1, leftImg, leftImgOrig, img2, rightImg, rightImgOrig, points, nPoints, pyrLevel, templWidth, sWidth, scaleFactor, corrThresh, stereo);
285  };
286 
287  if (stereo)
288  {
289  // add some additional control points around image edges
290  // this is useful for better results - images are more distorted around edges
291  // and also for stereoscopic window adjustment - it must be alligned according to
292  // the nearest object which crosses the edge and these control points helps to find it.
293  MapPoints up;
294  MapPoints down;
295  MapPoints left;
296  MapPoints right;
297  int xstep = leftImg.size().x / (nPoints + 1);
298  int ystep = leftImg.size().y / (nPoints + 1);
299  for (int k = 6; k >= 0; --k)
300  {
301  for (int j = 0; j < 2; ++j)
302  {
303  for (unsigned int i = 0; i < nPoints; ++i)
304  {
305  up.insert(std::make_pair(0, vigra::Diff2D(j * xstep / 2 + i * xstep, 1 + k * 10)));
306  down.insert(std::make_pair(0, vigra::Diff2D(j * xstep / 2 + i * xstep, leftImg.size().y - 2 - k * 10)));
307  left.insert(std::make_pair(0, vigra::Diff2D(1 + k * 10, j * ystep / 2 + i * ystep)));
308  right.insert(std::make_pair(0, vigra::Diff2D(leftImg.size().x - 2 - k * 10, j * ystep / 2 + i * ystep)));
309  };
310  };
311  };
312  // execute parallel
313  #pragma omp parallel sections
314  {
315  #pragma omp section
316  {
317  FineTuneInterestPoints(pano, img1, leftImg, leftImgOrig, img2, rightImg, rightImgOrig, up, nPoints, pyrLevel, templWidth, sWidth, corrThresh, scaleFactor, stereo);
318  }
319  #pragma omp section
320  {
321  FineTuneInterestPoints(pano, img1, leftImg, leftImgOrig, img2, rightImg, rightImgOrig, down, nPoints, pyrLevel, templWidth, sWidth, corrThresh, scaleFactor, stereo);
322  }
323  #pragma omp section
324  {
325  FineTuneInterestPoints(pano, img1, leftImg, leftImgOrig, img2, rightImg, rightImgOrig, left, nPoints, pyrLevel, templWidth, sWidth, corrThresh, scaleFactor, stereo);
326  }
327  #pragma omp section
328  {
329  FineTuneInterestPoints(pano, img1, leftImg, leftImgOrig, img2, rightImg, rightImgOrig, right, nPoints, pyrLevel, templWidth, sWidth, corrThresh, scaleFactor, stereo);
330  }
331  }
332  }
333 };
334 
335 void alignStereoWindow(HuginBase::Panorama& pano, bool pop_out)
336 {
337  HuginBase::CPVector cps = pano.getCtrlPoints();
338  std::vector<HuginBase::PTools::Transform*> transTable(pano.getNrOfImages());
339 
340  std::vector<int> max_i(pano.getNrOfImages() - 1, -1); // index of a point with biggest shift
341  std::vector<int> max_i_b(pano.getNrOfImages() - 1, -1); // the same as above, only border points considered
342  std::vector<double> max_dif(pano.getNrOfImages() - 1, -1000000000); // value of the shift
343  std::vector<double> max_dif_b(pano.getNrOfImages() - 1, -1000000000); // the same as above, only border points considered
344 
345  for (int i=0; i < pano.getNrOfImages(); i++)
346  {
347  transTable[i] = new HuginBase::PTools::Transform();
348  transTable[i]->createInvTransform(pano.getImage(i), pano.getOptions());
349  }
350 
351  double rbs = 0.1; // relative border size
352 
353  for (int i=0; i < (int)cps.size(); i++)
354  {
355  if (cps[i].mode == HuginBase::ControlPoint::X)
356  {
357  if (max_i[cps[i].image1Nr] < 0) // first control point for given pair
358  {
359  max_i[cps[i].image1Nr] = i; // use it as a fallback in case on other points exist
360  }
361  continue;
362  }
363 
364  vigra::Size2D size1 = pano.getImage(cps[i].image1Nr).getSize();
365  vigra::Size2D size2 = pano.getImage(cps[i].image2Nr).getSize();
366 
367  vigra::Rect2D rect1(size1);
368  vigra::Rect2D rect2(size2);
369 
370  rect1.addBorder(-size1.width() * rbs, -size1.height() * rbs);
371  rect2.addBorder(-size2.width() * rbs, -size2.height() * rbs);
372 
373 
374  double xt1, yt1, xt2, yt2;
375  if(!transTable[cps[i].image1Nr]->transformImgCoord(xt1, yt1, cps[i].x1, cps[i].y1))
376  {
377  continue;
378  }
379  if(!transTable[cps[i].image2Nr]->transformImgCoord(xt2, yt2, cps[i].x2, cps[i].y2))
380  {
381  continue;
382  }
383 
384  double dif = xt2 - xt1;
385  if (dif > max_dif[cps[i].image1Nr])
386  {
387  max_dif[cps[i].image1Nr] = dif;
388  max_i[cps[i].image1Nr] = i;
389  }
390 
391  if (!(rect1.contains(vigra::Point2D(cps[i].x1, cps[i].y1)) &&
392  rect2.contains(vigra::Point2D(cps[i].x2, cps[i].y2))))
393  {
394  // the same for border points only
395  if (dif > max_dif_b[cps[i].image1Nr])
396  {
397  max_dif_b[cps[i].image1Nr] = dif;
398  max_i_b[cps[i].image1Nr] = i;
399  }
400  }
401  }
402 
403  for (int i=0; i < pano.getNrOfImages(); i++)
404  {
405  delete transTable[i];
406  }
407 
408  for (int i=0; i < (int)max_i.size(); i++)
409  {
410  if (pop_out && (max_i_b[i] >= 0)) // check points at border
411  {
412  cps[max_i_b[i]].mode = HuginBase::ControlPoint::X_Y;
413  }
414  else if (max_i[i] >= 0) // no points at border - use any point
415  {
416  cps[max_i[i]].mode = HuginBase::ControlPoint::X_Y;
417  }
418  else
419  {
420  //no points at all - should not happen
421  }
422 
423  }
424 
425  HuginBase::CPVector newCPs;
426  for (int i=0; i < (int)cps.size(); i++)
427  {
428  if (cps[i].mode != HuginBase::ControlPoint::X) // remove the vertical control lines, X_Y points replaces them
429  {
430  newCPs.push_back(cps[i]);
431  }
432  }
433 
434  pano.setCtrlPoints(newCPs);
435 }
436 
438 {
440  HuginBase::CalculateOptimalROI cropPano(pano, &dummy, true);
441  cropPano.run();
442 
443  vigra::Rect2D roi=cropPano.getResultOptimalROI();
444  //set the ROI - fail if the right/bottom is zero, meaning all zero
445  if(!roi.isEmpty())
446  {
448  opt.setROI(roi);
449  pano.setOptions(opt);
450  std::cout << "Set crop size to " << roi.left() << "," << roi.top() << "," << roi.right() << "," << roi.bottom() << std::endl;
451  }
452  else
453  {
454  std::cout << "Could not find best crop rectangle for image" << std::endl;
455  };
456 }
457 
459 {
461  {
462  cpErrorThreshold = 3;
463  corrThresh = 0.9;
464  nPoints = 8;
465  grid = 5;
466  hfov = 0;
467  pyrLevel = 1;
468  linear = false; // Assume linear input files if true
469  optHFOV = false;
470  optDistortion = false;
471  optCenter = false;
472  optX = false;
473  optY = false;
474  optZ = false;
475  stereo = false;
476  stereo_window = false;
477  pop_out = false;
478  crop = false;
479  fisheye = false;
480  gpu = false;
481  loadDistortion = false;
482  sortImagesByEv = true;
483  alignToFirst = false;
484  dontRemapRef = false;
485  }
486 
488  double corrThresh;
489  int nPoints;
490  int grid; // Partition images into grid x grid subregions, each with npoints
491  double hfov;
492  bool linear;
493  bool optHFOV;
495  bool optCenter;
496  bool optX;
497  bool optY;
498  bool optZ;
499  bool fisheye;
500  bool stereo;
502  bool pop_out;
503  bool crop;
504  bool gpu;
509  int pyrLevel;
510  std::string alignedPrefix;
511  std::string ptoFile;
512  std::string hdrFile;
513  std::string basename;
514 };
515 
516 // dummy panotools progress functions
517 static int ptProgress(int command, char* argument)
518 {
519  return 1;
520 }
521 static int ptinfoDlg(int command, char* argument)
522 {
523  return 1;
524 }
525 
527 {
528 public:
529  explicit SortImageVectorEV(const HuginBase::Panorama* pano) : m_pano(pano) {};
530  bool operator()(const unsigned int i, const unsigned int j)
531  {
532  return m_pano->getImage(i).getExposureValue() > m_pano->getImage(j).getExposureValue();
533  };
534 private:
536 };
537 
538 template <class PixelType>
539 int main2(std::vector<std::string> files, Parameters param)
540 {
541  typedef vigra::BasicImage<PixelType> ImageType;
542  try
543  {
544  HuginBase::Panorama pano;
545  HuginBase::Lens l;
546 
547  // add the first image.to the panorama object
549  srcImg.setFilename(files[0]);
550 
551  if (param.fisheye)
552  {
553  srcImg.setProjection(HuginBase::SrcPanoImage::FULL_FRAME_FISHEYE);
554  }
555  srcImg.readEXIF();
556  srcImg.applyEXIFValues();
557  // for maximum and minimum exposure value of all images
558  double maxEv = 0;
559  double minEv = 0;
560  if (param.sortImagesByEv)
561  {
562  if (fabs(srcImg.getExposureValue()) < 1E-6)
563  {
564  // no exposure values found in file, don't sort images
565  param.sortImagesByEv = false;
566  }
567  else
568  {
569  maxEv = srcImg.getExposureValue();
570  minEv = srcImg.getExposureValue();
571  };
572  };
573  // disable autorotate
574  srcImg.setRoll(0);
575  if (srcImg.getSize().x == 0 || srcImg.getSize().y == 0)
576  {
577  std::cerr << "Could not decode image: " << files[0] << "Unsupported image file format" << std::endl;
578  return 1;
579  }
580 
581  if(param.loadDistortion)
582  {
583  if(srcImg.readDistortionFromDB())
584  {
585  std::cout << "\tRead distortion data from lens database." << std::endl;
586  }
587  else
588  {
589  std::cout << "\tNo valid distortion data found in lens database." << std::endl;
590  }
591  }
592 
593  // use hfov specified by user.
594  if (param.hfov > 0)
595  {
596  srcImg.setHFOV(param.hfov);
597  }
598  else if (srcImg.getCropFactor() == 0)
599  {
600  // could not read HFOV, assuming default: 50
601  srcImg.setHFOV(50);
602  }
603 
604  if (param.linear)
605  {
606  srcImg.setResponseType(HuginBase::SrcPanoImage::RESPONSE_LINEAR);
607  if (g_verbose>0)
608  {
609  std::cout << "Using linear response" << std::endl;
610  }
611  }
612 
613  pano.addImage(srcImg);
614 
615  // setup output to be exactly similar to input image
617 
618  if (param.fisheye)
619  {
621  }
622  else
623  {
625  }
626  opts.setHFOV(srcImg.getHFOV(), false);
627  opts.setWidth(srcImg.getSize().x, false);
628  opts.setHeight(srcImg.getSize().y);
629  // output to tiff format
631  opts.tiff_saveROI = false;
632  // m estimator, to be more robust against points on moving objects
633  opts.huberSigma = 2;
634  // save also exposure value of first image
635  opts.outputExposureValue = srcImg.getExposureValue();
636  pano.setOptions(opts);
637 
638  // variables that should be optimized
639  // optimize nothing in the first image
640  HuginBase::OptimizeVector optvars(1);
641  std::vector<unsigned int> images;
642  images.push_back(0);
643 
644  HuginBase::StandardImageVariableGroups variable_groups(pano);
645 
646  // loop to add images.
647  for (int i = 1; i < (int) files.size(); i++)
648  {
649  // add next image.
650  srcImg.setFilename(files[i]);
651  // reset size to force new detection of image size
652  srcImg.setSize(vigra::Size2D());
653  srcImg.readEXIF();
654  srcImg.applyEXIFValues();
655  if (srcImg.getSize().x == 0 || srcImg.getSize().y == 0)
656  {
657  std::cerr << "Could not decode image: " << files[i] << "Unsupported image file format" << std::endl;
658  return 1;
659  }
660  if (pano.getImage(0).getSize() != srcImg.getSize())
661  {
662  std::cerr << "Images have different sizes." << std::endl
663  << files[0] << " has " << pano.getImage(0).getSize() << " pixel, while " << std::endl
664  << files[i] << " has " << srcImg.getSize() << " pixel." << std::endl
665  << "This is not supported. Align_image_stack works only with images of the same size." << std::endl;
666  return 1;
667  };
668  if (param.sortImagesByEv)
669  {
670  const double exposureValue = srcImg.getExposureValue();
671  if (exposureValue > maxEv)
672  {
673  maxEv = exposureValue;
674  };
675  if (exposureValue < minEv)
676  {
677  minEv = exposureValue;
678  };
679  };
680 
681  if(param.loadDistortion)
682  {
683  if(srcImg.readDistortionFromDB())
684  {
685  std::cout << "\tRead distortion data from lens database." << std::endl;
686  }
687  else
688  {
689  std::cout << "\tNo valid distortion data found in lens database." << std::endl;
690  }
691  }
692 
693  if (param.hfov > 0)
694  {
695  srcImg.setHFOV(param.hfov);
696  }
697  else if (srcImg.getCropFactor() == 0)
698  {
699  // could not read HFOV, assuming default: 50
700  srcImg.setHFOV(50);
701  }
702 
703  int imgNr = pano.addImage(srcImg);
704  variable_groups.update();
705  // each image shares the same lens.
706  variable_groups.getLenses().switchParts(imgNr, 0);
707  // unlink HFOV?
708  if (param.optHFOV)
709  {
710  pano.unlinkImageVariableHFOV(0);
711  }
712  if (param.optDistortion)
713  {
714  pano.unlinkImageVariableRadialDistortion(0);
715  }
716  if (param.optCenter)
717  {
718  pano.unlinkImageVariableRadialDistortionCenterShift(0);
719  }
720  // All images are in the same stack: Link the stack variable.
721  pano.linkImageVariableStack(0, imgNr);
722  images.push_back(i);
723  // optimize yaw, roll, pitch
724  std::set<std::string> vars;
725  vars.insert("y");
726  vars.insert("p");
727  vars.insert("r");
728  if (param.optHFOV)
729  {
730  vars.insert("v");
731  }
732  if (param.optDistortion)
733  {
734  vars.insert("a");
735  vars.insert("b");
736  vars.insert("c");
737  }
738  if (param.optCenter)
739  {
740  vars.insert("d");
741  vars.insert("e");
742  }
743  if (param.optX)
744  {
745  vars.insert("TrX");
746  }
747  if (param.optY)
748  {
749  vars.insert("TrY");
750  }
751  if (param.optZ)
752  {
753  vars.insert("TrZ");
754  }
755  optvars.push_back(vars);
756 
757  };
758 
759  // sort now all images by exposure value
760  if (param.sortImagesByEv)
761  {
762  // if exposure value spread is too small disable sorting
763  // this can happen e.g. for focus stacks
764  if (maxEv - minEv > 0.05)
765  {
766  std::sort(images.begin(), images.end(), SortImageVectorEV(&pano));
767  }
768  else
769  {
770  param.sortImagesByEv = false;
771  std::cout << "WARNING: Spread of exposure values is very small." << std::endl
772  << " Disabling sorting images by exposure value." << std::endl << std::endl;
773  };
774  };
775 
776  // load first image
777  vigra::ImageImportInfo firstImgInfo(pano.getSrcImage(images[0]).getFilename().c_str());
778 
779  // original size
780  ImageType* leftImgOrig = new ImageType(firstImgInfo.size());
781  // rescale image
782  ImageType* leftImg = new ImageType();
783  {
784  if(firstImgInfo.numExtraBands() == 1)
785  {
786  vigra::BImage alpha(firstImgInfo.size());
787  vigra::importImageAlpha(firstImgInfo, destImage(*leftImgOrig), destImage(alpha));
788  }
789  else if (firstImgInfo.numExtraBands() == 0)
790  {
791  vigra::importImage(firstImgInfo, destImage(*leftImgOrig));
792  }
793  else
794  {
795  vigra_fail("Images with multiple extra (alpha) channels not supported");
796  }
797  vigra_ext::reduceNTimes(*leftImgOrig, *leftImg, param.pyrLevel);
798  }
799 
800 
801  ImageType* rightImg = new ImageType(leftImg->size());
802  ImageType* rightImgOrig = new ImageType(leftImgOrig->size());
803  // loop to add control points between them.
804  for (int i = 1; i < (int) images.size(); i++)
805  {
806  if (g_verbose > 0)
807  {
808  if (param.alignToFirst)
809  {
810  std::cout << "Creating control points between " << pano.getSrcImage(images[0]).getFilename().c_str() << " and " <<
811  pano.getSrcImage(images[i]).getFilename().c_str() << std::endl;
812  }
813  else
814  {
815  std::cout << "Creating control points between " << pano.getSrcImage(images[i - 1]).getFilename().c_str() << " and " <<
816  pano.getSrcImage(images[i]).getFilename().c_str() << std::endl;
817  };
818  }
819 
820  // load the actual image data of the next image
821  vigra::ImageImportInfo nextImgInfo(pano.getSrcImage(images[i]).getFilename().c_str());
822  assert(nextImgInfo.size() == firstImgInfo.size());
823  {
824  if (nextImgInfo.numExtraBands() == 1)
825  {
826  vigra::BImage alpha(nextImgInfo.size());
827  vigra::importImageAlpha(nextImgInfo, destImage(*rightImgOrig), destImage(alpha));
828  }
829  else if (nextImgInfo.numExtraBands() == 0)
830  {
831  vigra::importImage(nextImgInfo, destImage(*rightImgOrig));
832  }
833  else
834  {
835  vigra_fail("Images with multiple extra (alpha) channels not supported");
836  }
837  vigra_ext::reduceNTimes(*rightImgOrig, *rightImg, param.pyrLevel);
838  }
839 
840  // add control points.
841  // work on smaller images
842  // TODO: or use a fast interest point operator.
843  if (param.alignToFirst)
844  {
845  createCtrlPoints(pano, 0, *leftImg, *leftImgOrig, images[i], *rightImg, *rightImgOrig, param.pyrLevel, 2, param.nPoints, param.grid, param.corrThresh, param.stereo);
846  vigra::initImage(vigra::destImageRange(*rightImg), vigra::NumericTraits<PixelType>::zero());
847  vigra::initImage(vigra::destImageRange(*rightImgOrig), vigra::NumericTraits<PixelType>::zero());
848  }
849  else
850  {
851  createCtrlPoints(pano, images[i - 1], *leftImg, *leftImgOrig, images[i], *rightImg, *rightImgOrig, param.pyrLevel, 2, param.nPoints, param.grid, param.corrThresh, param.stereo);
852 
853  // swap images;
854  delete leftImg;
855  delete leftImgOrig;
856  leftImg = rightImg;
857  leftImgOrig = rightImgOrig;
858  rightImg = new ImageType(leftImg->size());
859  rightImgOrig = new ImageType(leftImgOrig->size());
860  };
861  }
862  delete leftImg;
863  delete rightImg;
864  delete leftImgOrig;
865  delete rightImgOrig;
866 
867  // optimize everything.
868  pano.setOptimizeVector(optvars);
869  // disable optimizer progress messages if -v not given
870  if (g_verbose == 0)
871  {
872  PT_setProgressFcn(ptProgress);
873  PT_setInfoDlgFcn(ptinfoDlg);
874  };
875  bool optimizeError = (HuginBase::PTools::optimize(pano) > 0);
876 
877  // need to do some basic outlier pruning.
878  // remove all points with error higher than a specified threshold
879  if (param.cpErrorThreshold > 0)
880  {
881  HuginBase::CPVector cps = pano.getCtrlPoints();
882  HuginBase::CPVector newCPs;
883  for (int i=0; i < (int)cps.size(); i++)
884  {
885  if (cps[i].error < param.cpErrorThreshold ||
886  cps[i].mode == HuginBase::ControlPoint::X) // preserve the vertical control point for stereo alignment
887  {
888  newCPs.push_back(cps[i]);
889  }
890  }
891  if (g_verbose > 0)
892  {
893  std::cout << "Ctrl points before pruning: " << cps.size() << ", after: " << newCPs.size() << std::endl;
894  }
895  pano.setCtrlPoints(newCPs);
896  if (param.stereo_window)
897  {
898  alignStereoWindow(pano, param.pop_out);
899  }
900  if (param.optHFOV)
901  {
902  // check that reference image contains cp, otherwise optimizing hfov
903  // goes haywire
904  if (pano.getCtrlPointsForImage(0).empty())
905  {
906  std::cerr << std::endl << "After control points pruning reference images has no control" << std::endl
907  << "points Optimizing field of view in this case results in undefined" << std::endl
908  << "behaviour. Increase error distance (-t parameter), tweak cp" << std::endl
909  << "detection parameters or don't optimize HFOV." << std::endl
910  << std::endl
911  << "Exiting..." << std::endl;
912  return 1;
913  };
914  };
915  // reoptimize
916  // check that we have enough control points left
917  if (pano.getNrOfCtrlPoints() < pano.getOptimizeVector().size())
918  {
919  std::cerr << std::endl << "After control points pruning there are only " << pano.getNrOfCtrlPoints() << " control points" << std::endl
920  << "left, but you selected " << pano.getOptimizeVector().size() << " parameters to optimize." << std::endl
921  << "This will give strange results." << std::endl
922  << "Increase error distance (-t parameter), tweak cp" << std::endl
923  << "detection parameters or select less parameters to optimize." << std::endl
924  << std::endl
925  << "Exiting..." << std::endl;
926  return 1;
927  }
928  optimizeError = (HuginBase::PTools::optimize(pano) > 0);
929  }
930 
931  if (param.crop)
932  {
933  autoCrop(pano);
934  }
935  // deactivate ref image if requested
936  if (param.dontRemapRef)
937  {
938  pano.activateImage(0, false);
939  };
940 
941  HuginBase::UIntSet imgs = pano.getActiveImages();
942  // some check for valid output
943  HuginBase::UIntSet outputImages = HuginBase::getImagesinROI(pano, imgs);
944  if (optimizeError || outputImages.size() != imgs.size())
945  {
946  if (!param.ptoFile.empty())
947  {
948  pano.WritePTOFile(param.ptoFile);
949  }
950  std::cerr << "An error occurred during optimization." << std::endl;
951  if (param.ptoFile.empty())
952  {
953  std::cerr << "Try adding \"-p debug.pto\" and checking output." << std::endl;
954  }
955  else
956  {
957  std::cerr << "Check output file " << param.ptoFile << " for details." << std::endl;
958  };
959  std::cerr << "Exiting..." << std::endl;
960  return 1;
961  }
962 
963  if (param.hdrFile.size())
964  {
965  // TODO: photometric alignment (HDR, fixed white balance)
966  //utils::StreamProgressReporter progress(2.0);
967  //loadImgsAndExtractPoints(pano, nPoints, pyrLevel, randomPoints, progress, points);
968  //smartOptimizePhotometric
969 
970  // switch to HDR output mode
973  opts.outputPixelType = "FLOAT";
975  pano.setOptions(opts);
976 
977  // remap all images
978  AppBase::ProgressDisplay* progress;
979  if(g_verbose > 0)
980  {
981  progress = new AppBase::StreamProgressDisplay(std::cout);
982  }
983  else
984  {
985  progress = new AppBase::DummyProgressDisplay();
986  };
988  progress, param.hdrFile, imgs);
989  std::cout << "Written HDR output to " << param.hdrFile << std::endl;
990  delete progress;
991  }
992  if (param.alignedPrefix.size())
993  {
994  // disable all exposure compensation stuff.
998  opts.outputPixelType = "";
999  opts.remapUsingGPU = param.gpu;
1000  pano.setOptions(opts);
1001  // remap all images
1002  AppBase::ProgressDisplay* progress;
1003  if(g_verbose > 0)
1004  {
1005  progress = new AppBase::StreamProgressDisplay(std::cout);
1006  }
1007  else
1008  {
1009  progress = new AppBase::DummyProgressDisplay();
1010  };
1011  // pass option to ignore exposure to stitcher
1013  HuginBase::Nona::SetAdvancedOption(advOpts, "ignoreExposure", true);
1015  progress, param.alignedPrefix, imgs, advOpts);
1016  delete progress;
1017  std::cout << "Written aligned images to files with prefix \"" << param.alignedPrefix << "\"" << std::endl;
1018  }
1019 
1020  // At this point we have panorama options set according to the output
1021  if (!param.ptoFile.empty())
1022  {
1023  if (pano.WritePTOFile(param.ptoFile))
1024  {
1025  std::cout << "Written output to " << param.ptoFile << std::endl;
1026  };
1027  }
1028 
1029 
1030  }
1031  catch (std::exception& e)
1032  {
1033  std::cerr << "ERROR: caught exception: " << e.what() << std::endl;
1034  return 1;
1035  }
1036  return 0;
1037 }
1038 
1039 int main(int argc, char* argv[])
1040 {
1041  // parse arguments
1042  const char* optstring = "a:ef:g:hlmdiSAPCp:vo:s:t:c:xyz";
1043  int c;
1044 
1045  g_verbose = 0;
1046 
1047  Parameters param;
1048  enum
1049  {
1050  CORRTHRESH=1000,
1051  THREADS,
1052  GPU,
1053  LENSDB,
1054  USEGIVENORDER,
1055  ALIGNTOFIRST,
1056  DONTREMAPREF,
1057  };
1058 
1059  static struct option longOptions[] =
1060  {
1061  {"corr", required_argument, NULL, CORRTHRESH },
1062  {"verbose", no_argument, NULL, 'v'},
1063  {"threads", required_argument, NULL, THREADS },
1064  {"gpu", no_argument, NULL, GPU },
1065  {"distortion", no_argument, NULL, LENSDB },
1066  {"use-given-order", no_argument, NULL, USEGIVENORDER },
1067  {"align-to-first", no_argument, NULL, ALIGNTOFIRST},
1068  {"dont-remap-ref", no_argument, NULL, DONTREMAPREF},
1069  {"help", no_argument, NULL, 'h' },
1070  0
1071  };
1072  while ((c = getopt_long(argc, argv, optstring, longOptions, nullptr)) != -1)
1073  {
1074  switch (c)
1075  {
1076  case 'a':
1077  param.alignedPrefix = optarg;
1078  break;
1079  case 'c':
1080  param.nPoints = atoi(optarg);
1081  if (param.nPoints < 1)
1082  {
1083  std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid parameter: Number of points/grid (-c) must be at least 1" << std::endl;
1084  return 1;
1085  }
1086  break;
1087  case 'e':
1088  param.fisheye = true;
1089  break;
1090  case 'f':
1091  param.hfov = atof(optarg);
1092  if (param.hfov <= 0)
1093  {
1094  std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid parameter: HFOV (-f) must be greater than 0" << std::endl;
1095  return 1;
1096  }
1097  break;
1098  case 'g':
1099  param.grid = atoi(optarg);
1100  if (param.grid < 1 || param.grid>50)
1101  {
1102  std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid parameter: number of grid cells (-g) should be between 1 and 50" << std::endl;
1103  return 1;
1104  }
1105  break;
1106  case 'l':
1107  param.linear = true;
1108  break;
1109  case 'm':
1110  param.optHFOV = true;
1111  break;
1112  case 'd':
1113  param.optDistortion = true;
1114  break;
1115  case 'i':
1116  param.optCenter = true;
1117  break;
1118  case 'x':
1119  param.optX = true;
1120  break;
1121  case 'y':
1122  param.optY = true;
1123  break;
1124  case 'z':
1125  param.optZ = true;
1126  break;
1127  case 'S':
1128  param.stereo = true;
1129  break;
1130  case 'A':
1131  param.stereo = true;
1132  param.stereo_window = true;
1133  break;
1134  case 'P':
1135  param.stereo = true;
1136  param.stereo_window = true;
1137  param.pop_out = true;
1138  break;
1139  case 'C':
1140  param.crop = true;
1141  break;
1142  case 't':
1143  param.cpErrorThreshold = atof(optarg);
1144  if (param.cpErrorThreshold <= 0)
1145  {
1146  std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid parameter: control point error threshold (-t) must be greater than 0" << std::endl;
1147  return 1;
1148  }
1149  break;
1150  case 'p':
1151  param.ptoFile = optarg;
1152  break;
1153  case 'o':
1154  param.hdrFile = optarg;
1155  break;
1156  case 'v':
1157  g_verbose++;
1158  break;
1159  case 'h':
1160  usage(hugin_utils::stripPath(argv[0]).c_str());
1161  return 0;
1162  case 's':
1163  param.pyrLevel = atoi(optarg);
1164  if (param.pyrLevel < 0 || param.pyrLevel >8)
1165  {
1166  std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid parameter: scaling (-s) should be between 0 and 8" << std::endl;
1167  return 1;
1168  }
1169  break;
1170  case CORRTHRESH:
1171  param.corrThresh = atof(optarg);
1172  if (param.corrThresh <= 0 || param.corrThresh > 1.0)
1173  {
1174  std::cerr << hugin_utils::stripPath(argv[0]) << ": Invalid parameter: correlation should be between 0 and 1" << endl;
1175  return 1;
1176  };
1177  break;
1178  case THREADS:
1179  std::cout << "WARNING: Switch --threads is deprecated. Set environment variable OMP_NUM_THREADS instead" << std::endl;
1180  break;
1181  case GPU:
1182  param.gpu = true;
1183  break;
1184  case LENSDB:
1185  param.loadDistortion = true;
1186  break;
1187  case USEGIVENORDER:
1188  param.sortImagesByEv = false;
1189  break;
1190  case ALIGNTOFIRST:
1191  param.alignToFirst = true;
1192  param.sortImagesByEv = false;
1193  break;
1194  case DONTREMAPREF:
1195  param.dontRemapRef = true;
1196  break;
1197  case ':':
1198  case '?':
1199  // missing argument or invalid switch
1200  return 1;
1201  break;
1202  default:
1203  // this should not happen
1204  abort();
1205  }
1206  }
1207 
1208  // use always given image order for stereo options
1209  if (param.stereo)
1210  {
1211  param.sortImagesByEv = false;
1212  };
1213  unsigned nFiles = argc - optind;
1214  if (nFiles < 2)
1215  {
1216  std::cerr << hugin_utils::stripPath(argv[0]) << ": At least two files need to be specified" << std::endl;
1217  return 1;
1218  }
1219 
1220  if (param.hdrFile.empty() && param.ptoFile.empty() && param.alignedPrefix.empty())
1221  {
1222  std::cerr << hugin_utils::stripPath(argv[0]) << ": Please specify at least one of the -p, -o or -a options." << std::endl;
1223  return 1;
1224  }
1225 
1226  // extract file names
1227  std::vector<std::string> files;
1228  for (size_t i=0; i < nFiles; i++)
1229  {
1230  const std::string filename(argv[optind + i]);
1231  // reject raw files
1233  {
1234  std::cerr << "Ignoring raw file " << filename << std::endl;
1235  continue;
1236  };
1237  // check that it is a valid image file
1238  if (!vigra::isImage(filename.c_str()))
1239  {
1240  std::cerr << "Could not read file " << filename << std::endl;
1241  continue;
1242  };
1243  files.push_back(filename);
1244  };
1245  if (files.empty())
1246  {
1247  std::cerr << "ERROR: No valid files given. Nothing to do." << std::endl;
1248  return 1;
1249  };
1250 
1251  std::string pixelType;
1252 
1253  bool grayscale = false;
1254  int returnValue = 1;
1255  try
1256  {
1257  vigra::ImageImportInfo firstImgInfo(files[0].c_str());
1258  pixelType = firstImgInfo.getPixelType();
1259  if (firstImgInfo.numExtraBands()>1)
1260  {
1261  std::cerr << "ERROR: images with several alpha channels are not supported." << std::endl;
1262  return 1;
1263  };
1264  grayscale = firstImgInfo.isGrayscale();
1265  }
1266  catch (std::exception& e)
1267  {
1268  std::cerr << "ERROR: caught exception: " << e.what() << std::endl;
1269  return 1;
1270  }
1271 
1272  if(param.gpu)
1273  {
1274  param.gpu=hugin_utils::initGPU(&argc, argv);
1275  };
1276  if (grayscale)
1277  {
1278  if (pixelType == "UINT8")
1279  {
1280  returnValue=main2<vigra::UInt8>(files, param);
1281  }
1282  else if (pixelType == "INT16")
1283  {
1284  returnValue=main2<vigra::Int16>(files, param);
1285  }
1286  else if (pixelType == "UINT16")
1287  {
1288  returnValue = main2<vigra::UInt16>(files, param);
1289  }
1290  else if (pixelType == "FLOAT")
1291  {
1292  returnValue=main2<float>(files, param);
1293  }
1294  else
1295  {
1296  std::cerr << " ERROR: unsupported pixel type: " << pixelType << std::endl;
1297  }
1298  }
1299  else
1300  {
1301  if (pixelType == "UINT8")
1302  {
1303  returnValue = main2<vigra::RGBValue<vigra::UInt8> >(files, param);
1304  }
1305  else if (pixelType == "INT16")
1306  {
1307  returnValue = main2<vigra::RGBValue<vigra::Int16> >(files, param);
1308  }
1309  else if (pixelType == "UINT16")
1310  {
1311  returnValue = main2<vigra::RGBValue<vigra::UInt16> >(files, param);
1312  }
1313  else if (pixelType == "FLOAT")
1314  {
1315  returnValue = main2<vigra::RGBValue<float> >(files, param);
1316  }
1317  else
1318  {
1319  std::cerr << " ERROR: unsupported pixel type: " << pixelType << std::endl;
1320  }
1321  };
1322 
1323  if(param.gpu)
1324  {
1326  };
1328  return returnValue;
1329 }
bool wrapupGPU()
cleanup GPU settings
Definition: utils.cpp:914
Dummy progress display, without output.
bool applyEXIFValues(bool applyEVValue=true)
apply values found in EXIF data to SrcPanoImage class, call readEXIF() before to initialize some valu...
void setHeight(unsigned int h)
set panorama height
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
Definition: Panorama.cpp:1620
int g_verbose
CorrelationResult PointFineTune(const IMAGET &templImg, ACCESSORT access_t, vigra::Diff2D templPos, int templSize, const IMAGES &searchImg, ACCESSORS access_s, vigra::Diff2D searchPos, int sWidth)
fine tune a point with normalized cross correlation
Definition: Correlation.h:504
vigra_ext::CorrelationResult FineTunePoint(const ImageType &leftImg, const vigra::Diff2D templPos, const int templSize, const ImageType &rightImg, const vigra::Diff2D searchPos, const int searchWidth, vigra::VigraTrueType)
Somewhere to specify what variables belong to what.
UIntSet getImagesinROI(const PanoramaData &pano, const UIntSet activeImages)
returns set of images which are visible in output ROI
bool operator()(const unsigned int i, const unsigned int j)
SortImageVectorEV(const HuginBase::Panorama *pano)
std::size_t getNrOfCtrlPoints() const
number of control points
Definition: Panorama.h:306
const HuginBase::Panorama * m_pano
wraps around PTOptimizer
virtual void run()
runs the algorithm.
const CPVector & getCtrlPoints() const
get all control point of this Panorama
Definition: Panorama.h:319
std::string hdrFile
represents a control point
Definition: ControlPoint.h:38
void setOptimizeVector(const OptimizeVector &optvec)
set optimize setting
Definition: Panorama.cpp:297
void findInterestPointsPartial(vigra::triple< ImageIter, ImageIter, ImageAcc > img, const vigra::Rect2D &rect, double scale, unsigned nPoints, std::multimap< double, vigra::Diff2D > &points)
static void Clean()
cleanup the static LensDB instance, must be called at the end of the program
Definition: LensDB.cpp:2010
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
helper for OpenMP
void alignStereoWindow(HuginBase::Panorama &pano, bool pop_out)
class to access Hugins camera and lens database
Model for a panorama.
Definition: Panorama.h:152
static int ptinfoDlg(int command, char *argument)
unsigned int addCtrlPoint(const ControlPoint &point)
add a new control point.
Definition: Panorama.cpp:381
const OptimizeVector & getOptimizeVector() const
return the optimize settings stored inside panorama
Definition: Panorama.h:454
std::size_t getNrOfImages() const
number of images.
Definition: Panorama.h:205
std::string getExtension(const std::string &basename2)
Get extension of a filename.
Definition: utils.cpp:99
std::vector< unsigned int > getCtrlPointsForImage(unsigned int imgNr) const
return all control points for a given image.
Definition: Panorama.cpp:83
void setCtrlPoints(const CPVector &points)
set all control points (Ippei: Is this supposed to be &#39;add&#39; method?)
Definition: Panorama.cpp:449
vigra::FRGBImage ImageType
virtual vigra::Rect2D getResultOptimalROI()
return the ROI structure?, for now area
Maximum of correlation, position and value.
Definition: Correlation.h:56
hugin_utils::FDiff2D curv
Definition: Correlation.h:68
ImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
void activateImage(unsigned int imgNr, bool active=true)
mark an image as active or inactive.
Definition: Panorama.cpp:1575
evaluate x, points are on a vertical line
Definition: ControlPoint.h:47
std::multimap< double, vigra::Diff2D > MapPoints
static hugin_omp::Lock lock
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:324
void stitchPanorama(const PanoramaData &pano, const PanoramaOptions &opt, AppBase::ProgressDisplay *progress, const std::string &basename, const UIntSet &usedImgs, const AdvancedOptions &advOptions)
The main stitching function.
Definition: Stitcher.cpp:40
static int ptProgress(int command, char *argument)
void setROI(const vigra::Rect2D &val)
vigra::triple< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImageRange(const ROIImage< Image, Mask > &img)
helper function for ROIImages
Definition: ROIImage.h:287
!! from PTOptimise.h 1951
bool initGPU(int *argcp, char **argv)
Try to initalise GLUT and GLEW, and create an OpenGL context for GPU stitching.
Definition: utils.cpp:858
unsigned int addImage(const SrcPanoImage &img)
the the number for a specific image
Definition: Panorama.cpp:319
compute interest points
UIntSet getActiveImages() const
get active images
Definition: Panorama.cpp:1585
void importImageAlpha(const ImageImportInfo &import_info, ImageIterator image_iterator, ImageAccessor image_accessor, AlphaIterator alpha_iterator, AlphaAccessor alpha_accessor)
Read the image specified by the given vigra::ImageImportInfo object including its alpha channel...
Definition: impexalpha.hxx:479
void createCtrlPoints(HuginBase::Panorama &pano, int img1, const ImageType &leftImg, const ImageType &leftImgOrig, int img2, const ImageType &rightImg, const ImageType &rightImgOrig, int pyrLevel, double scale, unsigned nPoints, unsigned grid, double corrThresh=0.9, bool stereo=false)
void setHFOV(double h, bool keepView=true)
set the horizontal field of view.
Contains various routines used for stitching panoramas.
std::string alignedPrefix
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition: Panorama.h:481
bool readDistortionFromDB()
tries to read distortion data from lens database you need to call SrcPanoImage::readEXIF before to fi...
static void usage()
Definition: Main.cpp:32
Holds transformations for Image -&gt; Pano and the other way.
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
bool readEXIF()
try to fill out information about the image, by examining the exif data
unsigned int optimize(PanoramaData &pano, const char *userScript)
optimize the images imgs, for variables optvec, using vars as start.
void setSize(vigra::Size2D val)
Set the image size in pixels.
std::string GetHuginVersion()
return a string with version numbers
Definition: utils.cpp:920
int main2(std::vector< std::string > files, Parameters param)
hugin_utils::FDiff2D maxpos
Definition: Correlation.h:64
void update()
Update part numbers for each variable group.
std::map< std::string, std::string > AdvancedOptions
std::vector< ControlPoint > CPVector
Definition: ControlPoint.h:99
vigra::triple< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImageRange(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:312
std::string basename
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
Definition: Panorama.cpp:2059
std::vector< std::set< std::string > > OptimizeVector
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
void FineTuneInterestPoints(HuginBase::Panorama &pano, int img1, const ImageType &leftImg, const ImageType &leftImgOrig, int img2, const ImageType &rightImg, const ImageType &rightImgOrig, const MapPoints &points, unsigned nPoints, int pyrLevel, int templWidth, int sWidth, double scaleFactor, double corrThresh, bool stereo)
void setOptions(const PanoramaOptions &opt)
set new output settings This is not used directly for optimizing/stiching, but it can be feed into ru...
Definition: Panorama.cpp:1531
bool IsRawExtension(const std::string testExt)
return true if extension belongs to a raw file
Definition: utils.cpp:959
All variables of a source image.
Definition: SrcPanoImage.h:194
void setProjection(ProjectionFormat f)
set the Projection format and adjust the hfov/vfov if nessecary
Panorama image options.
void switchParts(unsigned int ImageNr, unsigned int partNr)
switch a given image to a different part number.
void reduceNTimes(ImageIn &in, Image &out, int n)
Definition: Pyramid.h:39
evaluate y, points are on a horizontal line
Definition: ControlPoint.h:48
a progress display to print progress reports to a stream
void FindInterestPointsPartial(const ImageType &image, const vigra::Rect2D &rect, double scale, unsigned nPoints, std::multimap< double, vigra::Diff2D > &points, vigra::VigraTrueType)
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
Definition: utils.cpp:160
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
void SetAdvancedOption(AdvancedOptions &opts, const std::string &name, const bool value)
store the option with name in AdvancedOptions
std::string ptoFile
void autoCrop(HuginBase::Panorama &pano)
int main(int argc, char *argv[])
Definition: Main.cpp:167