Hugintrunk  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PointSampler.h
Go to the documentation of this file.
1 // -*- c-basic-offset: 4 -*-
24 #ifndef _POINTSAMPLER_H
25 #define _POINTSAMPLER_H
26 
27 #include <ctime>
28 
29 #include <hugin_shared.h>
30 #include <hugin_config.h>
31 #include <vigra/stdimage.hxx>
33 
34 #include <random>
35 #include <functional>
36 #include <vigra_ext/utils.h>
38 #include <panodata/PanoramaData.h>
39 
40 namespace HuginBase
41 {
45  {
46  public:
48  enum LimitType{LIMIT_UINT8, LIMIT_UINT16, LIMIT_FLOAT};
52  LimitIntensity(LimitType limit);
54  const float GetMinI() const {
55  return m_minI;
56  };
58  const float GetMaxI() const {
59  return m_maxI;
60  }
61  private:
63  float m_minI, m_maxI;
64  };
65  typedef std::vector<LimitIntensity> LimitIntensityVector;
66 
68  {
69  protected:
71  PointSampler(PanoramaData& panorama, AppBase::ProgressDisplay* progressDisplay,
72  std::vector<vigra::FRGBImage*> images, LimitIntensityVector limits,
73  int nPoints)
74  : TimeConsumingPanoramaAlgorithm(panorama, progressDisplay),
75  o_images(images), o_numPoints(nPoints), m_limits(limits)
76  {};
77 
78  public:
80  virtual ~PointSampler() {};
81 
82  protected:
84  typedef vigra_ext::ImageInterpolator<vigra::FRGBImage::const_traverser,
85  vigra::FRGBImage::ConstAccessor,
86  vigra_ext::interp_cubic > InterpolImg;
87 
89  void sampleAndExtractPoints(AppBase::ProgressDisplay* progress);
90 
92  virtual void samplePoints(const std::vector<InterpolImg>& imgs,
93  const std::vector<vigra::FImage*>& voteImgs,
94  const PanoramaData& pano,
95  const LimitIntensityVector limitI,
96  std::vector<std::multimap<double,vigra_ext::PointPairRGB> >& radiusHist,
97  unsigned& nGoodPoints,
98  unsigned& nBadPoints,
100 
105  template<class PointPairClass>
106  static void sampleRadiusUniform(const std::vector<std::multimap<double,PointPairClass> >& radiusHist,
107  unsigned nPoints,
108  std::vector<PointPairClass>& selectedPoints,
110 
111  public:
113  virtual bool modifiesPanoramaData() const
114  { return false; }
115 
117  virtual bool runAlgorithm();
118 
120  {
121  run();
122  return *this;
123  }
124 
125  public:
127  typedef std::vector<vigra_ext::PointPairRGB> PointPairs;
128 
131  {
132  //[TODO] debug unsuccessful
133 
134  return o_resultPoints;
135  }
136 
137 
138  protected:
139  std::vector<vigra::FRGBImage*> o_images;
143  };
144 
145 
150  {
151  public:
154  std::vector<vigra::FRGBImage*> images, LimitIntensityVector limits,
155  int nPoints)
156  : PointSampler(panorama, progressDisplay, images, limits, nPoints)
157  {};
158 
160  virtual ~AllPointSampler() {};
161 
162 
163  public:
167  template <class Img, class VoteImg, class PP>
168  static void sampleAllPanoPoints(const std::vector<Img> &imgs,
169  const std::vector<VoteImg *> &voteImgs,
170  const PanoramaData& pano,
171  int nPoints,
172  const LimitIntensityVector limitI,
173  std::vector<std::multimap<double, PP > > & radiusHist,
174  unsigned & nGoodPoints,
175  unsigned & nBadPoints,
176  AppBase::ProgressDisplay* progress);
177 
178  protected:
180  virtual void samplePoints(const std::vector<InterpolImg>& imgs,
181  const std::vector<vigra::FImage*>& voteImgs,
182  const PanoramaData& pano,
183  const LimitIntensityVector limitI,
184  std::vector<std::multimap<double,vigra_ext::PointPairRGB> >& radiusHist,
185  unsigned& nGoodPoints,
186  unsigned& nBadPoints,
187  AppBase::ProgressDisplay* progress)
188  {
189  sampleAllPanoPoints(imgs,
190  voteImgs,
191  pano,
192  o_numPoints,
193  limitI,
194  radiusHist,
195  nGoodPoints,
196  nBadPoints,
197  progress);
198  }
199 
200  };
201 
202 
207  {
208  public:
211  std::vector<vigra::FRGBImage*> images, LimitIntensityVector limits,
212  int nPoints)
213  : PointSampler(panorama, progressDisplay, images, limits, nPoints)
214  {};
215 
217  virtual ~RandomPointSampler() {};
218 
219 
220  public:
221  template <class Img, class VoteImg, class PP>
222  static void sampleRandomPanoPoints(const std::vector<Img>& imgs,
223  const std::vector<VoteImg *> &voteImgs,
224  const PanoramaData& pano,
225  int nPoints,
226  const LimitIntensityVector limitI,
227  std::vector<std::multimap<double, PP > > & radiusHist,
228  unsigned & nBadPoints,
229  AppBase::ProgressDisplay* progress);
230 
231  protected:
233  virtual void samplePoints(const std::vector<InterpolImg>& imgs,
234  const std::vector<vigra::FImage*>& voteImgs,
235  const PanoramaData& pano,
236  const LimitIntensityVector limitI,
237  std::vector<std::multimap<double,vigra_ext::PointPairRGB> >& radiusHist,
238  unsigned& nGoodPoints,
239  unsigned& nBadPoints,
240  AppBase::ProgressDisplay* progress)
241  {
243  voteImgs,
244  pano,
245  5*o_numPoints,
246  limitI,
247  radiusHist,
248  nBadPoints,
249  progress);
250  }
251 
252  };
253 
254 
255 
256 } // namespace
257 
258 
259 
260 
261 
262 //==============================================================================
263 // templated methods
264 
266 
267 namespace HuginBase {
268 
269 template<class PointPairClass>
270 void PointSampler::sampleRadiusUniform(const std::vector<std::multimap<double, PointPairClass> >& radiusHist,
271  unsigned nPoints,
272  std::vector<PointPairClass> &selectedPoints,
273  AppBase::ProgressDisplay* progress)
274 {
275  typedef std::multimap<double,PointPairClass> PointPairMap;
276 
277  // reserve selected points..
278  int drawsPerBin = nPoints / radiusHist.size();
279  // reallocate output vector.
280  selectedPoints.reserve(drawsPerBin*radiusHist.size());
281  for (typename std::vector<PointPairMap>::const_iterator bin = radiusHist.begin();
282  bin != radiusHist.end(); ++bin)
283  {
284  unsigned i=drawsPerBin;
285  // copy into vector
286  for (typename PointPairMap::const_iterator it= (*bin).begin();
287  it != (*bin).end(); ++it)
288  {
289  selectedPoints.push_back(it->second);
290  // do not extract more than drawsPerBin Point pairs.
291  --i;
292  if (i == 0)
293  break;
294  }
295  }
296 }
297 
298 
299 
300 template <class Img, class VoteImg, class PP>
301 void AllPointSampler::sampleAllPanoPoints(const std::vector<Img> &imgs,
302  const std::vector<VoteImg *> &voteImgs,
303  const PanoramaData& pano,
304  int nPoints,
305  const LimitIntensityVector limitI,
306  //std::vector<vigra_ext::PointPair> &points,
307  std::vector<std::multimap<double, PP > > & radiusHist,
308  unsigned & nGoodPoints,
309  unsigned & nBadPoints,
310  AppBase::ProgressDisplay* progress)
311 {
312  typedef typename Img::PixelType PixelType;
313 
314  // use 10 bins
315  radiusHist.resize(10);
316  const unsigned pairsPerBin = nPoints / radiusHist.size();
317 
318  nGoodPoints = 0;
319  nBadPoints = 0;
320  vigra_precondition(imgs.size() > 1, "sampleAllPanoPoints: At least two images required");
321 
322  const unsigned nImg = imgs.size();
323 
324  vigra::Size2D srcSize = pano.getImage(0).getSize();
325  double maxr = sqrt(((double)srcSize.x)*srcSize.x + ((double)srcSize.y)*srcSize.y) / 2.0;
326 
327  // create an array of transforms.
328  //std::vector<SpaceTransform> transf(imgs.size());
329  std::vector<PTools::Transform*> transf(imgs.size());
330 
331  // initialize transforms, and interpolating accessors
332  for(unsigned i=0; i < nImg; i++) {
333  vigra_precondition(pano.getImage(i).getSize() == srcSize, "images need to have the same size");
334  transf[i] = new PTools::Transform;
335  transf[i]->createTransform(pano.getImage(i), pano.getOptions());
336  }
337 
338  const vigra::Rect2D roi = pano.getOptions().getROI();
339  for (int y=roi.top(); y < roi.bottom(); ++y) {
340  for (int x=roi.left(); x < roi.right(); ++x) {
341  hugin_utils::FDiff2D panoPnt(x,y);
342  for (unsigned i=0; i< nImg-1; i++) {
343  // transform pixel
345  if(!transf[i]->transformImgCoord(p1, panoPnt))
346  continue;
347  vigra::Point2D p1Int(p1.toDiff2D());
348  // is inside:
349  if (!pano.getImage(i).isInside(p1Int)) {
350  // point is outside image
351  continue;
352  }
353  PixelType i1;
354  vigra::UInt8 maskI;
355  if (imgs[i](p1.x,p1.y, i1, maskI)){
356  float im1 = vigra_ext::getMaxComponent(i1);
357  if (limitI[i].GetMinI() > im1 || limitI[i].GetMaxI() < im1 || maskI == 0) {
358  // ignore pixels that are too dark or bright
359  continue;
360  }
361  double r1 = hugin_utils::norm((p1 - pano.getImage(i).getRadialVigCorrCenter()) / maxr);
362 
363  // check inner image
364  for (unsigned j=i+1; j < nImg; j++) {
366  if(!transf[j]->transformImgCoord(p2, panoPnt))
367  continue;
368  vigra::Point2D p2Int(p2.toDiff2D());
369  if (!pano.getImage(j).isInside(p2Int)) {
370  // point is outside image
371  continue;
372  }
373  PixelType i2;
374  vigra::UInt8 maskI2;
375  if (imgs[j](p2.x, p2.y, i2, maskI2)){
376  float im2 = vigra_ext::getMaxComponent(i2);
377  if (limitI[j].GetMinI() > im2 || limitI[j].GetMaxI() < im2 || maskI2 == 0) {
378  // ignore pixels that are too dark or bright
379  continue;
380  }
381  double r2 = hugin_utils::norm((p2 - pano.getImage(j).getRadialVigCorrCenter()) / maxr);
382  // add pixel
383  const VoteImg & vimg1 = *voteImgs[i];
384  const VoteImg & vimg2 = *voteImgs[j];
385  double laplace = hugin_utils::sqr(vimg1[p1Int]) + hugin_utils::sqr(vimg2[p2Int]);
386  int bin1 = (int)(r1*10);
387  int bin2 = (int)(r2*10);
388  // a center shift might lead to radi > 1.
389  if (bin1 > 9) bin1 = 9;
390  if (bin2 > 9) bin2 = 9;
391 
392  PP pp;
393  if (im1 <= im2) {
394  // choose i1 to be smaller than i2
395  pp = PP(i, i1, p1, r1, j, i2, p2, r2);
396  } else {
397  pp = PP(j, i2, p2, r2, i, i1, p1, r1);
398  }
399 
400  // decide which bin should be used.
401  std::multimap<double, PP> * map1 = &radiusHist[bin1];
402  std::multimap<double, PP> * map2 = &radiusHist[bin2];
403  std::multimap<double, PP> * destMap;
404  if (map1->empty()) {
405  destMap = map1;
406  } else if (map2->empty()) {
407  destMap = map2;
408  } else if (map1->size() < map2->size()) {
409  destMap = map1;
410  } else if (map1->size() > map2->size()) {
411  destMap = map2;
412  } else if (map1->rbegin()->first > map2->rbegin()->first) {
413  // heuristic: insert into bin with higher maximum laplacian filter response
414  // (higher probablity of misregistration).
415  destMap = map1;
416  } else {
417  destMap = map2;
418  }
419  // insert
420  destMap->insert(std::make_pair(laplace,pp));
421  // remove last element if too many elements have been gathered
422  if (destMap->size() > pairsPerBin) {
423  destMap->erase((--(destMap->end())));
424  }
425  nGoodPoints++;
426  }
427  }
428  }
429  }
430  }
431  }
432 
433  for(unsigned i=0; i < nImg; i++) {
434  delete transf[i];
435  }
436 }
437 
438 
439 
440 template <class Img, class VoteImg, class PP>
441 void RandomPointSampler::sampleRandomPanoPoints(const std::vector<Img>& imgs,
442  const std::vector<VoteImg *> &voteImgs,
443  const PanoramaData& pano,
444  int nPoints,
445  const LimitIntensityVector limitI,
446  //std::vector<PP> &points,
447  std::vector<std::multimap<double, PP > > & radiusHist,
448  unsigned & nBadPoints,
449  AppBase::ProgressDisplay* progress)
450 {
451  typedef typename Img::PixelType PixelType;
452 
453  vigra_precondition(imgs.size() > 1, "sampleRandomPanoPoints: At least two images required");
454 
455  const unsigned nImg = imgs.size();
456 
457  const unsigned nBins = radiusHist.size();
458  const unsigned pairsPerBin = nPoints / nBins;
459 
460  // create an array of transforms.
461  //std::vector<SpaceTransform> transf(imgs.size());
462  std::vector<PTools::Transform *> transf(imgs.size());
463  std::vector<double> maxr(imgs.size());
464 
465  // initialize transforms, and interpolating accessors
466  for(unsigned i=0; i < nImg; i++) {
467  // same size is not needed?
468 // vigra_precondition(src[i].getSize() == srcSize, "images need to have the same size");
469  transf[i] = new PTools::Transform;
470  transf[i]->createTransform(pano.getImage(i), pano.getOptions());
471  vigra::Size2D srcSize = pano.getImage(i).getSize();
472  maxr[i] = sqrt(((double)srcSize.x)*srcSize.x + ((double)srcSize.y)*srcSize.y) / 2.0;
473  }
474  // init random number generator
475  const vigra::Rect2D roi = pano.getOptions().getROI();
476  std::mt19937 rng(static_cast<unsigned int>(std::time(0)));
477  std::uniform_int_distribution<unsigned int> distribx(roi.left(), roi.right()-1);
478  std::uniform_int_distribution<unsigned int> distriby(roi.top(), roi.bottom()-1);
479  auto randX = std::bind(distribx, std::ref(rng));
480  auto randY = std::bind(distriby, std::ref(rng));
481 
482  for (unsigned maxTry = nPoints*5; nPoints > 0 && maxTry > 0; maxTry--) {
483  unsigned x = randX();
484  unsigned y = randY();
485  hugin_utils::FDiff2D panoPnt(x,y);
486  for (unsigned i=0; i< nImg-1; i++) {
487  // transform pixel
488  PixelType i1;
490  if(!transf[i]->transformImgCoord(p1, panoPnt))
491  continue;
492  vigra::Point2D p1Int(p1.toDiff2D());
493  // check if pixel is valid
494  if (!pano.getImage(i).isInside(p1Int)) {
495  // point is outside image
496  continue;
497  }
498  vigra::UInt8 maskI;
499  if ( imgs[i](p1.x,p1.y, i1, maskI)){
500  float im1 = vigra_ext::getMaxComponent(i1);
501  if (limitI[i].GetMinI() > im1 || limitI[i].GetMaxI() < im1) {
502  // ignore pixels that are too dark or bright
503  continue;
504  }
505  double r1 = hugin_utils::norm((p1 - pano.getImage(i).getRadialVigCorrCenter()) / maxr[i]);
506  for (unsigned j=i+1; j < nImg; j++) {
507  PixelType i2;
509  if(!transf[j]->transformImgCoord(p2, panoPnt))
510  continue;
511  // check if a pixel is inside the source image
512  vigra::Point2D p2Int(p2.toDiff2D());
513  if (!pano.getImage(j).isInside(p2Int)) {
514  // point is outside image
515  continue;
516  }
517  vigra::UInt8 maskI2;
518  if (imgs[j](p2.x, p2.y, i2, maskI2)){
519  float im2 = vigra_ext::getMaxComponent(i2);
520  if (limitI[j].GetMinI() > im2 || limitI[j].GetMaxI() < im2) {
521  // ignore pixels that are too dark or bright
522  continue;
523  }
524  // TODO: add check for gradient radius.
525  double r2 = hugin_utils::norm((p2 - pano.getImage(j).getRadialVigCorrCenter()) / maxr[j]);
526 #if 0
527  // add pixel
528  if (im1 <= im2) {
529  points.push_back(PP(i, i1, p1, r1, j, i2, p2, r2) );
530  } else {
531  points.push_back(PP(j, i2, p2, r2, i, i1, p1, r1) );
532  }
533 #else
534  // add pixel
535  const VoteImg & vimg1 = *voteImgs[i];
536  const VoteImg & vimg2 = *voteImgs[j];
537  double laplace = hugin_utils::sqr(vimg1[p1Int]) + hugin_utils::sqr(vimg2[p2Int]);
538  size_t bin1 = (size_t)(r1*nBins);
539  size_t bin2 = (size_t)(r2*nBins);
540  // a center shift might lead to radi > 1.
541  if (bin1+1 > nBins) bin1 = nBins-1;
542  if (bin2+1 > nBins) bin2 = nBins-1;
543 
544  PP pp;
545  if (im1 <= im2) {
546  // choose i1 to be smaller than i2
547  pp = PP(i, i1, p1, r1, j, i2, p2, r2);
548  } else {
549  pp = PP(j, i2, p2, r2, i, i1, p1, r1);
550  }
551 
552  // decide which bin should be used.
553  std::multimap<double, PP> * map1 = &radiusHist[bin1];
554  std::multimap<double, PP> * map2 = &radiusHist[bin2];
555  std::multimap<double, PP> * destMap;
556  if (map1->empty()) {
557  destMap = map1;
558  } else if (map2->empty()) {
559  destMap = map2;
560  } else if (map1->size() < map2->size()) {
561  destMap = map1;
562  } else if (map1->size() > map2->size()) {
563  destMap = map2;
564  } else if (map1->rbegin()->first > map2->rbegin()->first) {
565  // heuristic: insert into bin with higher maximum laplacian filter response
566  // (higher probablity of misregistration).
567  destMap = map1;
568  } else {
569  destMap = map2;
570  }
571  // insert
572  destMap->insert(std::make_pair(laplace,pp));
573  // remove last element if too many elements have been gathered
574  if (destMap->size() > pairsPerBin) {
575  destMap->erase((--(destMap->end())));
576  }
577 // nGoodPoints++;
578 #endif
579  nPoints--;
580  }
581  }
582  }
583  }
584  }
585  for(unsigned i=0; i < imgs.size(); i++) {
586  delete transf[i];
587  }
588 
589 }
590 
591 
592 } // namespace
593 #endif //_H
static void sampleRadiusUniform(const std::vector< std::multimap< double, PointPairClass > > &radiusHist, unsigned nPoints, std::vector< PointPairClass > &selectedPoints, AppBase::ProgressDisplay *)
extract some random points out of the bins.
Definition: PointSampler.h:270
double norm(T t)
Definition: hugin_math.h:175
class for storing the limits of an image used by the sampler to exclude too dark or too bright pixel ...
Definition: PointSampler.h:44
V getMaxComponent(vigra::RGBValue< V > const &v)
get the maximum component of a vector (also works for single pixel types...)
Definition: utils.h:268
float m_minI
internal stored limits
Definition: PointSampler.h:63
LimitType
some pre-defined limits
Definition: PointSampler.h:48
PointSampler(PanoramaData &panorama, AppBase::ProgressDisplay *progressDisplay, std::vector< vigra::FRGBImage * > images, LimitIntensityVector limits, int nPoints)
Definition: PointSampler.h:71
virtual bool modifiesPanoramaData() const
returns true if the algorithm changes the PanoramaData.
Definition: PointSampler.h:113
const float GetMaxI() const
return the upper limit
Definition: PointSampler.h:58
hugin_utils::FDiff2D getRadialVigCorrCenter() const
AllPointSampler(PanoramaData &panorama, AppBase::ProgressDisplay *progressDisplay, std::vector< vigra::FRGBImage * > images, LimitIntensityVector limits, int nPoints)
Definition: PointSampler.h:153
T sqr(T t)
Definition: hugin_math.h:169
&quot;wrapper&quot; for efficient interpolation access to an image
std::vector< vigra::FRGBImage * > o_images
Definition: PointSampler.h:139
bool isInside(vigra::Point2D p, bool ignoreMasks=false) const
check if a coordinate is inside the source image
functions to manage ROI&#39;s
cubic interpolation
static void sampleAllPanoPoints(const std::vector< Img > &imgs, const std::vector< VoteImg * > &voteImgs, const PanoramaData &pano, int nPoints, const LimitIntensityVector limitI, std::vector< std::multimap< double, PP > > &radiusHist, unsigned &nGoodPoints, unsigned &nBadPoints, AppBase::ProgressDisplay *progress)
sample all points inside a panorama and check for create a bins of point pairs that include a specifi...
Definition: PointSampler.h:301
virtual void samplePoints(const std::vector< InterpolImg > &imgs, const std::vector< vigra::FImage * > &voteImgs, const PanoramaData &pano, const LimitIntensityVector limitI, std::vector< std::multimap< double, vigra_ext::PointPairRGB > > &radiusHist, unsigned &nGoodPoints, unsigned &nBadPoints, AppBase::ProgressDisplay *progress)
Definition: PointSampler.h:180
PointPairs getResultPoints()
Definition: PointSampler.h:130
LimitIntensityVector m_limits
Definition: PointSampler.h:142
const vigra::Rect2D & getROI() const
virtual const PanoramaOptions & getOptions() const =0
returns the options for this panorama
Model for a panorama.
Definition: PanoramaData.h:81
virtual const SrcPanoImage & getImage(std::size_t nr) const =0
get a panorama image, counting starts with 0
#define IMPEX
Definition: hugin_shared.h:39
virtual void samplePoints(const std::vector< InterpolImg > &imgs, const std::vector< vigra::FImage * > &voteImgs, const PanoramaData &pano, const LimitIntensityVector limitI, std::vector< std::multimap< double, vigra_ext::PointPairRGB > > &radiusHist, unsigned &nGoodPoints, unsigned &nBadPoints, AppBase::ProgressDisplay *progress)
Definition: PointSampler.h:233
static void sampleRandomPanoPoints(const std::vector< Img > &imgs, const std::vector< VoteImg * > &voteImgs, const PanoramaData &pano, int nPoints, const LimitIntensityVector limitI, std::vector< std::multimap< double, PP > > &radiusHist, unsigned &nBadPoints, AppBase::ProgressDisplay *progress)
Definition: PointSampler.h:441
std::vector< vigra_ext::PointPairRGB > PointPairs
Definition: PointSampler.h:127
Holds transformations for Image -&gt; Pano and the other way.
std::vector< LimitIntensity > LimitIntensityVector
Definition: PointSampler.h:65
RandomPointSampler(PanoramaData &panorama, AppBase::ProgressDisplay *progressDisplay, std::vector< vigra::FRGBImage * > images, LimitIntensityVector limits, int nPoints)
Definition: PointSampler.h:210
vigra::Diff2D toDiff2D() const
Definition: hugin_math.h:129
PointSampler & execute()
Definition: PointSampler.h:119
const float GetMinI() const
return the lower limit
Definition: PointSampler.h:54
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