8 #include <boost/bind.hpp>
14 PoseEstimator::PoseEstimator(
const double locH,
18 boost::shared_ptr<CustomIntegrandFactor> cif,
19 const bool partialview,
20 const bool progress) :
21 evaluationStrategy_(KernelCollection::MAX_EVAL),
22 loc_h_(locH), ori_h_(oriH),
23 nChains_(nChains), n_(n),
24 cif_(cif), partialview_(partialview),
25 progress_(progress), meshTol_(4)
27 if (nChains_ <= 0) nChains_ = 8;
28 parallel_ = typeFromName<parallelizer>(PARALLELIZATION);
33 PoseEstimator::modelToSceneTransformation(
const boost::optional<kernel::se3>& gtTransfo)
const
40 n = objectModel_.
size();
43 NUKLEI_WARN(
"Warning: Object model has more than 1000 points. "
44 "To keep computational cost low, only 1000 points will be "
45 "used at each inference loop. "
46 "Use -n to force a large number of model points.");
53 KernelCollection poses;
56 NUKLEI_WARN(
"Nuklei has not been compiled with OpenMP support. "
57 "Pose estimation will use a single core.");
61 pi_->initialize(0, 10*n*(partialview_?4:1)*nChains_ / 10,
"Estimating pose", 0);
63 parallelizer p(nChains_, parallel_);
64 std::vector<kernel::se3> retv =
65 p.run<kernel::se3>(boost::bind(&PoseEstimator::mcmc,
this, n),
66 kernel::base::WeightAccessor());
71 for (std::vector<kernel::se3>::const_iterator i = retv.begin();
82 bool s = (d.first < t.first && d.second < t.second);
85 std::cout <<
"Matching score: " << i->getWeight() <<
", ";
86 std::cout <<
"distance to GT: " << d.first <<
" " << d.second <<
", ";
87 if (s) std::cout <<
"success";
88 else std::cout <<
"failure";
89 std::cout << std::endl;
91 std::cout <<
"Number of successful chains: " << success <<
" out of ";
92 std::cout << poses.size() <<
"." << std::endl;
95 kernel::se3 pose(*poses.sortBegin(1));
96 pose.setWeight(findMatchingScore(pose));
103 PoseEstimator::findMatchingScore(
const kernel::se3& pose)
const
105 NUKLEI_TRACE_BEGIN();
106 kernel::se3 t = pose;
110 double w1 = 0, w2 = 0;
112 KernelCollection tmp = objectModel_;
114 tmp.computeKernelStatistics();
118 i != objectModel_.
end(); ++i)
120 w1 += sceneModel_.
evaluationAt(*i->polyTransformedWith(t),
121 evaluationStrategy_);
125 i != sceneModel_.
end(); ++i)
127 w2 += tmp.evaluationAt(*i, evaluationStrategy_);
130 t.setWeight(w1/objectModel_.
size() * (cif_?cif_->factor(pose):1.));
144 evaluationStrategy_);
145 t.setWeight(t.getWeight() + w);
147 t.setWeight(t.getWeight()/std::pow(std::distance(viewIterator, viewIterator.end()), .7) * (cif_?cif_->factor(pose):1.));
149 if (cif_ && !cif_->test(t))
153 return t.getWeight();
157 void PoseEstimator::load(
const std::string& objectFilename,
158 const std::string& sceneFilename,
159 const std::string& meshfile,
160 const std::string& viewpointfile,
162 const bool computeNormals)
164 NUKLEI_TRACE_BEGIN();
165 KernelCollection objectModel, sceneModel;
168 Vector3 viewpoint(0, 0, 0);
174 load(objectModel, sceneModel, meshfile, viewpoint,
175 light, computeNormals);
180 void PoseEstimator::load(
const KernelCollection& objectModel,
181 const KernelCollection& sceneModel,
182 const std::string& meshfile,
183 const Vector3& viewpoint,
185 const bool computeNormals)
187 NUKLEI_TRACE_BEGIN();
188 objectModel_ = objectModel;
189 sceneModel_ = sceneModel;
190 viewpoint_ = viewpoint;
192 if (objectModel_.
size() == 0 || sceneModel_.
size() == 0)
195 if (objectModel_.
front().polyType() == kernel::base::R3)
204 if (sceneModel_.
front().polyType() == kernel::base::R3)
213 if (objectModel_.
front().polyType() != sceneModel_.
front().polyType())
214 NUKLEI_THROW(
"Input point clouds must be defined on the same domain.");
216 if (light && sceneModel_.
size() > 10000)
219 KernelCollection tmp;
222 for (; i != i.end(); i++)
229 objectSize_ = objectModel_.
moments()->getLocH();
232 loc_h_ = objectSize_ / 10;
245 if (!meshfile.empty())
246 objectModel_.readMeshFromOffFile(meshfile);
254 pi_.reset(
new ProgressIndicator(1,
"", 11));
260 double PoseEstimator::Ti(
const unsigned i,
const unsigned F)
263 const double T0 = .5;
264 const double TF = .05;
266 return std::max(T0 * std::pow(TF/T0,
double(i)/F), TF);
270 bool PoseEstimator::recomputeIndices(std::vector<int>& indices,
271 const kernel::se3& nextPose,
274 Vector3 mean = objectModel_.
mean()->getLoc();
275 Vector3 v = la::normalized(viewpointInFrame(nextPose) - mean);
276 std::vector<int> pindices = objectModel_.
partialView(v, meshTol_,
true,
true);
278 if (pindices.size() < 20)
return false;
284 if (indices.size() > n)
297 PoseEstimator::metropolisHastings(kernel::se3& currentPose,
303 NUKLEI_TRACE_BEGIN();
306 std::vector<int> indices;
312 indices.push_back(i.index());
317 kernel::se3 nextPose;
319 bool independentProposal =
false;
325 independentProposal =
true;
327 for (
int count = 0; ; ++count)
329 if (count == 100)
return;
330 const kernel::base& randomModelPoint = objectModel_.
at(indices.at(
Random::uniformInt(indices.size())));
331 kernel::se3::ptr k2 = randomModelPoint.polySe3Proj();
334 nextPose = k1->transformationFrom(*k2);
336 if (cif_ && !cif_->test(nextPose))
continue;
340 bool visible =
false;
342 if (randomModelPoint.polyType() == kernel::base::R3XS2P)
344 viewpointInFrame(nextPose),
347 visible = objectModel_.
isVisibleFrom(randomModelPoint.getLoc(),
348 viewpointInFrame(nextPose),
350 if (!visible)
continue;
352 if (! recomputeIndices(indices, nextPose, n))
363 independentProposal =
false;
364 NUKLEI_DEBUG_ASSERT(currentPose.loc_h_ > 0 && currentPose.ori_h_ > 0);
365 for (
int count = 0; ; ++count)
367 if (count == 100)
return;
368 nextPose = currentPose.sample();
369 if (cif_ && !cif_->test(nextPose))
continue;
370 if (partialview_ && ! recomputeIndices(indices, nextPose, n))
380 double factor = (cif_?cif_->factor(nextPose):1.);
383 for (
unsigned pi = 0; pi < indices.size(); ++pi)
385 const kernel::base& objectPoint =
386 objectModel_.
at(indices.at(pi));
391 if (WEIGHTED_SUM_EVIDENCE_EVAL)
394 KernelCollection::WEIGHTED_SUM_EVAL) +
395 WHITE_NOISE_POWER/sceneModel_.
size() );
399 w = (sceneModel_.
evaluationAt(*test, KernelCollection::MAX_EVAL) +
408 if (pi < std::sqrt(indices.size()))
continue;
411 weight_t nextWeight = weight/(pi+1.);
412 if (partialview_) nextWeight = weight/std::sqrt(pi+1.);
416 if (pi == indices.size()-1)
418 currentPose = nextPose;
419 currentWeight = nextWeight;
425 weight_t dec = std::pow(nextWeight/currentWeight, 1./temperature);
426 if (independentProposal) dec *= currentWeight/nextWeight;
429 if (dec < .6*threshold)
435 if (pi == indices.size()-1)
439 currentPose = nextPose;
440 currentWeight = nextWeight;
450 PoseEstimator::mcmc(
const int n)
const
452 NUKLEI_TRACE_BEGIN();
453 kernel::se3 currentPose, bestPose;
455 bestPose.setWeight(currentWeight);
456 metropolisHastings(currentPose, currentWeight, 1,
true, n);
460 if (partialview_) nSteps = 1000;
462 nSteps = 10*n*(partialview_?4:1);
464 for (
int i = 0; i < nSteps; i++)
468 coord_t bLocH = objectSize_/10;
469 coord_t eLocH = objectSize_/40;
473 unsigned e = nSteps-1;
475 currentPose.setLocH(
double(e-i)/e * bLocH +
476 double(i)/e * eLocH);
477 currentPose.setOriH(
double(e-i)/e * bOriH +
478 double(i)/e * eOriH);
479 if (currentPose.loc_h_ <= 0)
481 NUKLEI_THROW(
"Unexpected value for currentPose.loc_h_.");
483 if (progress_ && i%10 == 0) pi_->mtInc();
486 metropolisHastings(currentPose, currentWeight,
487 Ti(i, nSteps/5),
false, n);
489 if (currentWeight > bestPose.getWeight())
491 bestPose = currentPose;
492 bestPose.setWeight(currentWeight);
500 Vector3 PoseEstimator::viewpointInFrame(
const kernel::se3& frame)
const
503 kernel::se3 invt = origin.transformationFrom(frame);
506 return v.transformedWith(invt).getLoc();
510 PoseEstimator::writeAlignedModel(
const std::string& filename,
511 const kernel::se3& t)
const
513 NUKLEI_TRACE_BEGIN();
514 KernelCollection objectModel = objectModel_;
517 objectModel = KernelCollection();
520 i != objectModel_.
end(); ++i)
523 bool visible =
false;
524 const kernel::base& tmp = *i;
525 if (tmp.polyType() == kernel::base::R3XS2P)
527 viewpointInFrame(tt),
531 viewpointInFrame(tt),
538 objectModel.back().setDescriptor(d);
542 objectModel.transformWith(t);
545 Observation::SERIAL);
549 void PoseEstimator::setCustomIntegrandFactor(boost::shared_ptr<CustomIntegrandFactor> cif)
554 boost::shared_ptr<CustomIntegrandFactor> PoseEstimator::getCustomIntegrandFactor()
const