Visual Servoing Platform  version 3.6.1 under development (2024-09-07)
vpParticleFilter.h
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  *
30  * Description:
31  * Display a point cloud using PCL library.
32  */
33 
34 #ifndef VP_PARTICLE_FILTER_H
35 #define VP_PARTICLE_FILTER_H
36 
37 #include <visp3/core/vpConfig.h>
38 
39 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
40 #include <visp3/core/vpColVector.h>
41 #include <visp3/core/vpGaussRand.h>
42 #include <visp3/core/vpMatrix.h>
43 
44 #include <functional> // std::function
45 
46 #ifdef VISP_HAVE_OPENMP
47 #include <omp.h>
48 #endif
49 
57 template <typename MeasurementsType>
59 {
60 public:
65  typedef struct vpParticlesWithWeights
66  {
67  std::vector<vpColVector> m_particles;
68  std::vector<double> m_weights;
70 
77  typedef std::function<vpColVector(const vpColVector &, const vpColVector &)> vpStateAddFunction;
78 
84  typedef std::function<vpColVector(const vpColVector &, const double &)> vpProcessFunction;
85 
92  typedef std::function<vpColVector(const vpColVector &, const vpColVector &, const double &)> vpCommandStateFunction;
93 
101  typedef std::function<double(const vpColVector &, const MeasurementsType &)> vpLikelihoodFunction;
102 
110  typedef std::function<vpColVector(const std::vector<vpColVector> &, const std::vector<double> &, const vpStateAddFunction &)> vpFilterFunction;
111 
117  typedef std::function<bool(const unsigned int &, const std::vector<double> &)> vpResamplingConditionFunction;
118 
123  typedef std::function<vpParticlesWithWeights(const std::vector<vpColVector> &, const std::vector<double> &)> vpResamplingFunction;
124 
135  VP_EXPLICIT vpParticleFilter(const unsigned int &N, const std::vector<double> &stdev, const long &seed = -1, const int &nbThreads = -1);
136 
137  inline virtual ~vpParticleFilter() { }
138 
155  void init(const vpColVector &x0, const vpProcessFunction &f,
156  const vpLikelihoodFunction &l,
157  const vpResamplingConditionFunction &checkResamplingFunc, const vpResamplingFunction &resamplingFunc,
158  const vpFilterFunction &filterFunc = weightedMean,
159  const vpStateAddFunction &addFunc = simpleAdd);
160 
177  void init(const vpColVector &x0, const vpCommandStateFunction &bx,
178  const vpLikelihoodFunction &l,
179  const vpResamplingConditionFunction &checkResamplingFunc, const vpResamplingFunction &resamplingFunc,
180  const vpFilterFunction &filterFunc = weightedMean,
181  const vpStateAddFunction &addFunc = simpleAdd);
182 
195  void filter(const MeasurementsType &z, const double &dt, const vpColVector &u = vpColVector());
196 
207  void predict(const double &dt, const vpColVector &u = vpColVector());
208 
215  void update(const MeasurementsType &z);
216 
223 
231  inline void setProcessFunction(const vpProcessFunction &f)
232  {
233  m_f = f;
234  m_useCommandStateFunction = false;
235  m_useProcessFunction = true;
236  }
237 
246  {
247  m_bx = bx;
248  m_useCommandStateFunction = true;
249  m_useProcessFunction = false;
250  }
251 
258  inline void setLikelihoodFunction(const vpLikelihoodFunction &likelihood)
259  {
260  m_likelihood = likelihood;
261  }
262 
269  inline void setFilterFunction(const vpFilterFunction &filterFunc)
270  {
271  m_stateFilterFunc = filterFunc;
272  }
273 
280  inline void setCheckResamplingFunction(const vpResamplingConditionFunction &resamplingCondFunc)
281  {
282  m_checkIfResample = resamplingCondFunc;
283  }
284 
291  inline void setResamplingFunction(const vpResamplingFunction &resamplingFunc)
292  {
293  m_resampling = resamplingFunc;
294  }
295 
303  inline static vpColVector simpleAdd(const vpColVector &a, const vpColVector &toAdd)
304  {
305  vpColVector res = a + toAdd;
306  return res;
307  }
308 
318  static vpColVector weightedMean(const std::vector<vpColVector> &particles, const std::vector<double> &weights, const vpStateAddFunction &addFunc);
319 
329  static bool simpleResamplingCheck(const unsigned int &N, const std::vector<double> &weights);
330 
339  static vpParticlesWithWeights simpleImportanceResampling(const std::vector<vpColVector> &particles, const std::vector<double> &weights);
340 
341 private:
342  void initParticles(const vpColVector &x0);
343 #ifdef VISP_HAVE_OPENMP
344  void predictMultithread(const double &dt, const vpColVector &u);
345  void updateMultithread(const MeasurementsType &z);
346 #endif
347 
348  void predictMonothread(const double &dt, const vpColVector &u);
349  void updateMonothread(const MeasurementsType &z);
350 
351  static vpUniRand sampler;
352  static vpUniRand samplerRandomIdx;
353 
354  unsigned int m_N;
355  unsigned int m_nbMaxThreads;
356  std::vector<std::vector<vpGaussRand>> m_noiseGenerators;
357  std::vector<vpColVector> m_particles;
358  std::vector<double> m_w;
360  vpColVector m_Xest;
362  vpProcessFunction m_f;
363  vpLikelihoodFunction m_likelihood;
365  vpFilterFunction m_stateFilterFunc;
366  vpResamplingConditionFunction m_checkIfResample;
367  vpResamplingFunction m_resampling;
368  vpStateAddFunction m_stateAdd;
370  bool m_useProcessFunction;
371  bool m_useCommandStateFunction;
372 };
373 
374 template <typename MeasurementsType>
376 
377 template <typename MeasurementsType>
379 
380 template <typename MeasurementsType>
381 vpParticleFilter<MeasurementsType>::vpParticleFilter(const unsigned int &N, const std::vector<double> &stdev, const long &seed, const int &nbThreads)
382  : m_N(N)
383  , m_particles(N)
384  , m_w(N, 1./static_cast<double>(N))
385  , m_useProcessFunction(false)
386  , m_useCommandStateFunction(false)
387 {
388 #ifndef VISP_HAVE_OPENMP
389  m_nbMaxThreads = 1;
390  if (nbThreads > 1) {
391  std::cout << "[vpParticleFilter::vpParticleFilter] WARNING: OpenMP is not available, maximum number of threads to use clamped to 1" << std::endl;
392  }
393 #else
394  int maxThreads = omp_get_max_threads();
395  if (nbThreads <= 0) {
396  m_nbMaxThreads = maxThreads;
397  }
398  else if (nbThreads > maxThreads) {
399  m_nbMaxThreads = maxThreads;
400  std::cout << "[vpParticleFilter::vpParticleFilter] WARNING: maximum number of threads to use clamped to "
401  << maxThreads << " instead of " << nbThreads << " due to OpenMP restrictions." << std::endl;
402  std::cout << "[vpParticleFilter::vpParticleFilter] If you want more, consider to use omp_set_num_threads before." << std::endl;
403  }
404  else {
405  m_nbMaxThreads = nbThreads;
406  }
407 #endif
408  // Generating the random generators
409  unsigned int sizeState = static_cast<unsigned int>(stdev.size());
410  m_noiseGenerators.resize(m_nbMaxThreads);
411  unsigned long long seedForGenerator;
412  if (seed > 0) {
413  seedForGenerator = seed;
414  }
415  else {
416  seedForGenerator = static_cast<unsigned long long>(vpTime::measureTimeMicros());
417  }
418 
419  // Sampler for the simpleImportanceResampling method
420  sampler.setSeed(seed, 0x123465789ULL);
421  samplerRandomIdx.setSeed(seed + 4224, 0x123465789ULL);
422 
423  vpUniRand seedGenerator(seedForGenerator);
424  for (unsigned int threadId = 0; threadId < m_nbMaxThreads; ++threadId) {
425  for (unsigned int stateId = 0; stateId < sizeState; ++stateId) {
426  m_noiseGenerators[threadId].push_back(vpGaussRand(stdev[stateId], 0., seedGenerator.uniform(0., 1e9)));
427  }
428  }
429 }
430 
431 template <typename MeasurementsType>
433  const vpLikelihoodFunction &l,
434  const vpResamplingConditionFunction &checkResamplingFunc, const vpResamplingFunction &resamplingFunc,
435  const vpFilterFunction &filterFunc, const vpStateAddFunction &addFunc)
436 {
437  m_f = f;
438  m_stateFilterFunc = filterFunc;
439  m_likelihood = l;
440  m_checkIfResample = checkResamplingFunc;
441  m_resampling = resamplingFunc;
442  m_stateAdd = addFunc;
443  m_useProcessFunction = true;
444  m_useCommandStateFunction = false;
445 
446  // Initialize the different particles
447  initParticles(x0);
448 }
449 
450 template <typename MeasurementsType>
452  const vpLikelihoodFunction &l,
453  const vpResamplingConditionFunction &checkResamplingFunc, const vpResamplingFunction &resamplingFunc,
454  const vpFilterFunction &filterFunc, const vpStateAddFunction &addFunc)
455 {
456  m_bx = bx;
457  m_stateFilterFunc = filterFunc;
458  m_likelihood = l;
459  m_checkIfResample = checkResamplingFunc;
460  m_resampling = resamplingFunc;
461  m_stateAdd = addFunc;
462  m_useProcessFunction = false;
463  m_useCommandStateFunction = true;
464 
465  // Initialize the different particles
466  initParticles(x0);
467 }
468 
469 template <typename MeasurementsType>
470 void vpParticleFilter<MeasurementsType>::filter(const MeasurementsType &z, const double &dt, const vpColVector &u)
471 {
472  predict(dt, u);
473  update(z);
474 }
475 
476 template <typename MeasurementsType>
478 {
479  if (m_nbMaxThreads == 1) {
480  predictMonothread(dt, u);
481  }
482 #ifdef VISP_HAVE_OPENMP
483  else {
484  predictMultithread(dt, u);
485  }
486 #endif
487 }
488 
489 template <typename MeasurementsType>
490 void vpParticleFilter<MeasurementsType>::update(const MeasurementsType &z)
491 {
492  if (m_nbMaxThreads == 1) {
493  updateMonothread(z);
494  }
495 #ifdef VISP_HAVE_OPENMP
496  else {
497  updateMultithread(z);
498  }
499 #endif
500  bool shouldResample = m_checkIfResample(m_N, m_w);
501  if (shouldResample) {
502  vpParticlesWithWeights particles_weights = m_resampling(m_particles, m_w);
503  m_particles = std::move(particles_weights.m_particles);
504  m_w = std::move(particles_weights.m_weights);
505  }
506 }
507 
508 template <typename MeasurementsType>
510 {
511  return m_stateFilterFunc(m_particles, m_w, m_stateAdd);
512 }
513 
514 template <typename MeasurementsType>
515 vpColVector vpParticleFilter<MeasurementsType>::weightedMean(const std::vector<vpColVector> &particles, const std::vector<double> &weights, const vpStateAddFunction &addFunc)
516 {
517  size_t nbParticles = particles.size();
518  if (nbParticles == 0) {
519  throw(vpException(vpException::dimensionError, "No particles to add when computing the mean"));
520  }
521  vpColVector res = particles[0] * weights[0];
522  for (size_t i = 1; i < nbParticles; ++i) {
523  res = addFunc(res, particles[i] * weights[i]);
524  }
525  return res;
526 }
527 
528 template <typename MeasurementsType>
529 bool vpParticleFilter<MeasurementsType>::simpleResamplingCheck(const unsigned int &N, const std::vector<double> &weights)
530 {
531  double sumSquare = 0.;
532  for (unsigned int i = 0; i < N; ++i) {
533  sumSquare += weights[i] * weights[i];
534  }
535  if (sumSquare < std::numeric_limits<double>::epsilon()) {
536  // All the particles diverged
537  return true;
538  }
539  double N_eff = 1.0 / sumSquare;
540  return (N_eff < (N / 2.0));
541 }
542 
543 template <typename MeasurementsType>
544 typename vpParticleFilter<MeasurementsType>::vpParticlesWithWeights vpParticleFilter<MeasurementsType>::simpleImportanceResampling(const std::vector<vpColVector> &particles, const std::vector<double> &weights)
545 {
546  unsigned int nbParticles = static_cast<unsigned int>(particles.size());
547  double x = 0.;
548  double sumWeights = 0.;
549  std::vector<int> idx(nbParticles);
550 
551  // Draw indices of the randomly chosen particles from the vector of particles
552  for (unsigned int i = 0; i < nbParticles; ++i) {
553  x = sampler();
554  sumWeights = 0.0;
555  int index = samplerRandomIdx.uniform(0, nbParticles); // In case all the weights are null
556  for (unsigned int j = 0; j < nbParticles; ++j) {
557  if (x < sumWeights + weights[j]) {
558  index = j;
559  break;
560  }
561  sumWeights += weights[j];
562  }
563  idx[i] = index;
564  }
565 
566  // Draw the randomly chosen particles corresponding to the indices
567  vpParticlesWithWeights newParticlesWeights;
568  newParticlesWeights.m_particles.resize(nbParticles);
569  for (unsigned int i = 0; i < nbParticles; ++i) {
570  newParticlesWeights.m_particles[i] = particles[idx[i]];
571  }
572 
573  // Reinitialize the weights
574  newParticlesWeights.m_weights.resize(nbParticles, 1.0/ static_cast<double>(nbParticles));
575  return newParticlesWeights;
576 }
577 
578 template <typename MeasurementsType>
580 {
581  unsigned int sizeState = x0.size();
582  unsigned int chunkSize = m_N / m_nbMaxThreads;
583  double uniformWeight = 1. / static_cast<double>(m_N);
584  for (unsigned int i = 0; i < m_nbMaxThreads; ++i) {
585  unsigned int idStart = chunkSize * i;
586  unsigned int idStop = chunkSize * (i + 1);
587  // Last chunk must go until the end
588  if (i == m_nbMaxThreads - 1) {
589  idStop = m_N;
590  }
591  for (unsigned int id = idStart; id < idStop; ++id) {
592  // Generating noise
593  vpColVector noise(sizeState);
594  for (unsigned int idState = 0; idState < sizeState; ++idState) {
595  noise[idState] = m_noiseGenerators[i][idState]();
596  }
597  // Adding noise to the initial state
598  m_particles[id] = m_stateAdd(x0, noise);
599 
600  // (Re)initializing its weight
601  m_w[id] = uniformWeight;
602  }
603  }
604 }
605 
606 #ifdef VISP_HAVE_OPENMP
607 template <typename MeasurementsType>
609 {
610  int iam, nt, ipoints, istart, npoints(m_N);
611  unsigned int sizeState = m_particles[0].size();
612 #pragma omp parallel default(shared) private(iam, nt, ipoints, istart)
613  {
614  iam = omp_get_thread_num();
615  nt = omp_get_num_threads();
616  ipoints = npoints / nt;
617  // size of partition
618  istart = iam * ipoints; // starting array index
619  if (iam == nt-1) {
620  // last thread may do more
621  ipoints = npoints - istart;
622  }
623 
624  for (int i = istart; i< istart + ipoints; ++i) {
625  // Updating the particles following the process (or command) function
626  if (m_useCommandStateFunction) {
627  m_particles[i] = m_bx(u, m_particles[i], dt);
628  }
629  else if (m_useProcessFunction) {
630  m_particles[i] = m_f(m_particles[i], dt);
631  }
632 
633  // Generating noise to add to the particle
634  vpColVector noise(sizeState);
635  for (unsigned int j = 0; j < sizeState; ++j) {
636  noise[j] = m_noiseGenerators[iam][j]();
637  }
638 
639  // Adding the noise to the particle
640  m_particles[i] = m_stateAdd(m_particles[i], noise);
641  }
642  }
643 }
644 
645 template <typename MeasurementsType>
646 double threadLikelihood(const typename vpParticleFilter<MeasurementsType>::vpLikelihoodFunction &likelihood, const std::vector<vpColVector> &v_particles,
647  const vpColVector &z, std::vector<double> &w, const int &istart, const int &ipoints)
648 {
649  double sum(0.0);
650  for (int i = istart; i< istart + ipoints; ++i) {
651  w[i] = w[i] * likelihood(v_particles[i], z);
652  sum += w[i];
653  }
654  return sum;
655 }
656 
657 template <typename MeasurementsType>
658 void vpParticleFilter<MeasurementsType>::updateMultithread(const MeasurementsType &z)
659 {
660  double sumWeights = 0.0;
661  int iam, nt, ipoints, istart, npoints(m_N);
662  vpColVector tempSums(m_nbMaxThreads, 0.0);
663  // Compute the weights depending on the likelihood of a particle with regard to the measurements
664 #pragma omp parallel default(shared) private(iam, nt, ipoints, istart)
665  {
666  iam = omp_get_thread_num();
667  nt = omp_get_num_threads();
668  ipoints = npoints / nt;
669  // size of partition
670  istart = iam * ipoints; // starting array index
671  if (iam == nt-1) {
672  // last thread may do more
673  ipoints = npoints - istart;
674  }
675  tempSums[iam] = threadLikelihood<MeasurementsType>(m_likelihood, m_particles, z, m_w, istart, ipoints);
676  }
677  sumWeights = tempSums.sum();
678 
679  if (sumWeights > std::numeric_limits<double>::epsilon()) {
680 #pragma omp parallel default(shared) private(iam, nt, ipoints, istart)
681  {
682  iam = omp_get_thread_num();
683  nt = omp_get_num_threads();
684  ipoints = npoints / nt;
685  // size of partition
686  istart = iam * ipoints; // starting array index
687  if (iam == nt-1) {
688  // last thread may do more
689  ipoints = npoints - istart;
690  }
691 
692  // Normalize the weights
693  for (int i = istart; i < istart + ipoints; ++i) {
694  m_w[i] = m_w[i] / sumWeights;
695  }
696  }
697  }
698 }
699 #endif
700 
701 template <typename MeasurementsType>
703 {
704  unsigned int sizeState = m_particles[0].size();
705  for (unsigned int i = 0; i < m_N; ++i) {
706  // Updating the particle following the process (or command) function
707  if (m_useCommandStateFunction) {
708  m_particles[i] = m_bx(u, m_particles[i], dt);
709  }
710  else if (m_useProcessFunction) {
711  m_particles[i] = m_f(m_particles[i], dt);
712  }
713  else {
714  throw(vpException(vpException::notInitialized, "vpParticleFilter has not been initialized before calling predict"));
715  }
716 
717  // Generating noise to add to the particle
718  vpColVector noise(sizeState);
719  for (unsigned int j = 0; j < sizeState; ++j) {
720  noise[j] = m_noiseGenerators[0][j]();
721  }
722 
723  // Adding the noise to the particle
724  m_particles[i] = m_stateAdd(m_particles[i], noise);
725  }
726 }
727 
728 template <typename MeasurementsType>
729 void vpParticleFilter<MeasurementsType>::updateMonothread(const MeasurementsType &z)
730 {
731  double sumWeights = 0.;
732  // Compute the weights depending on the likelihood of a particle with regard to the measurements
733  for (unsigned int i = 0; i < m_N; ++i) {
734  m_w[i] = m_w[i] * m_likelihood(m_particles[i], z);
735  sumWeights += m_w[i];
736  }
737 
738  // Normalize the weights
739  if (sumWeights > std::numeric_limits<double>::epsilon()) {
740  for (unsigned int i = 0; i < m_N; ++i) {
741  m_w[i] = m_w[i] / sumWeights;
742  }
743  }
744 }
745 END_VISP_NAMESPACE
746 #endif
747 #endif
unsigned int size() const
Return the number of elements of the 2D array.
Definition: vpArray2D.h:349
Implementation of column vector and the associated operations.
Definition: vpColVector.h:191
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ notInitialized
Used to indicate that a parameter is not initialized.
Definition: vpException.h:74
@ dimensionError
Bad dimension.
Definition: vpException.h:71
Class for generating random number with normal probability density.
Definition: vpGaussRand.h:117
The class permits to use a Particle Filter.
std::function< vpParticlesWithWeights(const std::vector< vpColVector > &, const std::vector< double > &)> vpResamplingFunction
Function that takes as argument the vector of particles and the vector of associated weights....
virtual ~vpParticleFilter()
void setResamplingFunction(const vpResamplingFunction &resamplingFunc)
Set the resampling function that generate new particles and associated weights when the filter starts...
void setLikelihoodFunction(const vpLikelihoodFunction &likelihood)
Set the likelihood function that updates the weights of the particles based on the new measurements.
std::function< vpColVector(const std::vector< vpColVector > &, const std::vector< double > &, const vpStateAddFunction &)> vpFilterFunction
Filter function, which computes the filtered state of the particle filter. The first argument is the ...
void filter(const MeasurementsType &z, const double &dt, const vpColVector &u=vpColVector())
Perform first the prediction step and then the update step. If needed, resampling will also be perfor...
static bool simpleResamplingCheck(const unsigned int &N, const std::vector< double > &weights)
Returns true if the following condition is fulfilled, or if all the particles diverged: .
static vpColVector weightedMean(const std::vector< vpColVector > &particles, const std::vector< double > &weights, const vpStateAddFunction &addFunc)
Simple function to compute a weighted mean, which just does .
std::function< vpColVector(const vpColVector &, const double &)> vpProcessFunction
Process model function, which projects a particle forward in time. The first argument is a particle,...
struct vpParticleFilter::vpParticlesWithWeights vpParticlesWithWeights
Structure of vectors for which the i^th element of the weights vector is associated to the i^th eleme...
void init(const vpColVector &x0, const vpProcessFunction &f, const vpLikelihoodFunction &l, const vpResamplingConditionFunction &checkResamplingFunc, const vpResamplingFunction &resamplingFunc, const vpFilterFunction &filterFunc=weightedMean, const vpStateAddFunction &addFunc=simpleAdd)
Set the guess of the initial state.
std::function< vpColVector(const vpColVector &, const vpColVector &, const double &)> vpCommandStateFunction
Command model function, which projects a particle forward in time according to the command and its pr...
static vpParticlesWithWeights simpleImportanceResampling(const std::vector< vpColVector > &particles, const std::vector< double > &weights)
Function implementing the resampling of a Simple Importance Resampling Particle Filter.
std::function< bool(const unsigned int &, const std::vector< double > &)> vpResamplingConditionFunction
Function that takes as argument the number of particles and the vector of weights associated to each ...
static vpColVector simpleAdd(const vpColVector &a, const vpColVector &toAdd)
Simple function to compute an addition, which just does .
void setCheckResamplingFunction(const vpResamplingConditionFunction &resamplingCondFunc)
Set the function that returns true when the filter starts to degenerate and false otherwise.
void setFilterFunction(const vpFilterFunction &filterFunc)
Set the filter function that compute the filtered state from the particles and their associated weigh...
VP_EXPLICIT vpParticleFilter(const unsigned int &N, const std::vector< double > &stdev, const long &seed=-1, const int &nbThreads=-1)
Construct a new vpParticleFilter object.
std::function< double(const vpColVector &, const MeasurementsType &)> vpLikelihoodFunction
Likelihood function, which evaluates the likelihood of a particle with regard to the measurements....
void predict(const double &dt, const vpColVector &u=vpColVector())
Predict the new state based on the last state and how far in time we want to predict.
void setCommandStateFunction(const vpCommandStateFunction &bx)
Set the command function to use when projecting the particles in the future.
void setProcessFunction(const vpProcessFunction &f)
Set the process function to use when projecting the particles in the future.
void update(const MeasurementsType &z)
Update the weights of the particles based on a new measurement. The weights will be normalized (i....
std::function< vpColVector(const vpColVector &, const vpColVector &)> vpStateAddFunction
Function that computes either the equivalent of an addition in the state space. The first argument is...
vpColVector computeFilteredState()
Compute the filtered state from the particles and their associated weights.
Class for generating random numbers with uniform probability density.
Definition: vpUniRand.h:125
int uniform(int a, int b)
Definition: vpUniRand.cpp:159
void setSeed(uint64_t initstate, uint64_t initseq)
Definition: vpUniRand.cpp:202
VISP_EXPORT double measureTimeMicros()
Structure of vectors for which the i^th element of the weights vector is associated to the i^th eleme...
std::vector< vpColVector > m_particles