Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
fulla.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 
31 #include <vigra/error.hxx>
32 #include <vigra/impex.hxx>
33 #include <vigra/codec.hxx>
34 #include <vigra_ext/impexalpha.hxx>
35 #include <getopt.h>
36 
38 #include <nona/SpaceTransform.h>
40 
41 #include <hugin_basic.h>
42 #include <lensdb/LensDB.h>
43 
44 #include <tiffio.h>
46 
47 template <class SrcImgType, class AlphaImgType, class FlatImgType, class DestImgType>
48 void correctImage(SrcImgType& srcImg,
49  const AlphaImgType& srcAlpha,
50  const FlatImgType& srcFlat,
52  vigra_ext::Interpolator interpolator,
53  double maxValue,
54  DestImgType& destImg,
55  AlphaImgType& destAlpha,
56  bool doCrop,
57  AppBase::ProgressDisplay* progress);
58 
59 template <class PIXELTYPE>
60 void correctRGB(HuginBase::SrcPanoImage& src, vigra::ImageImportInfo& info, const char* outfile,
61  bool crop, const std::string& compression, AppBase::ProgressDisplay* progress);
62 
63 static void usage(const char* name)
64 {
65  std::cout << name << ": correct lens distortion, vignetting and chromatic abberation" << std::endl
66  << "fulla version " << hugin_utils::GetHuginVersion() << endl
67  << std::endl
68  << "Usage: " << name << " [options] inputfile(s) " << std::endl
69  << " option are: " << std::endl
70  << " --green=db|a:b:c:d Correct radial distortion for all channels" << std::endl
71  << " Specify 'db' for database lookup or" << std::endl
72  << " the 4 coefficients a:b:c:d" << std::endl
73  << " --blue=db|a:b:c:d Correct radial distortion for blue channel," << std::endl
74  << " this is applied on top of the --green" << std::endl
75  << " distortion coefficients, use for TCA corr" << std::endl
76  << " Specify 'db' for database lookup or" << std::endl
77  << " the 4 coefficients a:b:c:d" << std::endl
78  << " --red=db|a:b:c:d Correct radial distortion for red channel," << std::endl
79  << " this is applied on top of the --green" << std::endl
80  << " distortion coefficients, use for TCA corr" << std::endl
81  << " Specify 'db' for database lookup or" << std::endl
82  << " the 4 coefficients a:b:c:d" << std::endl
83  << " --camera-maker=Maker Camera manufacturer, for database query" << std::endl
84  << " --camera-model=Cam Camera name, for database query" << std::endl
85  << " --lensname=Lens Lens name, for database query" << std::endl
86  << " Specify --camera-maker and --camera-model" << std::endl
87  << " for fixed lens cameras or --lensname" << std::endl
88  << " for interchangeable lenses." << std::endl
89  << " --focallength=50 Specify focal length in mm, for database query" << std::endl
90  << " --aperture=3.5 Specify aperture for vignetting data database query" << std::endl
91  << " --dont-rescale Do not rescale the image to avoid black borders." << std::endl
92  << std::endl
93  << " --flatfield=filename Vignetting correction by flatfield division" << std::endl
94  << " I = I / c, c = flatfield / mean(flatfield)" << std::endl
95  << " --vignetting=db|a:b:c:d Correct vignetting (by division)" << std::endl
96  << " Specify db for database look up or the " << std::endl
97  << " the 4 coefficients a:b:c:d" << std::endl
98  << " I = I / ( a + b*r^2 + c*r^4 + d*r^6)" << std::endl
99  << " --linear Do vignetting correction in linear color space" << std::endl
100  << " --gamma=value Gamma of input data. used for gamma correction" << std::endl
101  << " before and after flatfield correction" << std::endl
102  << " --help Display help (this text)" << std::endl
103  << " --output=name Set output filename. If more than one image is given," << std::endl
104  << " the name will be uses as suffix" << std::endl
105  << " (default suffix: _corr)" << std::endl
106  << " --compression=value Compression of the output files" << std::endl
107  << " For jpeg output: 0-100" << std::endl
108  << " For tiff output: PACKBITS, DEFLATE, LZW" << std::endl
109  << " --offset=X:Y Horizontal and vertical shift" << std::endl
110  << " --verbose Verbose" << std::endl;
111 }
112 
113 
114 int main(int argc, char* argv[])
115 {
116  // parse arguments
117  const char* optstring = "e:g:b:r:m:n:l:d:sf:c:i:t:ho:x:va:";
118  int o;
119  enum
120  {
121  LINEAR_RESPONSE = 1000
122  };
123  static struct option longOptions[] =
124  {
125  { "linear", no_argument, NULL, LINEAR_RESPONSE },
126  { "green", required_argument, NULL, 'g' },
127  { "blue", required_argument, NULL, 'b' },
128  { "red", required_argument, NULL, 'r' },
129  { "lensname", required_argument, NULL, 'l' },
130  { "camera-maker", required_argument, NULL, 'm' },
131  { "camera-model", required_argument, NULL, 'n' },
132  { "aperture", required_argument, NULL, 'a' },
133  { "focallength", required_argument, NULL, 'd' },
134  { "flatfield", required_argument, NULL, 'f' },
135  { "dont-rescale", no_argument, NULL, 's' },
136  { "vignetting", required_argument, NULL, 'c' },
137  { "gamma", required_argument, NULL, 'i' },
138  { "threads", required_argument, NULL, 't' },
139  { "output", required_argument, NULL, 'o' },
140  { "compression", required_argument, NULL, 'e' },
141  { "offset", required_argument, NULL, 'x' },
142  { "verbose", no_argument, NULL, 'v' },
143  { "help", no_argument, NULL, 'h' },
144  0
145  };
146 
147  std::vector<double> vec4(4);
148  bool doFlatfield = false;
149  bool doVigRadial = false;
150  bool doCropBorders = true;
151  unsigned verbose = 0;
152 
153  std::string batchPostfix("_corr");
154  std::string outputFile;
155  std::string compression;
156  bool doLookupDistortion = false;
157  bool doLookupTCA = false;
158  bool doLookupVignetting = false;
159  std::string cameraMaker;
160  std::string cameraName;
161  std::string lensName;
162  float focalLength=0;
163  float aperture = 0;
164  double gamma = 1.0;
165  double shiftX = 0;
166  double shiftY = 0;
167  std::string argument;
168 
170  while ((o = getopt_long(argc, argv, optstring, longOptions, nullptr)) != -1)
171  switch (o)
172  {
173  case 'e':
174  compression = optarg;
175  break;
176  case 'r':
177  argument = optarg;
178  argument = hugin_utils::tolower(argument);
179  if (argument == "db")
180  {
181  doLookupTCA = true;
182  }
183  else
184  {
185  if (sscanf(optarg, "%lf:%lf:%lf:%lf", &vec4[0], &vec4[1], &vec4[2], &vec4[3]) != 4)
186  {
187  std::cerr << hugin_utils::stripPath(argv[0]) << ": invalid -r argument" << std::endl;
188  return 1;
189  }
190  srcImg.setRadialDistortionRed(vec4);
191  };
192  break;
193  case 'g':
194  argument = optarg;
195  argument = hugin_utils::tolower(argument);
196  if (argument == "db")
197  {
198  doLookupDistortion = true;
199  }
200  else
201  {
202  if (sscanf(optarg, "%lf:%lf:%lf:%lf", &vec4[0], &vec4[1], &vec4[2], &vec4[3]) != 4)
203  {
204  std::cerr << hugin_utils::stripPath(argv[0]) << ": invalid -g argument" << std::endl;
205  return 1;
206  }
207  srcImg.setRadialDistortion(vec4);
208  };
209  break;
210  case 'b':
211  argument = optarg;
212  argument = hugin_utils::tolower(argument);
213  if (argument == "db")
214  {
215  doLookupTCA = true;
216  }
217  else
218  {
219  if (sscanf(optarg, "%lf:%lf:%lf:%lf", &vec4[0], &vec4[1], &vec4[2], &vec4[3]) != 4)
220  {
221  std::cerr << hugin_utils::stripPath(argv[0]) << ": invalid -b argument" << std::endl;
222  return 1;
223  }
224  srcImg.setRadialDistortionBlue(vec4);
225  };
226  break;
227  case 's':
228  doCropBorders = false;
229  break;
230  case 'f':
231  srcImg.setFlatfieldFilename(optarg);
232  doFlatfield = true;
233  break;
234  case 'i':
235  gamma = atof(optarg);
236  srcImg.setGamma(gamma);
237  break;
238  case 'm':
239  cameraMaker = optarg;
240  break;
241  case 'n':
242  cameraName = optarg;
243  break;
244  case 'l':
245  lensName = optarg;
246  break;
247  case 'd':
248  focalLength = atof(optarg);
249  break;
250  case 'a':
251  aperture = atof(optarg);
252  break;
253  case 'c':
254  argument = optarg;
255  argument = hugin_utils::tolower(argument);
256  if (argument == "db")
257  {
258  doLookupVignetting = true;
259  }
260  else
261  {
262  if (sscanf(optarg, "%lf:%lf:%lf:%lf", &vec4[0], &vec4[1], &vec4[2], &vec4[3]) != 4)
263  {
264  std::cerr << hugin_utils::stripPath(argv[0]) << ": invalid -c argument" << std::endl;
265  return 1;
266  }
267  srcImg.setRadialVigCorrCoeff(vec4);
268  };
269  doVigRadial = true;
270  break;
271  case 'h':
272  usage(hugin_utils::stripPath(argv[0]).c_str());
273  return 0;
274  case 't':
275  std::cout << "WARNING: Switch --threads is deprecated. Set environment variable OMP_NUM_THREADS instead" << std::endl;
276  break;
277  case 'o':
278  outputFile = optarg;
279  break;
280  case 'x':
281  if (sscanf(optarg, "%lf:%lf", &shiftX, &shiftY) != 2)
282  {
283  std::cerr << hugin_utils::stripPath(argv[0]) << ": invalid -x argument" << std::endl;
284  return 1;
285  }
286  srcImg.setRadialDistortionCenterShift(hugin_utils::FDiff2D(shiftX, shiftY));
287  break;
288  case 'v':
289  verbose++;
290  break;
291  case LINEAR_RESPONSE:
292  srcImg.setResponseType(HuginBase::BaseSrcPanoImage::RESPONSE_LINEAR);
293  break;
294  case ':':
295  case '?':
296  // missing argument or invalid switch
297  return 1;
298  break;
299  default:
300  // this should not happen
301  abort();
302  }
303 
304  if (doVigRadial && doFlatfield)
305  {
306  std::cerr << hugin_utils::stripPath(argv[0]) << ": cannot use -f and -c at the same time" << std::endl;
307  return 1;
308  }
309 
311 
312  if (doVigRadial)
313  {
315  }
316  if (doFlatfield)
317  {
319  }
320 
322  srcImg.setVigCorrMode(vm);
323 
324  unsigned nFiles = argc - optind;
325  if (nFiles == 0)
326  {
327  std::cerr << hugin_utils::stripPath(argv[0]) << ": No input file(s) specified" << std::endl;
328  return 1;
329  }
330 
331  // get input images.
332  std::vector<std::string> inFiles;
333  std::vector<std::string> outFiles;
334  if (nFiles == 1)
335  {
336  if (outputFile.length() !=0)
337  {
338  inFiles.push_back(std::string(argv[optind]));
339  outFiles.push_back(outputFile);
340  }
341  else
342  {
343  std::string name(argv[optind]);
344  inFiles.push_back(name);
345  std::string basen = hugin_utils::stripExtension(name);
346  outFiles.push_back(basen.append(batchPostfix.append(".").append(hugin_utils::getExtension(name))));
347  }
348  }
349  else
350  {
351  // multiple files
352  bool withExtension = false;
353  if (outputFile.length() != 0)
354  {
355  batchPostfix = outputFile;
356  withExtension = (batchPostfix.find('.') != std::string::npos);
357  }
358  for (int i = optind; i < argc; i++)
359  {
360  std::string name(argv[i]);
361  inFiles.push_back(name);
362  if (withExtension)
363  {
364  outFiles.push_back(hugin_utils::stripExtension(name) + batchPostfix);
365  }
366  else
367  {
368  outFiles.push_back(hugin_utils::stripExtension(name) + batchPostfix + "." + hugin_utils::getExtension(name));
369  };
370  }
371  }
372 
373  if (doLookupDistortion || doLookupVignetting || doLookupTCA)
374  {
375  if (lensName.empty())
376  {
377  if (!cameraMaker.empty() && !cameraName.empty())
378  {
379  lensName = cameraMaker;
380  lensName.append("|");
381  lensName.append(cameraName);
382  };
383  };
384  };
385 
386  // suppress tiff warnings
387  TIFFSetWarningHandler(0);
388 
390  if (verbose > 0)
391  {
392  pdisp = new AppBase::StreamProgressDisplay(std::cout);
393  }
394  else
395  {
396  pdisp = new AppBase::DummyProgressDisplay();
397  };
398 
400  try
401  {
402  std::vector<std::string>::iterator outIt = outFiles.begin();
403  for (std::vector<std::string>::iterator inIt = inFiles.begin(); inIt != inFiles.end() ; ++inIt, ++outIt)
404  {
405  if (verbose > 0)
406  {
407  std::cerr << "Correcting " << *inIt << " -> " << *outIt << endl;
408  }
409  HuginBase::SrcPanoImage currentImg(srcImg);
410  currentImg.setFilename(*inIt);
411 
412  // load the input image
413  vigra::ImageImportInfo info(inIt->c_str());
414  const char* pixelType = info.getPixelType();
415  int bands = info.numBands();
416  int extraBands = info.numExtraBands();
417 
418  // do database lookup
419  if (doLookupDistortion || doLookupVignetting || doLookupTCA)
420  {
421  currentImg.readEXIF();
422  if (lensName.empty())
423  {
424  if (currentImg.getDBLensName().empty())
425  {
426  std::cerr << "Not enough data for database lookup" << std::endl
427  << "Specify lensname (--lensname) or camera maker and model " << std::endl
428  << "(--camera-maker and --camera-model) as parameter." << std::endl;
429  continue;
430  };
431  }
432  else
433  {
434  currentImg.setExifLens(lensName);
435  }
436  if (fabs(focalLength) < 0.1)
437  {
438  if (fabs(currentImg.getExifFocalLength()) < 0.1)
439  {
440  std::cerr << "Could not determine focal length." << std::endl
441  << "Specify focal length (--focallength) as parameter." << std::endl;
442  continue;
443  };
444  }
445  else
446  {
447  currentImg.setExifFocalLength(focalLength);
448  };
449  if (verbose > 1)
450  {
451  std::cout << "Lookup in database for " << currentImg.getDBLensName() << " @ " << currentImg.getExifFocalLength() << " mm" << std::endl;
452  };
453  if (doLookupDistortion)
454  {
455  if (!currentImg.readDistortionFromDB())
456  {
457  std::cerr << "No suitable distortion data found in database." << std::endl
458  << "Skipping image." << std::endl;
459  continue;
460  };
461  if (verbose > 1)
462  {
463  std::vector<double> dist = currentImg.getRadialDistortion();
464  std::cout << "Read distortion data: " << dist[0] << ", " << dist[1] << ", " << dist[2] << ", " << dist[3] << std::endl;
465  };
466  };
467  if (doLookupVignetting)
468  {
469  if (fabs(aperture) < 0.1)
470  {
471  if (fabs(currentImg.getExifAperture()) < 0.1)
472  {
473  std::cerr << "Could not determine aperture." << std::endl
474  << "Specify aperture (--aperture) as parameter." << std::endl;
475  continue;
476  };
477  }
478  else
479  {
480  currentImg.setExifAperture(aperture);
481  };
482  if (!currentImg.readVignettingFromDB())
483  {
484  std::cerr << "No suitable vignetting data found in database." << std::endl
485  << "Skipping image." << std::endl;
486  continue;
487  };
488  if (verbose > 1)
489  {
490  std::vector<double> vig = currentImg.getRadialVigCorrCoeff();
491  std::cout << "Read vigneting data: " << vig[1] << ", " << vig[2] << ", " << vig[3] << std::endl;
492  };
493  };
494 
495  if (doLookupTCA)
496  {
497  std::vector<double> tcaRed, tcaBlue;
498  if (lensDB.GetTCA(currentImg.getDBLensName(), currentImg.getExifFocalLength(), tcaRed, tcaBlue))
499  {
500  currentImg.setRadialDistortionRed(tcaRed);
501  currentImg.setRadialDistortionBlue(tcaBlue);
502  }
503  else
504  {
505  std::cerr << "No suitable tca data found in database." << std::endl
506  << "Skipping image." << std::endl;
507  continue;
508  };
509  if (verbose>1)
510  {
511  std::cout << "Read tca data red: " << tcaRed[0] << ", " << tcaRed[1] << ", " << tcaRed[2] << ", " << tcaRed[3] << std::endl;
512  std::cout << "Read tca data blue: " << tcaBlue[0] << ", " << tcaBlue[1] << ", " << tcaBlue[2] << ", " << tcaBlue[3] << std::endl;
513  };
514  };
515  };
516  currentImg.setSize(info.size());
517  // stitch the pano with a suitable image type
518  if (bands == 3 || (bands == 4 && extraBands == 1))
519  {
520  // TODO: add more cases
521  if (strcmp(pixelType, "UINT8") == 0)
522  {
523  correctRGB<vigra::RGBValue<vigra::UInt8> >(currentImg, info, outIt->c_str(), doCropBorders, compression, pdisp);
524  }
525  else if (strcmp(pixelType, "UINT16") == 0)
526  {
527  correctRGB<vigra::RGBValue<vigra::UInt16> >(currentImg, info, outIt->c_str(), doCropBorders, compression, pdisp);
528  }
529  else if (strcmp(pixelType, "INT16") == 0)
530  {
531  correctRGB<vigra::RGBValue<vigra::Int16> >(currentImg, info, outIt->c_str(), doCropBorders, compression, pdisp);
532  }
533  else if (strcmp(pixelType, "UINT32") == 0)
534  {
535  correctRGB<vigra::RGBValue<vigra::UInt32> >(currentImg, info, outIt->c_str(), doCropBorders, compression, pdisp);
536  }
537  else if (strcmp(pixelType, "FLOAT") == 0)
538  {
539  correctRGB<vigra::RGBValue<float> >(currentImg, info, outIt->c_str(), doCropBorders, compression, pdisp);
540  }
541  else if (strcmp(pixelType, "DOUBLE") == 0)
542  {
543  correctRGB<vigra::RGBValue<double> >(currentImg, info, outIt->c_str(), doCropBorders, compression, pdisp);
544  }
545  }
546  else
547  {
548  DEBUG_ERROR("unsupported depth, only 3 channel images are supported");
549  delete pdisp;
551  throw std::runtime_error("unsupported depth, only 3 channels images are supported");
552  return 1;
553  }
554  }
555  }
556  catch (std::exception& e)
557  {
558  std::cerr << "caught exception: " << e.what() << std::endl;
559  delete pdisp;
561  return 1;
562  }
563  delete pdisp;
565  return 0;
566 }
567 
569 {
570 public:
571  bool transformImgCoord(double & x_dest, double & y_dest, double x_src, double y_src) const
572  {
573  x_dest = x_src;
574  y_dest = y_src;
575  return true;
576  };
577 };
578 
579 
585 template <class SrcImgType, class AlphaImgType, class FlatImgType, class DestImgType>
586 void correctImage(SrcImgType& srcImg,
587  const AlphaImgType& srcAlpha,
588  FlatImgType& srcFlat,
590  vigra_ext::Interpolator interpolator,
591  double maxValue,
592  DestImgType& destImg,
593  AlphaImgType& destAlpha,
594  bool doCrop,
595  AppBase::ProgressDisplay* progress)
596 {
597  typedef typename SrcImgType::value_type SrcPixelType;
598  typedef typename DestImgType::value_type DestPixelType;
599 
600  // prepare some information required by multiple types of vignetting correction
601  progress->setMessage("correcting image");
602 
603  vigra::Diff2D shiftXY(- hugin_utils::roundi(src.getRadialDistortionCenterShift().x),
604  - hugin_utils::roundi(src.getRadialDistortionCenterShift().y));
605 
606  if ((src.getVigCorrMode() & HuginBase::SrcPanoImage::VIGCORR_FLATFIELD)
607  || (src.getVigCorrMode() & HuginBase::SrcPanoImage::VIGCORR_RADIAL))
608  {
610  if (src.getResponseType() == HuginBase::BaseSrcPanoImage::RESPONSE_EMOR)
611  {
612  std::vector<double> outLut;
613  vigra_ext::EMoR::createEMoRLUT(src.getEMoRParams(), outLut);
615  invResp.setOutput(1.0 / pow(2.0, src.getExposureValue()), outLut, maxValue);
616  if (maxValue != 1.0)
617  {
618  // transform to range 0..1 for vignetting correction
619  vigra::transformImage(srcImageRange(srcImg), destImage(srcImg), vigra::functor::Arg1()/vigra::functor::Param(maxValue));
620  };
621  };
622 
623  invResp.enforceMonotonicity();
624 
625  NullTransform transform;
626  // dummy alpha channel
627  vigra::BImage alpha(destImg.size());
628 
629  if (src.getVigCorrMode() & HuginBase::SrcPanoImage::VIGCORR_FLATFIELD)
630  {
631  invResp.setFlatfield(&srcFlat);
632  // transform flatfield to linear space if needed
633  if (src.getResponseType() == HuginBase::BaseSrcPanoImage::RESPONSE_EMOR)
634  {
635  HuginBase::SrcPanoImage flatSrc;
636  flatSrc.setVigCorrMode(HuginBase::SrcPanoImage::VIGCORR_NONE);
638  invRespFlat.setHDROutput(true, 1.0);
639  if (maxValue != 1.0)
640  {
641  vigra::transformImage(vigra::srcImageRange(srcFlat), vigra::destImage(srcFlat), vigra::functor::Arg1() / vigra::functor::Param(maxValue));
642  };
643  vigra_ext::transformImage(vigra::srcImageRange(srcFlat), vigra::destImageRange(srcFlat), vigra::destImage(alpha), vigra::Diff2D(0, 0), transform, invRespFlat, false, vigra_ext::INTERP_SPLINE_16, progress);
644  };
645  // smooth flatfield
646  vigra::gaussianSmoothing(vigra::srcImageRange(srcFlat), vigra::destImage(srcFlat), 20);
647  // calculate mean of flatfield and transform flat to vignetting correction values
648  vigra::FindAverage<typename FlatImgType::value_type> meanFlat;
649  vigra::inspectImage(vigra::srcImageRange(srcFlat), meanFlat);
650  vigra::transformImage(vigra::srcImageRange(srcFlat), vigra::destImage(srcFlat), vigra::functor::Arg1() / vigra::functor::Param(meanFlat.average()));
651  }
652  vigra_ext::transformImage(srcImageRange(srcImg), destImageRange(srcImg), destImage(alpha), vigra::Diff2D(0, 0), transform, invResp, false, vigra_ext::INTERP_SPLINE_16, progress);
653 
654  }
655 
656  // radial distortion correction
657  if (doCrop)
658  {
659  double scaleFactor = HuginBase::Nona::estScaleFactorForFullFrame(src);
660  DEBUG_DEBUG("Black border correction scale factor: " << scaleFactor);
661  double sf=scaleFactor;
662  std::vector<double> radGreen = src.getRadialDistortion();
663  for (int i=0; i < 4; i++)
664  {
665  radGreen[3-i] *=sf;
666  sf *=scaleFactor;
667  }
668  src.setRadialDistortion(radGreen);
669  }
670 
672 
673  if (src.getCorrectTCA())
674  {
675  /*
676  DEBUG_DEBUG("Final distortion correction parameters:" << endl
677  << "r: " << radRed[0] << " " << radRed[1] << " " << radRed[2] << " " << radRed[3] << endl
678  << "g: " << radGreen[0] << " " << radGreen[1] << " " << radGreen[2] << " " << radGreen[3] << endl
679  << "b: " << radBlue[0] << " " << radBlue[1] << " " << radBlue[2] << " " << radBlue[3] << endl);
680  */
681  // remap individual channels
683  transfr.InitRadialCorrect(src, 0);
684  AlphaImgType redAlpha(destAlpha.size());
685  if (transfr.isIdentity())
686  {
687  vigra::copyImage(srcIterRange(srcImg.upperLeft(), srcImg.lowerRight(), vigra::RedAccessor<SrcPixelType>()),
688  destIter(destImg.upperLeft(), vigra::RedAccessor<DestPixelType>()));
689  vigra::copyImage(srcImageRange(srcAlpha), destImage(redAlpha));
690  }
691  else
692  {
693  vigra_ext::transformImageAlpha(srcIterRange(srcImg.upperLeft(), srcImg.lowerRight(), vigra::RedAccessor<SrcPixelType>()),
694  srcImage(srcAlpha),
695  destIterRange(destImg.upperLeft(), destImg.lowerRight(), vigra::RedAccessor<DestPixelType>()),
696  destImage(redAlpha),
697  shiftXY,
698  transfr,
699  ptf,
700  false,
702  progress);
703  }
704 
706  transfg.InitRadialCorrect(src, 1);
707  AlphaImgType greenAlpha(destAlpha.size());
708  if (transfg.isIdentity())
709  {
710  vigra::copyImage(srcIterRange(srcImg.upperLeft(), srcImg.lowerRight(), vigra::GreenAccessor<SrcPixelType>()),
711  destIter(destImg.upperLeft(), vigra::GreenAccessor<DestPixelType>()));
712  vigra::copyImage(srcImageRange(srcAlpha), destImage(greenAlpha));
713  }
714  else
715  {
716  transformImageAlpha(srcIterRange(srcImg.upperLeft(), srcImg.lowerRight(), vigra::GreenAccessor<SrcPixelType>()),
717  srcImage(srcAlpha),
718  destIterRange(destImg.upperLeft(), destImg.lowerRight(), vigra::GreenAccessor<DestPixelType>()),
719  destImage(greenAlpha),
720  shiftXY,
721  transfg,
722  ptf,
723  false,
725  progress);
726  }
727 
729  transfb.InitRadialCorrect(src, 2);
730  AlphaImgType blueAlpha(destAlpha.size());
731  if (transfb.isIdentity())
732  {
733  vigra::copyImage(srcIterRange(srcImg.upperLeft(), srcImg.lowerRight(), vigra::BlueAccessor<SrcPixelType>()),
734  destIter(destImg.upperLeft(), vigra::BlueAccessor<DestPixelType>()));
735  vigra::copyImage(srcImageRange(srcAlpha), destImage(blueAlpha));
736 
737  }
738  else
739  {
740  transformImageAlpha(srcIterRange(srcImg.upperLeft(), srcImg.lowerRight(), vigra::BlueAccessor<SrcPixelType>()),
741  srcImage(srcAlpha),
742  destIterRange(destImg.upperLeft(), destImg.lowerRight(), vigra::BlueAccessor<DestPixelType>()),
743  destImage(blueAlpha),
744  shiftXY,
745  transfb,
746  ptf,
747  false,
749  progress);
750  }
751  vigra::combineThreeImages(srcImageRange(redAlpha), srcImage(greenAlpha), srcImage(blueAlpha), destImage(destAlpha),
752  vigra::functor::Arg1() & vigra::functor::Arg2() & vigra::functor::Arg3());
753  }
754  else
755  {
756  // remap with the same coefficient.
758  transf.InitRadialCorrect(src, 1);
759  std::vector <double> radCoeff = src.getRadialDistortion();
760  if (transf.isIdentity() ||
761  (radCoeff[0] == 0.0 && radCoeff[1] == 0.0 && radCoeff[2] == 0.0 && radCoeff[3] == 1.0))
762  {
763  vigra::copyImage(srcImageRange(srcImg), destImage(destImg));
764  vigra::copyImage(srcImageRange(srcAlpha), destImage(destAlpha));
765  }
766  else
767  {
770  srcImage(srcAlpha),
771  destImageRange(destImg),
772  destImage(destAlpha),
773  shiftXY,
774  transf,
775  ptfRGB,
776  false,
778  progress);
779  }
780  }
781 }
782 
783 
784 //void correctRGB(SrcImageInfo & src, ImageImportInfo & info, const char * outfile)
785 template <class PIXELTYPE>
786 void correctRGB(HuginBase::SrcPanoImage& src, vigra::ImageImportInfo& info, const char* outfile,
787  bool crop, const std::string& compression, AppBase::ProgressDisplay* progress)
788 {
789  vigra::BasicImage<vigra::RGBValue<double> > srcImg(info.size());
790  vigra::BasicImage<PIXELTYPE> output(info.size());
791  vigra::BImage alpha(info.size(), 255);
792  vigra::BImage outputAlpha(output.size());
793  if (info.numBands() == 3)
794  {
795  vigra::importImage(info, destImage(srcImg));
796  }
797  else
798  {
799  importImageAlpha(info, destImage(srcImg), destImage(alpha));
800  };
801  vigra::FImage flatfield;
802  if (src.getVigCorrMode() & HuginBase::SrcPanoImage::VIGCORR_FLATFIELD)
803  {
804  vigra::ImageImportInfo finfo(src.getFlatfieldFilename().c_str());
805  flatfield.resize(finfo.size());
806  vigra::importImage(finfo, destImage(flatfield));
807  }
808  correctImage(srcImg, alpha, flatfield, src, vigra_ext::INTERP_SPLINE_16, vigra_ext::getMaxValForPixelType(info.getPixelType()),
809  output, outputAlpha, crop, progress);
810  vigra::ImageExportInfo outInfo(outfile);
811  outInfo.setICCProfile(info.getICCProfile());
812  outInfo.setPixelType(info.getPixelType());
813  if (!compression.empty())
814  {
815  outInfo.setCompression(compression.c_str());
816  }
817  const std::string filetype(vigra::getEncoder(outInfo.getFileName())->getFileType());
818  if (vigra::isBandNumberSupported(filetype, 4))
819  {
820  // image format supports alpha channel
821  std::cout << "Saving " << outInfo.getFileName() << std::endl;
822  vigra::exportImageAlpha(srcImageRange(output), srcImage(outputAlpha), outInfo);
823  }
824  else
825  {
826  // image format does not support an alpha channel, disregard alpha channel
827  std::cout << "Saving " << outInfo.getFileName() << " without alpha channel" << std::endl
828  << "because the fileformat " << filetype << " does not support" << std::endl
829  << "an alpha channel." << std::endl;
830  exportImage(srcImageRange(output), outInfo);
831  };
832 }
Dummy progress display, without output.
double getMaxValForPixelType(const std::string &v)
Definition: utils.h:89
int roundi(T x)
Definition: hugin_math.h:73
void transformImage(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, vigra::triple< DestImageIterator, DestImageIterator, DestAccessor > dest, std::pair< AlphaImageIterator, AlphaAccessor > alpha, vigra::Diff2D destUL, TRANSFORM &transform, PixelTransform &pixelTransform, bool warparound, Interpolator interpol, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
Transform an image into the panorama.
static LensDB & GetSingleton()
returns the static LensDB instance
Definition: LensDB.cpp:2001
radiometric transformation, includes exposure, vignetting and white balance
std::string getDBLensName() const
constructs the lens name for the database it is the lensname if known, for compact cameras it is cons...
void enforceMonotonicity(LUT &lut)
enforce monotonicity of an array (mostly used for lookup tables)
Definition: lut.h:87
void exportImageAlpha(ImageIterator image_upper_left, ImageIterator image_lower_right, ImageAccessor image_accessor, AlphaIterator alpha_upper_left, AlphaAccessor alpha_accessor, const ImageExportInfo &export_info)
Write the image and its alpha channel to a file.
vigra::pair< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImage(const ROIImage< Image, Mask > &img)
Definition: ROIImage.h:300
static void Clean()
cleanup the static LensDB instance, must be called at the end of the program
Definition: LensDB.cpp:2010
main database class
Definition: LensDB.h:44
class to access Hugins camera and lens database
implementation of Space Transformation
empirical model of response
Definition: SrcPanoImage.h:100
VignettingCorrMode
vignetting correction mode (bitflags, no real enum)
Definition: SrcPanoImage.h:91
void combineThreeImages(SrcImageIterator1 src1_upperleft, SrcImageIterator1 src1_lowerright, SrcAccessor1 src1_acc, SrcImageIterator2 src2_upperleft, SrcAccessor2 src2_acc, SrcImageIterator3 src3_upperleft, SrcAccessor3 src3_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc, const Functor &func)
Definition: openmp_vigra.h:288
void setHDROutput(bool hdrMode, double destExposure)
std::string getExtension(const std::string &basename2)
Get extension of a filename.
Definition: utils.cpp:99
bool getCorrectTCA() const
void importImageAlpha(const ImageImportInfo &import_info, ImageIterator image_iterator, ImageAccessor image_accessor, AlphaIterator alpha_iterator, AlphaAccessor alpha_accessor, VigraTrueType)
Definition: impexalpha.hxx:240
float pow(float a, double b)
Definition: utils.h:181
radial vignetting correction
Definition: SrcPanoImage.h:93
void correctImage(SrcImgType &srcImg, const AlphaImgType &srcAlpha, const FlatImgType &srcFlat, HuginBase::SrcPanoImage src, vigra_ext::Interpolator interpolator, double maxValue, DestImgType &destImg, AlphaImgType &destAlpha, bool doCrop, AppBase::ProgressDisplay *progress)
void setMessage(const std::string &message, const std::string &filename="")
sets the message to given string
std::string stripExtension(const std::string &basename2)
remove extension of a filename
Definition: utils.cpp:130
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:324
Contains functions to transform whole images.
#define DEBUG_ERROR(msg)
Definition: utils.h:76
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
void InitRadialCorrect(const vigra::Size2D &sz, const std::vector< double > &radDist, const hugin_utils::FDiff2D &centerShift)
transformation for radial correction only
void createEMoRLUT(const std::vector< float > &params, VECTOR &lut)
Definition: emor.h:44
bool isIdentity()
returns true if this transform is an identity transform
bool readVignettingFromDB()
tries to read vignetting data from lens database you need to call SrcPanoImage::readEXIF before to fi...
void transformImageAlpha(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > src, std::pair< SrcAlphaIterator, SrcAlphaAccessor > srcAlpha, vigra::triple< DestImageIterator, DestImageIterator, DestAccessor > dest, std::pair< AlphaImageIterator, AlphaAccessor > alpha, vigra::Diff2D destUL, TRANSFORM &transform, PixelTransform &pixelTransform, bool warparound, Interpolator interpol, AppBase::ProgressDisplay *progress, bool singleThreaded=false)
Transform image, and respect a possible alpha channel.
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
#define DEBUG_DEBUG(msg)
Definition: utils.h:68
bool readEXIF()
try to fill out information about the image, by examining the exif data
bool transformImgCoord(double &x_dest, double &y_dest, double x_src, double y_src) const
Definition: fulla.cpp:571
void setSize(vigra::Size2D val)
Set the image size in pixels.
std::string GetHuginVersion()
return a string with version numbers
Definition: utils.cpp:920
double estScaleFactorForFullFrame(const SrcPanoImage &src)
Calculate effective scaling factor for a given source image.
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
void copyImage(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc)
Definition: openmp_vigra.h:305
static void info(const char *fmt,...)
Definition: svm.cpp:95
bool GetTCA(const std::string &lens, const double focal, std::vector< double > &tca_red, std::vector< double > &tca_blue) const
returns the tca distortion parameters of the lens
Definition: LensDB.cpp:2366
void correctRGB(HuginBase::SrcPanoImage &src, vigra::ImageImportInfo &info, const char *outfile, bool crop, const std::string &compression, AppBase::ProgressDisplay *progress)
Definition: fulla.cpp:786
Interpolator
enum with all interpolation methods
Definition: Interpolators.h:78
All variables of a source image.
Definition: SrcPanoImage.h:194
void setFlatfield(const vigra::FImage *flat)
a progress display to print progress reports to a stream
std::string tolower(const std::string &s)
convert a string to lowercase
Definition: stl_utils.h:49
void setOutput(double destExposure, const LUTD &destLut, double scale, double rangeCompression=0.0)
output lut
std::string stripPath(const std::string &filename)
remove the path of a filename (mainly useful for gui display of filenames)
Definition: utils.cpp:160
int main(int argc, char *argv[])
Definition: Main.cpp:167