Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PanoDetectorLogic.cpp
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 ; tab-width: 4 -*-
2 /*
3 * Copyright (C) 2007-2008 Anael Orlinski
4 *
5 * This file is part of Panomatic.
6 *
7 * Panomatic is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * Panomatic is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Panomatic; if not, write to the Free Software
19 * <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "ImageImport.h"
23 
24 #include "PanoDetector.h"
25 #include <iostream>
26 #include <fstream>
27 #include <vigra/distancetransform.hxx>
28 #include "vigra_ext/impexalpha.hxx"
29 #include "vigra_ext/cms.h"
30 
31 #include <localfeatures/Sieve.h>
36 
37 /*
38 #include "KDTree.h"
39 #include "KDTreeImpl.h"
40 */
41 #include "Utils.h"
42 #include "hugin_utils/stl_utils.h"
43 #include "Tracer.h"
44 
47 #include <nona/RemappedPanoImage.h>
48 #include <nona/ImageRemapper.h>
49 
50 #include <time.h>
51 
52 #define TRACE_IMG(X) {if (iPanoDetector.getVerbose() > 1) { TRACE_INFO("i" << ioImgInfo._number << " : " << X << std::endl);} }
53 #define TRACE_PAIR(X) {if (iPanoDetector.getVerbose() > 1){ TRACE_INFO("i" << ioMatchData._i1->_number << " <> " \
54  "i" << ioMatchData._i2->_number << " : " << X << std::endl)}}
55 
56 // define a Keypoint insertor
58 {
59 public:
60  explicit KeyPointVectInsertor(lfeat::KeyPointVect_t& iVect) : _v(iVect) {};
61  inline virtual void operator()(const lfeat::KeyPoint& k)
62  {
63  _v.push_back(lfeat::KeyPointPtr(new lfeat::KeyPoint(k)));
64  }
65 
66 private:
68 
69 };
70 
71 
72 // define a sieve extractor
73 class SieveExtractorKP : public lfeat::SieveExtractor<lfeat::KeyPointPtr>
74 {
75 public:
76  explicit SieveExtractorKP(lfeat::KeyPointVect_t& iV) : _v(iV) {};
77  inline virtual void operator()(const lfeat::KeyPointPtr& k)
78  {
79  _v.push_back(k);
80  }
81 private:
83 };
84 
85 class SieveExtractorMatch : public lfeat::SieveExtractor<lfeat::PointMatchPtr>
86 {
87 public:
89  inline virtual void operator()(const lfeat::PointMatchPtr& m)
90  {
91  _m.push_back(m);
92  }
93 private:
95 };
96 
97 bool PanoDetector::LoadKeypoints(ImgData& ioImgInfo, const PanoDetector& iPanoDetector)
98 {
99  TRACE_IMG("Loading keypoints...");
100 
102  ioImgInfo._loadFail = (info.filename.empty());
103 
104  // update ImgData
105  if(ioImgInfo.NeedsRemapping())
106  {
107  ioImgInfo._detectWidth = std::max(info.width,info.height);
108  ioImgInfo._detectHeight = std::max(info.width,info.height);
109  ioImgInfo._projOpts.setWidth(ioImgInfo._detectWidth);
110  ioImgInfo._projOpts.setHeight(ioImgInfo._detectHeight);
111  }
112  else
113  {
114  ioImgInfo._detectWidth = info.width;
115  ioImgInfo._detectHeight = info.height;
116  };
117  ioImgInfo._descLength = info.dimensions;
118 
119  return true;
120 }
121 
123 template <class SrcImageIterator, class SrcAccessor>
124 void applyMaskAndCrop(vigra::triple<SrcImageIterator, SrcImageIterator, SrcAccessor> img, const HuginBase::SrcPanoImage& SrcImg)
125 {
126  vigra::Diff2D imgSize = img.second - img.first;
127 
128  // create dest y iterator
129  SrcImageIterator yd(img.first);
130  // loop over the image and transform
131  for(int y=0; y < imgSize.y; ++y, ++yd.y)
132  {
133  // create x iterators
134  SrcImageIterator xd(yd);
135  for(int x=0; x < imgSize.x; ++x, ++xd.x)
136  {
137  if(!SrcImg.isInside(vigra::Point2D(x,y)))
138  {
139  *xd=0;
140  };
141  }
142  }
143 }
144 
146 template <class T>
148 {
149  typedef T result_type;
150  explicit ScaleFunctor(double scale) { m_scale = scale; };
151 
152  T operator()(const T & a) const
153  {
154  return m_scale*a;
155  }
156 
157  template <class T2>
158  T2 operator()(const T2 & a, const hugin_utils::FDiff2D & p) const
159  {
160  return m_scale*a;
161  }
162 
163  template <class T2, class A>
164  A hdrWeight(T2 v, A a) const
165  {
166  return a;
167  }
168 
169 private:
170  double m_scale;
171 };
172 
177 template <class ImageType, class PixelTransform>
179  size_t detectWidth, size_t detectHeight,
180  ImageType*& image, vigra::BImage*& mask,
181  const PixelTransform& pixelTransform,
182  ImageType*& finalImage, vigra::BImage*& finalMask)
183 {
186  transform.createTransform(srcImage, options);
187  finalImage = new ImageType(detectWidth, detectHeight);
188  finalMask = new vigra::BImage(detectWidth, detectHeight, vigra::UInt8(0));
189  if (srcImage.hasActiveMasks() || (srcImage.getCropMode() != HuginBase::SrcPanoImage::NO_CROP && !srcImage.getCropRect().isEmpty()))
190  {
191  if (!mask)
192  {
193  // image has no mask, create full mask
194  mask = new vigra::BImage(image->size(), vigra::UInt8(255));
195  };
196  applyMaskAndCrop(vigra::destImageRange(*mask), srcImage);
197  };
198  if (mask)
199  {
201  options.getROI().upperLeft(), transform, pixelTransform, false, vigra_ext::INTERP_CUBIC, &dummy);
202  delete mask;
203  mask = NULL;
204  }
205  else
206  {
208  options.getROI().upperLeft(), transform, pixelTransform, false, vigra_ext::INTERP_CUBIC, &dummy);
209  };
210  delete image;
211  image = NULL;
212 }
213 
216 template <class ImageType>
217 void HandleDownscaleImage(const HuginBase::SrcPanoImage& srcImage, ImageType*& image, vigra::BImage*& mask,
218  size_t detectWidth, size_t detectHeight, bool downscale,
219  ImageType*& finalImage, vigra::BImage*& finalMask)
220 {
221  if (srcImage.hasActiveMasks() || (srcImage.getCropMode() != HuginBase::SrcPanoImage::NO_CROP && !srcImage.getCropRect().isEmpty()))
222  {
223  if (!mask)
224  {
225  // image has no mask, create full mask
226  mask = new vigra::BImage(image->size(), vigra::UInt8(255));
227  };
228  //copy mask and crop from pto file into alpha layer
229  applyMaskAndCrop(vigra::destImageRange(*mask), srcImage);
230  };
231  if (downscale)
232  {
233  // Downscale image
234  finalImage = new ImageType(detectWidth, detectHeight);
235  vigra::resizeImageNoInterpolation(vigra::srcImageRange(*image), vigra::destImageRange(*finalImage));
236  delete image;
237  image = NULL;
238  //downscale mask
239  if (mask)
240  {
241  finalMask = new vigra::BImage(detectWidth, detectHeight);
242  vigra::resizeImageNoInterpolation(vigra::srcImageRange(*mask), vigra::destImageRange(*finalMask));
243  delete mask;
244  mask = NULL;
245  };
246  }
247  else
248  {
249  // simply copy pointer instead of copying the whole image data
250  finalImage = image;
251  if (mask)
252  {
253  finalMask = mask;
254  };
255  };
256 };
257 
258 // save some intermediate images to disc if defined
259 // #define DEBUG_LOADING_REMAPPING
260 bool PanoDetector::AnalyzeImage(ImgData& ioImgInfo, const PanoDetector& iPanoDetector)
261 {
262  vigra::DImage* final_img = NULL;
263  vigra::BImage* final_mask = NULL;
264 
265  try
266  {
267  ioImgInfo._loadFail=false;
268 
269  TRACE_IMG("Load image...");
270  vigra::ImageImportInfo aImageInfo(ioImgInfo._name.c_str());
271  if (aImageInfo.numExtraBands() > 1)
272  {
273  TRACE_INFO("Image with multiple alpha channels are not supported");
274  ioImgInfo._loadFail = true;
275  return false;
276  };
277  // remark: it would be possible to handle all cases with the same code
278  // but this would mean that in some cases there are unnecessary
279  // range conversions and image data copying actions needed
280  // so we use specialed code for several cases to reduce memory usage
281  // and prevent unnecessary range adaptions
282  if (aImageInfo.isGrayscale())
283  {
284  // gray scale image
285  vigra::DImage* image = new vigra::DImage(aImageInfo.size());
286  vigra::BImage* mask = NULL;
287  // load gray scale image
288  if (aImageInfo.numExtraBands() == 1)
289  {
290  mask=new vigra::BImage(aImageInfo.size());
291  vigra::importImageAlpha(aImageInfo, vigra::destImage(*image), vigra::destImage(*mask));
292  }
293  else
294  {
295  vigra::importImage(aImageInfo, vigra::destImage(*image));
296  };
297  // adopt range
298  double minVal = 0;
299  double maxVal;
300  if (aImageInfo.getPixelType() == std::string("FLOAT") || aImageInfo.getPixelType() == std::string("DOUBLE"))
301  {
302  vigra::FindMinMax<float> minmax; // init functor
303  vigra::inspectImage(vigra::srcImageRange(*image), minmax);
304  minVal = minmax.min;
305  maxVal = minmax.max;
306  }
307  else
308  {
309  maxVal = vigra_ext::getMaxValForPixelType(aImageInfo.getPixelType());
310  };
311  bool range255 = (fabs(maxVal - 255) < 0.01 && fabs(minVal) < 0.01);
312  if (aImageInfo.getICCProfile().empty())
313  {
314  // no icc profile, cpfind expects images in 0 ..255 range
315  TRACE_IMG("Rescale range...");
316  if (!range255)
317  {
319  vigra::linearRangeMapping(minVal, maxVal, 0.0, 255.0));
320  };
321  range255 = true;
322  }
323  else
324  {
325  // apply ICC profile
326  TRACE_IMG("Applying icc profile...");
327  // lcms expects for double datatype all values between 0 and 1
329  vigra::linearRangeMapping(minVal, maxVal, 0.0, 1.0));
330  range255 = false;
331  HuginBase::Color::ApplyICCProfile(*image, aImageInfo.getICCProfile(), TYPE_GRAY_DBL);
332  };
333  if (ioImgInfo.NeedsRemapping())
334  {
335  // remap image
336  TRACE_IMG("Remapping image...");
337  if (range255)
338  {
339  RemapImage(iPanoDetector._panoramaInfoCopy.getImage(ioImgInfo._number), ioImgInfo._projOpts,
340  ioImgInfo._detectWidth, ioImgInfo._detectHeight, image, mask, vigra_ext::PassThroughFunctor<double>(),
341  final_img, final_mask);
342  }
343  else
344  {
345  // images has been scaled to 0..1 range before, scale back to 0..255 range
346  RemapImage(iPanoDetector._panoramaInfoCopy.getImage(ioImgInfo._number), ioImgInfo._projOpts,
347  ioImgInfo._detectWidth, ioImgInfo._detectHeight, image, mask, ScaleFunctor<double>(255.0),
348  final_img, final_mask);
349  };
350  }
351  else
352  {
353  if (range255)
354  {
355  TRACE_IMG("Downscale and transform to suitable grayscale...");
356  HandleDownscaleImage(iPanoDetector._panoramaInfoCopy.getImage(ioImgInfo._number), image, mask,
357  ioImgInfo._detectWidth, ioImgInfo._detectHeight, ioImgInfo.IsDownscale(),
358  final_img, final_mask);
359  }
360  else
361  {
362  TRACE_IMG("Transform to suitable grayscale...");
363  HandleDownscaleImage(iPanoDetector._panoramaInfoCopy.getImage(ioImgInfo._number), image, mask,
364  ioImgInfo._detectWidth, ioImgInfo._detectHeight, ioImgInfo.IsDownscale(),
365  final_img, final_mask);
366  vigra::transformImage(vigra::srcImageRange(*final_img), vigra::destImage(*final_img), vigra::linearRangeMapping(0, 1, 0, 255));
367  };
368  };
369  if (iPanoDetector.getCeleste())
370  {
371  TRACE_IMG("Celeste does not work with grayscale images. Skipping...");
372  };
373  }
374  else
375  {
376  if (aImageInfo.isColor())
377  {
378  // rgb images
379  // prepare radius parameter for celeste
380  int radius = 1;
381  if (iPanoDetector.getCeleste())
382  {
383  radius = iPanoDetector.getCelesteRadius();
384  if (iPanoDetector._downscale)
385  {
386  radius >>= 1;
387  };
388  if (radius < 2)
389  {
390  radius = 2;
391  };
392  };
393  switch (aImageInfo.pixelType())
394  {
395  case vigra::ImageImportInfo::UINT8:
396  // special variant for unsigned 8 bit images
397  {
398  vigra::BRGBImage* rgbImage=new vigra::BRGBImage(aImageInfo.size());
399  vigra::BImage* mask = NULL;
400  // load image
401  if (aImageInfo.numExtraBands() == 1)
402  {
403  mask=new vigra::BImage(aImageInfo.size());
404  vigra::importImageAlpha(aImageInfo, vigra::destImage(*rgbImage), vigra::destImage(*mask));
405  }
406  else
407  {
408  vigra::importImage(aImageInfo, vigra::destImage(*rgbImage));
409  };
410  // apply icc profile
411  if (!aImageInfo.getICCProfile().empty())
412  {
413  TRACE_IMG("Applying icc profile...");
414  HuginBase::Color::ApplyICCProfile(*rgbImage, aImageInfo.getICCProfile(), TYPE_RGB_8);
415  };
416  vigra::BRGBImage* scaled = NULL;
417  if (ioImgInfo.NeedsRemapping())
418  {
419  // remap image
420  TRACE_IMG("Remapping image...");
421  RemapImage(iPanoDetector._panoramaInfoCopy.getImage(ioImgInfo._number), ioImgInfo._projOpts,
422  ioImgInfo._detectWidth, ioImgInfo._detectHeight, rgbImage, mask,
424  scaled, final_mask);
425  }
426  else
427  {
428  if (ioImgInfo.IsDownscale())
429  {
430  TRACE_IMG("Downscale image...");
431  };
432  HandleDownscaleImage(iPanoDetector._panoramaInfoCopy.getImage(ioImgInfo._number), rgbImage, mask,
433  ioImgInfo._detectWidth, ioImgInfo._detectHeight, ioImgInfo.IsDownscale(),
434  scaled, final_mask);
435  };
436  if (iPanoDetector.getCeleste())
437  {
438  TRACE_IMG("Mask areas with clouds...");
439  vigra::UInt16RGBImage* image16=new vigra::UInt16RGBImage(scaled->size());
441  vigra::linearIntensityTransform<vigra::RGBValue<vigra::UInt16> >(255));
442  vigra::BImage* celeste_mask = celeste::getCelesteMask(iPanoDetector.svmModel, *image16, radius, iPanoDetector.getCelesteThreshold(), 800, true, false);
443 #ifdef DEBUG_LOADING_REMAPPING
444  // DEBUG: export celeste mask
445  std::ostringstream maskfilename;
446  maskfilename << ioImgInfo._name << "_celeste_mask.JPG";
447  vigra::ImageExportInfo maskexinfo(maskfilename.str().c_str());
448  vigra::exportImage(vigra::srcImageRange(*celeste_mask), maskexinfo);
449 #endif
450  delete image16;
451  if (final_mask)
452  {
453  vigra::copyImageIf(vigra::srcImageRange(*celeste_mask), vigra::srcImage(*final_mask), vigra::destImage(*final_mask));
454  }
455  else
456  {
457  final_mask = celeste_mask;
458  };
459  };
460  // scale to greyscale
461  TRACE_IMG("Convert to greyscale double...");
462  final_img = new vigra::DImage(scaled->size());
463  vigra::copyImage(vigra::srcImageRange(*scaled, vigra::RGBToGrayAccessor<vigra::RGBValue<vigra::UInt8> >()),
464  vigra::destImage(*final_img));
465  delete scaled;
466  };
467  break;
468  case vigra::ImageImportInfo::UINT16:
469  // special variant for unsigned 16 bit images
470  {
471  vigra::UInt16RGBImage* rgbImage = new vigra::UInt16RGBImage(aImageInfo.size());
472  vigra::BImage* mask = NULL;
473  // load image
474  if (aImageInfo.numExtraBands() == 1)
475  {
476  mask = new vigra::BImage(aImageInfo.size());
477  vigra::importImageAlpha(aImageInfo, vigra::destImage(*rgbImage), vigra::destImage(*mask));
478  }
479  else
480  {
481  vigra::importImage(aImageInfo, vigra::destImage(*rgbImage));
482  };
483  // apply icc profile
484  if (!aImageInfo.getICCProfile().empty())
485  {
486  TRACE_IMG("Applying icc profile...");
487  HuginBase::Color::ApplyICCProfile(*rgbImage, aImageInfo.getICCProfile(), TYPE_RGB_16);
488  };
489  vigra::UInt16RGBImage* scaled = NULL;
490  if (ioImgInfo.NeedsRemapping())
491  {
492  // remap image
493  TRACE_IMG("Remapping image...");
494  RemapImage(iPanoDetector._panoramaInfoCopy.getImage(ioImgInfo._number), ioImgInfo._projOpts,
495  ioImgInfo._detectWidth, ioImgInfo._detectHeight, rgbImage, mask,
497  scaled, final_mask);
498  }
499  else
500  {
501  if (ioImgInfo.IsDownscale())
502  {
503  TRACE_IMG("Downscale image...");
504  };
505  HandleDownscaleImage(iPanoDetector._panoramaInfoCopy.getImage(ioImgInfo._number), rgbImage, mask,
506  ioImgInfo._detectWidth, ioImgInfo._detectHeight, ioImgInfo.IsDownscale(),
507  scaled, final_mask);
508  };
509  if (iPanoDetector.getCeleste())
510  {
511  TRACE_IMG("Mask areas with clouds...");
512  vigra::BImage* celeste_mask = celeste::getCelesteMask(iPanoDetector.svmModel, *scaled, radius, iPanoDetector.getCelesteThreshold(), 800, true, false);
513 #ifdef DEBUG_LOADING_REMAPPING
514  // DEBUG: export celeste mask
515  std::ostringstream maskfilename;
516  maskfilename << ioImgInfo._name << "_celeste_mask.JPG";
517  vigra::ImageExportInfo maskexinfo(maskfilename.str().c_str());
518  vigra::exportImage(vigra::srcImageRange(*celeste_mask), maskexinfo);
519 #endif
520  if (final_mask)
521  {
522  vigra::copyImageIf(vigra::srcImageRange(*celeste_mask), vigra::srcImage(*final_mask), vigra::destImage(*final_mask));
523  }
524  else
525  {
526  final_mask = celeste_mask;
527  };
528  };
529  // scale to greyscale
530  TRACE_IMG("Convert to greyscale double...");
531  final_img = new vigra::DImage(scaled->size());
532  // keypoint finder expext 0..255 range
533  vigra::transformImage(vigra::srcImageRange(*scaled, vigra::RGBToGrayAccessor<vigra::RGBValue<vigra::UInt16> >()),
534  vigra::destImage(*final_img), vigra::functor::Arg1() / vigra::functor::Param(255.0));
535  delete scaled;
536  };
537  break;
538  default:
539  // double variant for all other cases
540  {
541  vigra::DRGBImage* rgbImage = new vigra::DRGBImage(aImageInfo.size());
542  vigra::BImage* mask = NULL;
543  // load image
544  if (aImageInfo.numExtraBands() == 1)
545  {
546  mask = new vigra::BImage(aImageInfo.size());
547  vigra::importImageAlpha(aImageInfo, vigra::destImage(*rgbImage), vigra::destImage(*mask));
548  }
549  else
550  {
551  vigra::importImage(aImageInfo, vigra::destImage(*rgbImage));
552  };
553  // range adaption
554  double minVal = 0;
555  double maxVal;
556  const bool isDouble = aImageInfo.getPixelType() == std::string("FLOAT") || aImageInfo.getPixelType() == std::string("DOUBLE");
557  if (isDouble)
558  {
559  vigra::FindMinMax<float> minmax; // init functor
560  vigra::inspectImage(vigra::srcImageRange(*rgbImage, vigra::RGBToGrayAccessor<vigra::RGBValue<double> >()), minmax);
561  minVal = minmax.min;
562  maxVal = minmax.max;
563  }
564  else
565  {
566  maxVal = vigra_ext::getMaxValForPixelType(aImageInfo.getPixelType());
567  };
568  bool range255 = (fabs(maxVal - 255) < 0.01 && fabs(minVal) < 0.01);
569  if (aImageInfo.getICCProfile().empty())
570  {
571  // no icc profile, cpfind expects images in 0 ..255 range
572  TRACE_IMG("Rescale range...");
573  if (!range255)
574  {
575  int mapping = 0;
576  if (isDouble && iPanoDetector._panoramaInfoCopy.getImage(ioImgInfo._number).getResponseType() == HuginBase::BaseSrcPanoImage::RESPONSE_LINEAR)
577  {
578  // switch to log mapping for double/float images with linear response type
579  mapping = 1;
580  };
581  vigra_ext::applyMapping(vigra::srcImageRange(*rgbImage), vigra::destImage(*rgbImage), minVal, maxVal, mapping);
582  };
583  range255 = true;
584  }
585  else
586  {
587  // apply ICC profile
588  TRACE_IMG("Applying icc profile...");
589  // lcms expects for double datatype all values between 0 and 1
591  vigra_ext::LinearTransform<vigra::RGBValue<double> >(1.0 / maxVal - minVal, -minVal));
592  range255 = false;
593  HuginBase::Color::ApplyICCProfile(*rgbImage, aImageInfo.getICCProfile(), TYPE_RGB_DBL);
594  };
595  vigra::DRGBImage* scaled;
596  if (ioImgInfo.NeedsRemapping())
597  {
598  // remap image
599  TRACE_IMG("Remapping image...");
600  RemapImage(iPanoDetector._panoramaInfoCopy.getImage(ioImgInfo._number), ioImgInfo._projOpts,
601  ioImgInfo._detectWidth, ioImgInfo._detectHeight, rgbImage, mask, vigra_ext::PassThroughFunctor<double>(),
602  scaled, final_mask);
603  }
604  else
605  {
606  TRACE_IMG("Transform to suitable grayscale...");
607  HandleDownscaleImage(iPanoDetector._panoramaInfoCopy.getImage(ioImgInfo._number), rgbImage, mask,
608  ioImgInfo._detectWidth, ioImgInfo._detectHeight, ioImgInfo.IsDownscale(),
609  scaled, final_mask);
610  };
611  if (iPanoDetector.getCeleste())
612  {
613  TRACE_IMG("Mask areas with clouds...");
614  vigra::UInt16RGBImage* image16 = new vigra::UInt16RGBImage(scaled->size());
615  if (range255)
616  {
618  vigra::linearIntensityTransform<vigra::RGBValue<vigra::UInt16> >(255));
619  }
620  else
621  {
623  vigra::linearIntensityTransform<vigra::RGBValue<vigra::UInt16> >(65535));
624  };
625  vigra::BImage* celeste_mask = celeste::getCelesteMask(iPanoDetector.svmModel, *image16, radius, iPanoDetector.getCelesteThreshold(), 800, true, false);
626 #ifdef DEBUG_LOADING_REMAPPING
627  // DEBUG: export celeste mask
628  std::ostringstream maskfilename;
629  maskfilename << ioImgInfo._name << "_celeste_mask.JPG";
630  vigra::ImageExportInfo maskexinfo(maskfilename.str().c_str());
631  vigra::exportImage(vigra::srcImageRange(*celeste_mask), maskexinfo);
632 #endif
633  delete image16;
634  if (final_mask)
635  {
636  vigra::copyImageIf(vigra::srcImageRange(*celeste_mask), vigra::srcImage(*final_mask), vigra::destImage(*final_mask));
637  }
638  else
639  {
640  final_mask = celeste_mask;
641  };
642  };
643  // scale to greyscale
644  TRACE_IMG("Convert to greyscale double...");
645  final_img = new vigra::DImage(scaled->size());
646  // keypoint finder expext 0..255 range
647  if (range255)
648  {
649  vigra::copyImage(vigra::srcImageRange(*scaled, vigra::RGBToGrayAccessor<vigra::RGBValue<double> >()), vigra::destImage(*final_img));
650  }
651  else
652  {
653  vigra::transformImage(vigra::srcImageRange(*scaled, vigra::RGBToGrayAccessor<vigra::RGBValue<double> >()),
654  vigra::destImage(*final_img), vigra::functor::Arg1() * vigra::functor::Param(255.0));
655  };
656  delete scaled;
657  };
658  break;
659  };
660  }
661  else
662  {
663  TRACE_INFO("Cpfind works only with grayscale or RGB images");
664  ioImgInfo._loadFail = true;
665  return false;
666  };
667  };
668 
669 #ifdef DEBUG_LOADING_REMAPPING
670  // DEBUG: export remapped
671  std::ostringstream filename;
672  filename << ioImgInfo._name << "_grey.JPG";
673  vigra::ImageExportInfo exinfo(filename.str().c_str());
674  vigra::exportImage(vigra::srcImageRange(*final_img), exinfo);
675 #endif
676 
677  // Build integral image
678  TRACE_IMG("Build integral image...");
679  ioImgInfo._ii.init(*final_img);
680  delete final_img;
681 
682  // compute distance map
683  if(final_mask)
684  {
685  TRACE_IMG("Build distance map...");
686  //apply threshold, in case loaded mask contains other values than 0 and 255
688  vigra::Threshold<vigra::BImage::PixelType, vigra::BImage::PixelType>(1, 255, 0, 255));
689  ioImgInfo._distancemap.resize(final_mask->width(), final_mask->height(), 0);
690  vigra::distanceTransform(vigra::srcImageRange(*final_mask), vigra::destImage(ioImgInfo._distancemap), 255, 2);
691 #ifdef DEBUG_LOADING_REMAPPING
692  std::ostringstream maskfilename;
693  maskfilename << ioImgInfo._name << "_mask.JPG";
694  vigra::ImageExportInfo maskexinfo(maskfilename.str().c_str());
695  vigra::exportImage(vigra::srcImageRange(*final_mask), maskexinfo);
696  std::ostringstream distfilename;
697  distfilename << ioImgInfo._name << "_distancemap.JPG";
698  vigra::ImageExportInfo distexinfo(distfilename.str().c_str());
699  vigra::exportImage(vigra::srcImageRange(ioImgInfo._distancemap), distexinfo);
700 #endif
701  delete final_mask;
702  };
703  }
704  catch (std::exception& e)
705  {
706  TRACE_INFO("An error happened while loading image : caught exception: " << e.what() << std::endl);
707  ioImgInfo._loadFail=true;
708  return false;
709  }
710 
711  return true;
712 }
713 
714 
715 bool PanoDetector::FindKeyPointsInImage(ImgData& ioImgInfo, const PanoDetector& iPanoDetector)
716 {
717  TRACE_IMG("Find keypoints...");
718 
719  // setup the detector
720  KeyPointDetector aKP;
721 
722  // detect the keypoints
723  KeyPointVectInsertor aInsertor(ioImgInfo._kp);
724  aKP.detectKeypoints(ioImgInfo._ii, aInsertor);
725 
726  TRACE_IMG("Found "<< ioImgInfo._kp.size() << " interest points.");
727 
728  return true;
729 }
730 
731 bool PanoDetector::FilterKeyPointsInImage(ImgData& ioImgInfo, const PanoDetector& iPanoDetector)
732 {
733  TRACE_IMG("Filtering keypoints...");
734 
736  iPanoDetector.getSieve1Height(),
737  iPanoDetector.getSieve1Size());
738 
739  // insert the points in the Sieve if they are not masked
740  double aXF = (double)iPanoDetector.getSieve1Width() / (double)ioImgInfo._detectWidth;
741  double aYF = (double)iPanoDetector.getSieve1Height() / (double)ioImgInfo._detectHeight;
742 
743  const bool distmap_valid=(ioImgInfo._distancemap.width()>0 && ioImgInfo._distancemap.height()>0);
744  for (size_t i = 0; i < ioImgInfo._kp.size(); ++i)
745  {
746  lfeat::KeyPointPtr& aK = ioImgInfo._kp[i];
747  if(distmap_valid)
748  {
749  if(aK->_x > 0 && aK->_x < ioImgInfo._distancemap.width() && aK->_y > 0 && aK->_y < ioImgInfo._distancemap.height()
750  && ioImgInfo._distancemap((int)(aK->_x),(int)(aK->_y)) >aK->_scale*8)
751  {
752  //cout << " dist from border:" << ioImgInfo._distancemap((int)(aK->_x),(int)(aK->_y)) << " required dist: " << aK->_scale*12 << std::endl;
753  aSieve.insert(aK, (int)(aK->_x * aXF), (int)(aK->_y * aYF));
754  }
755  }
756  else
757  {
758  aSieve.insert(aK, (int)(aK->_x * aXF), (int)(aK->_y * aYF));
759  };
760  }
761 
762  // pull remaining values from the sieve
763  ioImgInfo._kp.clear();
764 
765  // make an extractor and pull the points
766  SieveExtractorKP aSieveExt(ioImgInfo._kp);
767  aSieve.extract(aSieveExt);
768 
769  TRACE_IMG("Kept " << ioImgInfo._kp.size() << " interest points.");
770 
771  return true;
772 
773 }
774 
776 {
777  TRACE_IMG("Make keypoint descriptors...");
778 
779  // build a keypoint descriptor
780  lfeat::CircularKeyPointDescriptor aKPD(ioImgInfo._ii);
781 
782  // vector for keypoints with more than one orientation
783  lfeat::KeyPointVect_t kp_new_ori;
784  for (size_t j = 0; j < ioImgInfo._kp.size(); ++j)
785  {
786  lfeat::KeyPointPtr& aK = ioImgInfo._kp[j];
787  double angles[4];
788  int nAngles = aKPD.assignOrientation(*aK, angles);
789  for (int i=0; i < nAngles; i++)
790  {
791  // duplicate Keypoint with additional angles
793  aKn->_ori = angles[i];
794  kp_new_ori.push_back(aKn);
795  }
796  }
797  ioImgInfo._kp.insert(ioImgInfo._kp.end(), kp_new_ori.begin(), kp_new_ori.end());
798 
799  for (size_t i = 0; i < ioImgInfo._kp.size(); ++i)
800  {
801  aKPD.makeDescriptor(*(ioImgInfo._kp[i]));
802  }
803  // store the descriptor length
804  ioImgInfo._descLength = aKPD.getDescriptorLength();
805  return true;
806 }
807 
808 bool PanoDetector::RemapBackKeypoints(ImgData& ioImgInfo, const PanoDetector& iPanoDetector)
809 {
810  if (ioImgInfo.IsDownscale())
811  {
812  for (size_t i = 0; i < ioImgInfo._kp.size(); ++i)
813  {
814  lfeat::KeyPointPtr& aK = ioImgInfo._kp[i];
815  aK->_x *= 2.0;
816  aK->_y *= 2.0;
817  aK->_scale *= 2.0;
818  };
819  }
820  else
821  {
822  if (ioImgInfo.NeedsRemapping())
823  {
824  TRACE_IMG("Remapping back keypoints...");
826  trafo1.createTransform(iPanoDetector._panoramaInfoCopy.getSrcImage(ioImgInfo._number),
827  ioImgInfo._projOpts);
828 
829  int dx1 = ioImgInfo._projOpts.getROI().left();
830  int dy1 = ioImgInfo._projOpts.getROI().top();
831 
832  for (size_t i = 0; i < ioImgInfo._kp.size(); ++i)
833  {
834  lfeat::KeyPointPtr& aK = ioImgInfo._kp[i];
835  double xout, yout;
836  if (trafo1.transformImgCoord(xout, yout, aK->_x + dx1, aK->_y + dy1))
837  {
838  // downscaling is take care of by the remapping transform
839  // no need for multiplying the scale factor...
840  aK->_x = xout;
841  aK->_y = yout;
842  };
843  };
844  };
845  };
846  return true;
847 }
848 
849 bool PanoDetector::BuildKDTreesInImage(ImgData& ioImgInfo, const PanoDetector& iPanoDetector)
850 {
851  TRACE_IMG("Build KDTree...");
852 
853  if(ioImgInfo._kp.empty())
854  {
855  return false;
856  };
857  // build a vector of KDElemKeyPointPtr
858 
859  // create feature vector matrix for flann
860  ioImgInfo._flann_descriptors = flann::Matrix<double>(new double[ioImgInfo._kp.size()*ioImgInfo._descLength],
861  ioImgInfo._kp.size(), ioImgInfo._descLength);
862  for (size_t i = 0; i < ioImgInfo._kp.size(); ++i)
863  {
864  memcpy(ioImgInfo._flann_descriptors[i], ioImgInfo._kp[i]->_vec, sizeof(double)*ioImgInfo._descLength);
865  }
866 
867  // build query structure
868  ioImgInfo._flann_index = new flann::Index<flann::L2<double> > (ioImgInfo._flann_descriptors, flann::KDTreeIndexParams(4));
869  ioImgInfo._flann_index->buildIndex();
870 
871  return true;
872 }
873 
874 bool PanoDetector::FreeMemoryInImage(ImgData& ioImgInfo, const PanoDetector& iPanoDetector)
875 {
876  TRACE_IMG("Freeing memory...");
877 
878  ioImgInfo._ii.clean();
879  ioImgInfo._distancemap.resize(0,0);
880 
881  return true;
882 }
883 
884 
885 bool PanoDetector::FindMatchesInPair(MatchData& ioMatchData, const PanoDetector& iPanoDetector)
886 {
887  TRACE_PAIR("Find Matches...");
888 
889  // retrieve the KDTree of image 2
890  flann::Index<flann::L2<double> > * index2 = ioMatchData._i2->_flann_index;
891 
892  // retrieve query points from image 1
893  flann::Matrix<double> & query = ioMatchData._i1->_flann_descriptors;
894 
895  // storage for sorted 2 best matches
896  int nn = 2;
897  flann::Matrix<int> indices(new int[query.rows*nn], query.rows, nn);
898  flann::Matrix<double> dists(new double[query.rows*nn], query.rows, nn);
899 
900  // perform matching using flann
901  index2->knnSearch(query, indices, dists, nn, flann::SearchParams(iPanoDetector.getKDTreeSearchSteps()));
902 
903  //typedef KDTreeSpace::BestMatch<KDElemKeyPoint> BM_t;
904  //std::set<BM_t, std::greater<BM_t> > aBestMatches;
905 
906  // store the matches already found to avoid 2 points in image1
907  // match the same point in image2
908  // both matches will be removed.
909  std::set<int> aAlreadyMatched;
910  std::set<int> aBadMatch;
911 
912  // unfiltered vector of matches
913  typedef std::pair<lfeat::KeyPointPtr, int> TmpPair_t;
914  std::vector<TmpPair_t> aUnfilteredMatches;
915 
916  //PointMatchVector_t aMatches;
917 
918  // go through all the keypoints of image 1
919  for (unsigned aKIt = 0; aKIt < query.rows; ++aKIt)
920  {
921  // accept the match if the second match is far enough
922  // put a lower value for stronger matching default 0.15
923  if (dists[aKIt][0] > iPanoDetector.getKDTreeSecondDistance() * dists[aKIt][1])
924  {
925  continue;
926  }
927 
928  // check if the kdtree match number is already in the already matched set
929  if (aAlreadyMatched.find(indices[aKIt][0]) != aAlreadyMatched.end())
930  {
931  // add to delete list and continue
932  aBadMatch.insert(indices[aKIt][0]);
933  continue;
934  }
935 
936  // TODO: add check for duplicate matches (can happen if a keypoint gets multiple orientations)
937 
938  // add the match number in already matched set
939  aAlreadyMatched.insert(indices[aKIt][0]);
940 
941  // add the match to the unfiltered list
942  aUnfilteredMatches.push_back(TmpPair_t(ioMatchData._i1->_kp[aKIt], indices[aKIt][0]));
943  }
944 
945  // now filter and fill the vector of matches
946  for (size_t i = 0; i < aUnfilteredMatches.size(); ++i)
947  {
948  TmpPair_t& aP = aUnfilteredMatches[i];
949  // if the image2 match number is in the badmatch set, skip it.
950  if (aBadMatch.find(aP.second) != aBadMatch.end())
951  {
952  continue;
953  }
954 
955  // add the match in the output vector
956  ioMatchData._matches.push_back(lfeat::PointMatchPtr( new lfeat::PointMatch(aP.first, ioMatchData._i2->_kp[aP.second])));
957  }
958 
959  delete[] indices.ptr();
960  delete[] dists.ptr();
961  TRACE_PAIR("Found " << ioMatchData._matches.size() << " matches.");
962  return true;
963 }
964 
965 bool PanoDetector::RansacMatchesInPair(MatchData& ioMatchData, const PanoDetector& iPanoDetector)
966 {
967  // Use panotools model for wide angle lenses
968  HuginBase::RANSACOptimizer::Mode rmode = iPanoDetector._ransacMode;
970  (rmode == HuginBase::RANSACOptimizer::AUTO && iPanoDetector._panoramaInfo->getImage(ioMatchData._i1->_number).getHFOV() < 65 &&
971  iPanoDetector._panoramaInfo->getImage(ioMatchData._i2->_number).getHFOV() < 65))
972  {
973  return RansacMatchesInPairHomography(ioMatchData, iPanoDetector);
974  }
975  else
976  {
977  return RansacMatchesInPairCam(ioMatchData, iPanoDetector);
978  }
979 }
980 
981 // new code with fisheye aware ransac
982 bool PanoDetector::RansacMatchesInPairCam(MatchData& ioMatchData, const PanoDetector& iPanoDetector)
983 {
984  TRACE_PAIR("RANSAC Filtering with Panorama model...");
985 
986  if (ioMatchData._matches.size() < (unsigned int)iPanoDetector.getMinimumMatches())
987  {
988  TRACE_PAIR("Too few matches ... removing all of them.");
989  ioMatchData._matches.clear();
990  return true;
991  }
992 
993  if (ioMatchData._matches.size() < 6)
994  {
995  TRACE_PAIR("Not enough matches for RANSAC filtering.");
996  return true;
997  }
998 
999  // setup a panorama project with the two images.
1000  // is this threadsafe (is this read only access?)
1001  HuginBase::UIntSet imgs;
1002  int pano_i1 = ioMatchData._i1->_number;
1003  int pano_i2 = ioMatchData._i2->_number;
1004  imgs.insert(pano_i1);
1005  imgs.insert(pano_i2);
1006  int pano_local_i1 = 0;
1007  int pano_local_i2 = 1;
1008  if (pano_i1 > pano_i2)
1009  {
1010  pano_local_i1 = 1;
1011  pano_local_i2 = 0;
1012  }
1013 
1014  // perform ransac matching.
1015  // ARGH the panotools optimizer uses global variables is not reentrant
1016  std::vector<int> inliers;
1017 #pragma omp critical
1018  {
1019  HuginBase::PanoramaData* panoSubset = iPanoDetector._panoramaInfo->getNewSubset(imgs);
1020 
1021  // create control point vector
1022  HuginBase::CPVector controlPoints(ioMatchData._matches.size());
1023  for (size_t i = 0; i < ioMatchData._matches.size(); ++i)
1024  {
1025  lfeat::PointMatchPtr& aM=ioMatchData._matches[i];
1026  controlPoints[i] = HuginBase::ControlPoint(pano_local_i1, aM->_img1_x, aM->_img1_y,
1027  pano_local_i2, aM->_img2_x, aM->_img2_y);
1028  }
1029  panoSubset->setCtrlPoints(controlPoints);
1030 
1031 
1032  PT_setProgressFcn(ptProgress);
1033  PT_setInfoDlgFcn(ptinfoDlg);
1034 
1035  HuginBase::RANSACOptimizer::Mode rmode = iPanoDetector._ransacMode;
1036  if (rmode == HuginBase::RANSACOptimizer::AUTO)
1037  {
1039  }
1040  // the RANSAC uses the distance in the image for determination of valid parameter
1041  // so make the threshold depending on the image size, use the given pixel distance relative to a 12 MPix image with 4000x3000 pixel
1042  const double threshold = iPanoDetector.getRansacDistanceThreshold() / 5000.0 * hypot(panoSubset->getImage(pano_local_i2).getWidth(), panoSubset->getImage(pano_local_i2).getHeight());
1043  inliers = HuginBase::RANSACOptimizer::findInliers(*panoSubset, pano_local_i1, pano_local_i2,
1044  threshold, rmode);
1045  PT_setProgressFcn(NULL);
1046  PT_setInfoDlgFcn(NULL);
1047  delete panoSubset;
1048  }
1049 
1050  TRACE_PAIR("Removed " << ioMatchData._matches.size() - inliers.size() << " matches. " << inliers.size() << " remaining.");
1051  if (inliers.size() < 0.5 * ioMatchData._matches.size())
1052  {
1053  // more than 50% of matches were removed, ignore complete pair...
1054  TRACE_PAIR("RANSAC found more than 50% outliers, removing all matches");
1055  ioMatchData._matches.clear();
1056  return true;
1057  }
1058 
1059 
1060  if (inliers.size() < (unsigned int)iPanoDetector.getMinimumMatches())
1061  {
1062  TRACE_PAIR("Too few matches ... removing all of them.");
1063  ioMatchData._matches.clear();
1064  return true;
1065  }
1066 
1067  // keep only inlier matches
1068  lfeat::PointMatchVector_t aInlierMatches;
1069  aInlierMatches.reserve(inliers.size());
1070 
1071  for (size_t i = 0; i < inliers.size(); ++i)
1072  {
1073  aInlierMatches.push_back(ioMatchData._matches[inliers[i]]);
1074  }
1075  ioMatchData._matches = aInlierMatches;
1076 
1077  /*
1078  if (iPanoDetector.getTest())
1079  TestCode::drawRansacMatches(ioMatchData._i1->_name, ioMatchData._i2->_name, ioMatchData._matches,
1080  aRemovedMatches, aRansacFilter, iPanoDetector.getDownscale());
1081  */
1082 
1083  return true;
1084 }
1085 
1086 // homography based ransac matching
1088 {
1089  TRACE_PAIR("RANSAC Filtering...");
1090 
1091  if (ioMatchData._matches.size() < (unsigned int)iPanoDetector.getMinimumMatches())
1092  {
1093  TRACE_PAIR("Too few matches ... removing all of them.");
1094  ioMatchData._matches.clear();
1095  return true;
1096  }
1097 
1098  if (ioMatchData._matches.size() < 6)
1099  {
1100  TRACE_PAIR("Not enough matches for RANSAC filtering.");
1101  return true;
1102  }
1103 
1104  lfeat::PointMatchVector_t aRemovedMatches;
1105 
1106  lfeat::Ransac aRansacFilter;
1107  aRansacFilter.setIterations(iPanoDetector.getRansacIterations());
1108  int thresholdDistance=iPanoDetector.getRansacDistanceThreshold();
1109  //increase RANSAC distance if the image were remapped to not exclude
1110  //too much points in this case
1111  if(ioMatchData._i1->NeedsRemapping() || ioMatchData._i2->NeedsRemapping())
1112  {
1113  thresholdDistance*=5;
1114  }
1115  aRansacFilter.setDistanceThreshold(thresholdDistance);
1116  aRansacFilter.filter(ioMatchData._matches, aRemovedMatches);
1117 
1118 
1119  TRACE_PAIR("Removed " << aRemovedMatches.size() << " matches. " << ioMatchData._matches.size() << " remaining.");
1120 
1121  if (aRemovedMatches.size() > ioMatchData._matches.size())
1122  {
1123  // more than 50% of matches were removed, ignore complete pair...
1124  TRACE_PAIR("More than 50% outliers, removing all matches");
1125  ioMatchData._matches.clear();
1126  return true;
1127  }
1128 
1129  if (iPanoDetector.getTest())
1130  TestCode::drawRansacMatches(ioMatchData._i1->_name, ioMatchData._i2->_name, ioMatchData._matches,
1131  aRemovedMatches, aRansacFilter, iPanoDetector.getDownscale());
1132 
1133  return true;
1134 
1135 }
1136 
1137 
1138 bool PanoDetector::FilterMatchesInPair(MatchData& ioMatchData, const PanoDetector& iPanoDetector)
1139 {
1140  TRACE_PAIR("Clustering matches...");
1141 
1142  if (ioMatchData._matches.size() < 2)
1143  {
1144  return true;
1145  }
1146 
1147  // compute min,max of x,y for image1
1148 
1149  double aMinX = std::numeric_limits<double>::max();
1150  double aMinY = std::numeric_limits<double>::max();
1151  double aMaxX = -std::numeric_limits<double>::max();
1152  double aMaxY = -std::numeric_limits<double>::max();
1153 
1154  for (size_t i = 0; i < ioMatchData._matches.size(); ++i)
1155  {
1156  lfeat::PointMatchPtr& aM = ioMatchData._matches[i];
1157  if (aM->_img1_x < aMinX)
1158  {
1159  aMinX = aM->_img1_x;
1160  }
1161  if (aM->_img1_x > aMaxX)
1162  {
1163  aMaxX = aM->_img1_x;
1164  }
1165 
1166  if (aM->_img1_y < aMinY)
1167  {
1168  aMinY = aM->_img1_y;
1169  }
1170  if (aM->_img1_y > aMaxY)
1171  {
1172  aMaxY = aM->_img1_y;
1173  }
1174  }
1175 
1176  double aSizeX = aMaxX - aMinX + 2; // add 2 so max/aSize is strict < 1
1177  double aSizeY = aMaxY - aMinY + 2;
1178 
1179  //
1180 
1182  iPanoDetector.getSieve2Height(),
1183  iPanoDetector.getSieve2Size());
1184 
1185  // insert the points in the Sieve
1186  double aXF = (double)iPanoDetector.getSieve2Width() / aSizeX;
1187  double aYF = (double)iPanoDetector.getSieve2Height() / aSizeY;
1188  for (size_t i = 0; i < ioMatchData._matches.size(); ++i)
1189  {
1190  lfeat::PointMatchPtr& aM = ioMatchData._matches[i];
1191  HuginBase::ControlPoint cp(ioMatchData._i1->_number, aM->_img1_x, aM->_img1_y,
1192  ioMatchData._i2->_number, aM->_img2_x, aM->_img2_y);
1193  if (set_contains(iPanoDetector._cpsHashSet, cp.getCPString()))
1194  {
1195  // match already exits, skipping
1196  continue;
1197  }
1198  aSieve.insert(aM, (int)((aM->_img1_x - aMinX) * aXF), (int)((aM->_img1_y - aMinY) * aYF));
1199  };
1200 
1201  // pull remaining values from the sieve
1202  ioMatchData._matches.clear();
1203 
1204  // make an extractor and pull the points
1205  SieveExtractorMatch aSieveExt(ioMatchData._matches);
1206  aSieve.extract(aSieveExt);
1207 
1208  TRACE_PAIR("Kept " << ioMatchData._matches.size() << " matches.");
1209  return true;
1210 }
1211 
1213 {
1214  // Write output pto file
1216  {
1217  std::cerr << "ERROR couldn't write to output file '" << _outputFile << "'!" << std::endl;
1218  }
1219 }
1220 
1222 {
1223  // Write output keyfile
1224 
1225  std::ofstream aOut(imgInfo._keyfilename.c_str(), std::ios_base::trunc);
1226 
1227  lfeat::SIFTFormatWriter writer(aOut);
1228 
1229  int origImgWidth = _panoramaInfo->getImage(imgInfo._number).getSize().width();
1230  int origImgHeight = _panoramaInfo->getImage(imgInfo._number).getSize().height();
1231 
1232  lfeat::ImageInfo img_info(imgInfo._name, origImgWidth, origImgHeight);
1233 
1234  writer.writeHeader ( img_info, imgInfo._kp.size(), imgInfo._descLength );
1235 
1236  for(size_t i=0; i<imgInfo._kp.size(); ++i)
1237  {
1238  lfeat::KeyPointPtr& aK=imgInfo._kp[i];
1239  writer.writeKeypoint ( aK->_x, aK->_y, aK->_scale, aK->_ori, aK->_score,
1240  imgInfo._descLength, aK->_vec );
1241  }
1242  writer.writeFooter();
1243 }
1244 
int getSieve2Width() const
Definition: PanoDetector.h:207
int getRansacIterations() const
Definition: PanoDetector.h:182
Dummy progress display, without output.
lfeat::PointMatchVector_t & _m
double getMaxValForPixelType(const std::string &v)
Definition: utils.h:89
int getSieve2Size() const
Definition: PanoDetector.h:215
std::vector< PointMatchPtr > PointMatchVector_t
Definition: PointMatch.h:53
void HandleDownscaleImage(const HuginBase::SrcPanoImage &srcImage, ImageType *&image, vigra::BImage *&mask, size_t detectWidth, size_t detectHeight, bool downscale, ImageType *&finalImage, vigra::BImage *&finalMask)
downscale image if requested, optimized code for non-downscale version to prevent unnecessary copying...
vigra::BImage _distancemap
Definition: PanoDetector.h:399
std::vector< KeyPointPtr > KeyPointVect_t
Definition: KeyPoint.h:111
void setHeight(unsigned int h)
set panorama height
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.
SrcPanoImage getSrcImage(unsigned imgNr) const
get a description of a source image
Definition: Panorama.cpp:1620
virtual void setCtrlPoints(const CPVector &points)=0
set all control points (Ippei: Is this supposed to be &#39;add&#39; method?)
vigra::BImage * getCelesteMask(struct svm_model *model, vigra::UInt16RGBImage &input, int radius, float threshold, int resize_dimension, bool adaptThreshold, bool verbose)
calculates the mask using SVM
Definition: Celeste.cpp:313
PanoramaData * getNewSubset(const UIntSet &imgs) const
Definition: Panorama.h:183
int getMinimumMatches() const
Definition: PanoDetector.h:178
void copyImageIf(SrcImageIterator src_upperleft, SrcImageIterator src_lowerright, SrcAccessor src_acc, MaskImageIterator mask_upperleft, MaskAccessor mask_acc, DestImageIterator dest_upperleft, DestAccessor dest_acc)
Definition: openmp_vigra.h:316
static const double A(-0.75)
static bool LoadKeypoints(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
static bool MakeKeyPointDescriptorsInImage(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
void makeDescriptor(KeyPoint &ioKeyPoint) const
HuginBase::PanoramaOptions _projOpts
Definition: PanoDetector.h:401
bool hasActiveMasks() const
returns true, if image has active masks
static std::vector< int > findInliers(PanoramaData &pano, int i1, int i2, double maxError, Mode mode=RPY)
T2 operator()(const T2 &a, const hugin_utils::FDiff2D &p) const
void setDistanceThreshold(int iDT)
Contains functions to transform whole images.
bool getTest() const
Definition: PanoDetector.h:304
static int ptinfoDlg(int command, char *argument)
Definition: icpfind.cpp:103
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition: stl_utils.h:74
static int ptProgress(int command, char *argument)
Definition: icpfind.cpp:99
int getHeight() const
Get the height of the image in pixels.
Definition: SrcPanoImage.h:276
void setIterations(int iIters)
bool isInside(vigra::Point2D p, bool ignoreMasks=false) const
check if a coordinate is inside the source image
vigra::pair< typename ROIImage< Image, Mask >::image_const_traverser, typename ROIImage< Image, Mask >::ImageConstAccessor > srcImage(const ROIImage< Image, Mask > &img)
Definition: ROIImage.h:300
void applyMapping(vigra::triple< SrcIterator, SrcIterator, SrcAccessor > img, vigra::pair< DestIterator, DestAccessor > dest, T min, T max, int mapping)
Definition: utils.h:685
represents a control point
Definition: ControlPoint.h:38
lfeat::KeyPointVect_t & _v
functor to scale image on the fly during other operations
std::set< unsigned int > UIntSet
Definition: PanoramaData.h:51
#define TRACE_PAIR(X)
const std::string getCPString() const
returns string which contains all features of a control point used for detecting duplicate control po...
static bool RansacMatchesInPairCam(MatchData &ioMatchData, const PanoDetector &iPanoDetector)
const vigra::Rect2D & getROI() const
static bool FilterKeyPointsInImage(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
int getSieve1Height() const
Definition: PanoDetector.h:136
bool IsDownscale() const
Definition: PanoDetector.h:439
std::string getPathPrefix(const std::string &filename)
Get the path to a filename.
Definition: utils.cpp:184
int getSieve1Size() const
Definition: PanoDetector.h:140
void filter(std::vector< PointMatchPtr > &ioMatches, std::vector< PointMatchPtr > &ioRemovedMatches)
vigra::FRGBImage ImageType
std::set< std::string > _cpsHashSet
Definition: PanoDetector.h:369
int getWidth() const
Get the width of the image in pixels.
Definition: SrcPanoImage.h:266
static bool FindMatchesInPair(MatchData &ioMatchData, const PanoDetector &iPanoDetector)
lfeat::KeyPointVect_t & _v
static bool RansacMatchesInPair(MatchData &ioMatchData, const PanoDetector &iPanoDetector)
virtual void operator()(const lfeat::PointMatchPtr &m)
#define TRACE_IMG(X)
Model for a panorama.
Definition: PanoramaData.h:81
void RemapImage(const HuginBase::SrcPanoImage &srcImage, const HuginBase::PanoramaOptions &options, size_t detectWidth, size_t detectHeight, ImageType *&image, vigra::BImage *&mask, const PixelTransform &pixelTransform, ImageType *&finalImage, vigra::BImage *&finalMask)
helper function to remap image to given projection, you can supply a pixelTransform, which will be applied during remapping, this is intended for scaling a image during remapping, but this means also, that no photometric corrections are applied, if this is wanted you need to supply a suitable pixelTransform
virtual const SrcPanoImage & getImage(std::size_t nr) const =0
get a panorama image, counting starts with 0
static bool RemapBackKeypoints(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
vigra::pair< typename ROIImage< Image, Alpha >::image_traverser, typename ROIImage< Image, Alpha >::ImageAccessor > destImage(ROIImage< Image, Alpha > &img)
Definition: ROIImage.h:324
void init(vigra::DImage &img)
Definition: Image.cpp:34
static void drawRansacMatches(std::string &i1, std::string &i2, lfeat::PointMatchVector_t &iOK, lfeat::PointMatchVector_t &iNOK, lfeat::Ransac &iRansac, bool iHalf)
Definition: TestCode.cpp:82
bool NeedsRemapping() const
Definition: PanoDetector.h:440
static bool FreeMemoryInImage(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
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
lfeat::PointMatchVector_t _matches
Definition: PanoDetector.h:452
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
ScaleFunctor(double scale)
flann::Matrix< double > _flann_descriptors
Definition: PanoDetector.h:411
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
#define TRACE_INFO(x)
Definition: Tracer.h:26
HuginBase::Panorama _panoramaInfoCopy
Definition: PanoDetector.h:368
T operator()(const T &a) const
struct celeste::svm_model * svmModel
Definition: PanoDetector.h:478
HuginBase::RANSACOptimizer::Mode _ransacMode
Definition: PanoDetector.h:337
bool transformImgCoord(double &x_dest, double &y_dest, double x_src, double y_src) const
like transform, but return image coordinates, not cartesian coordinates
int getKDTreeSearchSteps() const
Definition: PanoDetector.h:153
static bool FilterMatchesInPair(MatchData &ioMatchData, const PanoDetector &iPanoDetector)
lfeat::KeyPointVect_t _kp
Definition: PanoDetector.h:406
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.
static bool AnalyzeImage(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
virtual void operator()(const lfeat::KeyPointPtr &k)
KeyPointVectInsertor(lfeat::KeyPointVect_t &iVect)
std::string _keyfilename
Definition: PanoDetector.h:404
std::string _outputFile
Definition: PanoDetector.h:362
bool getDownscale() const
Definition: PanoDetector.h:237
static T max(T x, T y)
Definition: svm.cpp:65
Holds transformations for Image -&gt; Pano and the other way.
flann::Index< flann::L2< double > > * _flann_index
Definition: PanoDetector.h:412
double getCelesteThreshold() const
Definition: PanoDetector.h:284
int getSieve2Height() const
Definition: PanoDetector.h:211
SieveExtractorKP(lfeat::KeyPointVect_t &iV)
void applyMaskAndCrop(vigra::triple< SrcImageIterator, SrcImageIterator, SrcAccessor > img, const HuginBase::SrcPanoImage &SrcImg)
apply the mask and the crop of the given SrcImg to given mask image
std::shared_ptr< KeyPoint > KeyPointPtr
Definition: KeyPoint.h:110
SieveExtractorMatch(lfeat::PointMatchVector_t &iM)
std::vector< ControlPoint > CPVector
Definition: ControlPoint.h:99
double getKDTreeSecondDistance() const
Definition: PanoDetector.h:157
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
int assignOrientation(KeyPoint &ioKeyPoint, double angles[4]) const
bool WritePTOFile(const std::string &filename, const std::string &prefix="")
write data to given pto file
Definition: Panorama.cpp:2059
static void info(const char *fmt,...)
Definition: svm.cpp:95
bool getCeleste() const
Definition: PanoDetector.h:276
HuginBase::Panorama * _panoramaInfo
Definition: PanoDetector.h:367
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition: Panorama.h:211
virtual void operator()(const lfeat::KeyPoint &k)
int getCelesteRadius() const
Definition: PanoDetector.h:292
A hdrWeight(T2 v, A a) const
void clean()
Definition: Image.cpp:47
void writeKeyfile(ImgData &imgInfo)
int getSieve1Width() const
Definition: PanoDetector.h:132
All variables of a source image.
Definition: SrcPanoImage.h:194
Panorama image options.
std::shared_ptr< PointMatch > PointMatchPtr
Definition: PointMatch.h:52
functions to handle icc profiles in images
ImageInfo loadKeypoints(const std::string &filename, KeyPointVect_t &vec)
Definition: KeyPointIO.cpp:85
void detectKeypoints(Image &iImage, KeyPointInsertor &iInsertor)
static bool FindKeyPointsInImage(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
void createTransform(const vigra::Diff2D &srcSize, VariableMap srcVars, Lens::LensProjectionFormat srcProj, const vigra::Diff2D &destSize, PanoramaOptions::ProjectionFormat destProj, const std::vector< double > &destProjParam, double destHFOV, const vigra::Diff2D &origSrcSize)
initialize pano-&gt;image transformation
std::string filename
Definition: KeyPointIO.h:44
void ApplyICCProfile(ImageType &image, const vigra::ImageImportInfo::ICCProfile &iccProfile, const cmsUInt32Number imageFormat)
converts given image with iccProfile to sRGB/gray space, need to give pixel type in lcms2 format work...
Definition: cms.h:37
void setWidth(unsigned int w, bool keepView=true)
set panorama width keep the HFOV, if keepView=true
static bool BuildKDTreesInImage(ImgData &ioImgInfo, const PanoDetector &iPanoDetector)
static bool RansacMatchesInPairHomography(MatchData &ioMatchData, const PanoDetector &iPanoDetector)
int getRansacDistanceThreshold() const
Definition: PanoDetector.h:186