Hugin trunk 0.1
Loading...
Searching...
No Matches
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>
39
40namespace 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:
72 std::vector<vigra::FRGBImage*> images, LimitIntensityVector limits,
73 int nPoints)
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,
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,
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,
173 std::vector<std::multimap<double, PP > > & radiusHist,
174 unsigned & nGoodPoints,
175 unsigned & nBadPoints,
177
178 protected:
180 virtual void samplePoints(const std::vector<InterpolImg>& imgs,
181 const std::vector<vigra::FImage*>& voteImgs,
182 const PanoramaData& pano,
184 std::vector<std::multimap<double,vigra_ext::PointPairRGB> >& radiusHist,
185 unsigned& nGoodPoints,
186 unsigned& nBadPoints,
188 {
190 voteImgs,
191 pano,
193 limitI,
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
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,
227 std::vector<std::multimap<double, PP > > & radiusHist,
228 unsigned & nBadPoints,
230
231 protected:
233 virtual void samplePoints(const std::vector<InterpolImg>& imgs,
234 const std::vector<vigra::FImage*>& voteImgs,
235 const PanoramaData& pano,
237 std::vector<std::multimap<double,vigra_ext::PointPairRGB> >& radiusHist,
238 unsigned& nGoodPoints,
239 unsigned& nBadPoints,
241 {
243 voteImgs,
244 pano,
245 5*o_numPoints,
246 limitI,
249 progress);
250 }
251
252 };
253
254
255
256} // namespace
257
258
259
260
261
262//==============================================================================
263// templated methods
264
266
267namespace HuginBase {
268
269template<class PointPairClass>
270void PointSampler::sampleRadiusUniform(const std::vector<std::multimap<double, PointPairClass> >& radiusHist,
271 unsigned nPoints,
272 std::vector<PointPairClass> &selectedPoints,
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
300template <class Img, class VoteImg, class PP>
301void AllPointSampler::sampleAllPanoPoints(const std::vector<Img> &imgs,
302 const std::vector<VoteImg *> &voteImgs,
303 const PanoramaData& pano,
304 int nPoints,
306 //std::vector<vigra_ext::PointPair> &points,
307 std::vector<std::multimap<double, PP > > & radiusHist,
308 unsigned & nGoodPoints,
309 unsigned & nBadPoints,
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");
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) {
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)){
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)){
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];
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
440template <class Img, class VoteImg, class PP>
441void RandomPointSampler::sampleRandomPanoPoints(const std::vector<Img>& imgs,
442 const std::vector<VoteImg *> &voteImgs,
443 const PanoramaData& pano,
444 int nPoints,
446 //std::vector<PP> &points,
447 std::vector<std::multimap<double, PP > > & radiusHist,
448 unsigned & nBadPoints,
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");
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();
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)){
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)){
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];
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
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)
AllPointSampler(PanoramaData &panorama, AppBase::ProgressDisplay *progressDisplay, std::vector< vigra::FRGBImage * > images, LimitIntensityVector limits, int nPoints)
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...
class for storing the limits of an image used by the sampler to exclude too dark or too bright pixel
const float GetMaxI() const
return the upper limit
LimitType
some pre-defined limits
const float GetMinI() const
return the lower limit
Holds transformations for Image -> Pano and the other way.
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->image transformation
Model for a panorama.
virtual const PanoramaOptions & getOptions() const =0
returns the options for this panorama
virtual const SrcPanoImage & getImage(std::size_t nr) const =0
get a panorama image, counting starts with 0
const vigra::Rect2D & getROI() const
PointPairs getResultPoints()
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.
std::vector< vigra_ext::PointPairRGB > PointPairs
std::vector< vigra::FRGBImage * > o_images
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 *)=0
LimitIntensityVector m_limits
PointSampler(PanoramaData &panorama, AppBase::ProgressDisplay *progressDisplay, std::vector< vigra::FRGBImage * > images, LimitIntensityVector limits, int nPoints)
vigra_ext::ImageInterpolator< vigra::FRGBImage::const_traverser, vigra::FRGBImage::ConstAccessor, vigra_ext::interp_cubic > InterpolImg
PointSampler & execute()
virtual bool modifiesPanoramaData() const
returns true if the algorithm changes the PanoramaData.
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)
RandomPointSampler(PanoramaData &panorama, AppBase::ProgressDisplay *progressDisplay, std::vector< vigra::FRGBImage * > images, LimitIntensityVector limits, int nPoints)
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)
hugin_utils::FDiff2D getRadialVigCorrCenter() const
bool isInside(vigra::Point2D p, bool ignoreMasks=false) const
check if a coordinate is inside the source image
"wrapper" for efficient interpolation access to an image
#define IMPEX
mainly consists of wrapper around the pano tools library, to assist in ressource management and to pr...
Definition wxcms.cpp:39
std::vector< LimitIntensity > LimitIntensityVector
double norm(T t)
Definition hugin_math.h:187
V getMaxComponent(vigra::RGBValue< V > const &v)
get the maximum component of a vector (also works for single pixel types...)
Definition utils.h:268
vigra::Diff2D toDiff2D() const
Definition hugin_math.h:141
cubic interpolation
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
functions to manage ROI's