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