Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tutorial and examples for Particle Filter #1458

Merged
merged 98 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
fcaf564
[EXAMPLE][FIX] Fix readRealSenseData segfault when pointcloud is empty
Jul 25, 2024
5cc16a5
[TUTO][CLEAN] Fixed a compilation warning
Jul 25, 2024
774d8d2
[TUTO][FIX] Fix error 'Cannot initialize vpArray(0, 0) from std::vect…
Jul 25, 2024
4494cd8
[FIX] Fix 'multiple definition of vpDIsplayFactory:: allocateDisplay()
Jul 25, 2024
5794f5f
UpdatedCopyright
Jul 25, 2024
fb8da13
[TUTO] Began to write the Particle Filter tutorial code.
Jul 25, 2024
411c75f
[CORE] vpCannyEdgeDetection can now give the list of edge-points
Jul 25, 2024
139b888
[TUTO] Particle Filter tuto: least-mean square parabolla estimation
Jul 25, 2024
9b52be8
[TUTO] Added a RANSAC-based parabolla parameters estimation
Jul 26, 2024
6087c17
[FIX] The measurements were of incorrect type in threadLikelihood
Jul 26, 2024
4983d09
[EXAMPLE] Changed nbThreads to be able to set a negative value, to us…
Jul 26, 2024
df6f9e1
[TUTO] First draft of use of the Particle Filter
Jul 26, 2024
a2b6ebf
[TUTO] Protection against lack of display 3rd party
Jul 26, 2024
779b1f1
[TUTO] Added a class for the parabola model
Jul 26, 2024
979c87b
[MERGE] Merged master AprilTag PR into tuto_pf
Aug 5, 2024
6601c68
[TUTO] Extract the skeletton instead of using Canny to extract an edg…
Aug 5, 2024
8452e7d
TUTO] Improved RANSAC method
Aug 5, 2024
b89be67
[TUTO] Possible to read init points from a file
Aug 5, 2024
0cf391e
[TUTO] Moved const legend-related stuff in vpTutoCommonData + [TUTO][…
Aug 5, 2024
ad31df8
[TUTO] Moved the filling of the system and the construction from a ma…
Aug 5, 2024
1352bb0
[TUTO][FIX] Measured time in micros instead of millis for the PF
Aug 6, 2024
98fc4a6
[TUTO] Changed the tutorial for the PF
Aug 28, 2024
b4956da
[TUTO] Removed files of the former tuto for PF
Aug 28, 2024
d5f29ef
[TUTO] Fine-tuning PF parameters
Aug 28, 2024
40abc33
[MERGE] Fixed merge conflict in vpDisplayFactory
Aug 28, 2024
d95267d
[MERGE] Fixed merge conflict in vpDisplayFactory.h
Aug 28, 2024
70864a1
[TUTO] Improved PF tutorial, permitting setting parameters using CLI
Aug 29, 2024
743843b
[EXAMPLE] Changed the non-linear case example of the PF to match the …
Aug 29, 2024
6405e85
[TEST][EXAMPLE] Tuned the test based on the pf-nonlinear-example
Aug 29, 2024
c8c464c
[CLEAN] Corrected a typo in the PF tuto
Aug 29, 2024
8a60037
[FIX] Fix segfault when #threads != max(#threads) of the computer
Aug 29, 2024
d7043e6
[EXAMPLE][FIX] Fix formula to compute the position from the measurements
Aug 29, 2024
5c9445c
[EXAMPLE] Added another example for the PF
Aug 29, 2024
8416357
[EXAMPLE] Modified the likelihood function + [EXAMPLE][TEST] Added un…
Aug 29, 2024
3c25e84
[EXAMPLE][DOC] Improved documentation of the non-linear simple example
Sep 2, 2024
40f6641
[EXAMPLE] Includes the effect of the command in the process function
Sep 2, 2024
d02001e
[EXAMPLE] + [EXAMPLE][DOC]
Sep 2, 2024
bff0e7c
[TUTORIAL][DOC] Improved comments in PF tutorial
Sep 2, 2024
69c8148
[DOC][FIX] Fixed broken documentation of the UKF tutorial
Sep 2, 2024
4f11cb9
[TUTO][DOC] Began to wrote the documentation of the PF tutorial
Sep 2, 2024
af996bb
[TUTO][DOC] Finished the first draft of the PF tutorial documentation
Sep 2, 2024
ddf49c8
[TUTO] Generate simulated curves to check that LMS works. Tests revea…
Sep 4, 2024
6fad376
[TUTO] Can generate 2nd or 3rd degree polynomial simulated images
Sep 4, 2024
ff92325
[TUTO][FIX] Fix skelettonization when the thickness is of 1 pixel only
Sep 4, 2024
167dc66
[TUTO] Moved PF curve fitting tutorial in another folder
Sep 4, 2024
7d9a0c2
[TUTO] Created tuto based on UKF tuto and in another folder put the c…
Sep 4, 2024
a83864b
[TUTO][MERGE] Solved merge conflict with tuto_pf_like_ukf branch
Sep 4, 2024
f29cc46
[FIX] Solved linkage error
Sep 4, 2024
47d9c96
Merge branch 'tuto_pf_like_ukf' into tuto_pf
Sep 4, 2024
c5d852d
[FIX] Throw an error when the size of the state does not match the si…
Sep 4, 2024
4decd4c
Merge branch 'tuto_pf_like_ukf' into tuto_pf
Sep 4, 2024
f01ae20
[TUTO][FIX] Fix freeze when degree != 2
Sep 4, 2024
8aa2a94
[TUTO] Permits to generate polynomials of order > 3
Sep 4, 2024
1a5f005
[TUTO] Min nb of points depends on the degree of the polynomial
Sep 5, 2024
419cc04
[TUTO][FIX] Fixed the number of points to use in the RANSAC to build …
Sep 5, 2024
25043c8
[TUTO] Robustified the PF likelihood
Sep 5, 2024
0a9ac8b
[TUTO] Added plot and final stats
Sep 5, 2024
0f02633
[TUTO][FIX] Fixed the polynomial interpolation by normalizing a prior…
Sep 5, 2024
0700af4
[TUTO][FIX] tuto-pf-curve-fitting
Sep 5, 2024
d128e42
[TUTO] Added salt-and-pepper noise to see the usefulness of the PF
Sep 5, 2024
0ed9f6d
[TUTO] Added CLI options
Sep 6, 2024
2741f10
[TUTO] Changed the color of the PF graphs
Sep 6, 2024
68acda7
Merge branch 'tuto_pf_like_ukf' into tuto_pf
Sep 6, 2024
d283522
[TUTO][DOC][FIX] Fixed typo in doc
Sep 6, 2024
645bfc1
Merge branch 'tuto_pf_like_ukf' into tuto_pf
Sep 6, 2024
1cd085d
[TEST] Added a test for the PF
Sep 9, 2024
5d31ec1
[TUTO] Removed simulated data in the PF curve-fitting
Sep 9, 2024
0255e20
[CORE] vpUniRand::shuffleVector can now be seeded
Sep 9, 2024
08dfe04
[TEST] Added a test with noise added to the init points for the 2nd o…
Sep 9, 2024
2d2e64a
[TEST] Added a noisy case for the 3rd order polynomial interpolation
Sep 9, 2024
481dfc0
[TUTO] Removed display of skeletonized image, leaving only skeletoniz…
Sep 9, 2024
29d21fb
[TUTO] Removed RANSAC-based polynomial interpolator
Sep 10, 2024
bbd1c24
[TUTO][DOC] Added documentation for the segmentation methods + correc…
Sep 10, 2024
665def1
[TUTO] Error is now RMSE + using double
Sep 10, 2024
e010023
[TUTO] Averaging of the polynomials is done in a cleaner way
Sep 10, 2024
be519ee
[TEST] Use cleverer mean computation, which increases the PF accuracy
Sep 10, 2024
92f3b36
[TUTO] Created a separated tuto showing only polynomial interpolation…
Sep 10, 2024
076cc37
[TUTO] Created a tuto showing polynomial interpolation using a PF only
Sep 10, 2024
2e22f83
[TUTO] Removed useless evaluateRobust
Sep 10, 2024
39cd065
[TUTO] Automatic initialization of the PF
Sep 10, 2024
8b8da79
[TUTO] Added data + calib
Sep 10, 2024
4d6d0f7
[DOC] Clean the documentation adding DOXYGEN_SHOULD_SKIP_THIS
Sep 10, 2024
859cac2
[TUTO][DOC] Added a dox file to explain the curve fitting PF tutorial
Sep 10, 2024
a8a9070
Merge branch 'master' into tuto_pf_like_ukf
Sep 10, 2024
d1280ef
[FIX] Fixed multiple definition of vpDisplayFactory::makeDisplayGridH…
Sep 11, 2024
eb76327
[TUTO][FIX] Fix compilation errors when ViSP namespace is activated
Sep 11, 2024
68b5953
[FIX] Fixed typo in vpUniRand::shuffleVector
Sep 11, 2024
dd049ba
Merge with last changes
fspindle Sep 11, 2024
8127f2e
Introduce display factory usage
fspindle Sep 11, 2024
14204e3
Fix typos
fspindle Sep 11, 2024
b90c045
Update change log file with new tutorials
fspindle Sep 11, 2024
3bc7d32
Harmonize copyright headers in tutorial folder
fspindle Sep 11, 2024
5e98ed7
Relax tolerance in particle filter testing
fspindle Sep 11, 2024
d225943
[TUTO][FIX] Fix C++98 related compilation errors + removed unused inc…
Sep 11, 2024
3d01549
Merge branch 'tuto_pf_like_ukf' of github.com:rolalaro/visp into tuto…
Sep 11, 2024
280796f
[FIX] In vpUniRand::shuffleVector, the test on the CXX standard was i…
Sep 11, 2024
8c14616
Fix error: unsupported option '-mfpu=' for target 'arm64-apple-darwin…
fspindle Sep 12, 2024
c1624ea
Relax maxToleratedError for testing under windows
fspindle Sep 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion 3rdparty/simdlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,14 @@ elseif(ARM OR AARCH64)
vp_check_compiler_flag(CXX "-Wno-unused-command-line-argument" HAVE_NO_UNUSED_CMD_LINE_FLAG "${VISP_SOURCE_DIR}/cmake/checks/cpu_warning.cpp")
vp_check_compiler_flag(CXX "-Wno-asm-operand-widths" HAVE_NO_ASM_WIDTHS_FLAG "${VISP_SOURCE_DIR}/cmake/checks/cpu_warning.cpp")
vp_check_compiler_flag(CXX "-Wno-switch" HAVE_NO_SWITCH_FLAG "${VISP_SOURCE_DIR}/cmake/checks/cpu_warning.cpp")

if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm")
set(CXX_NEON_FLAG "-mfpu=neon")
if( NOT ((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER MATCHES "clang")))
set(CXX_NEON_FLAG "-mfpu=neon -mfpu=neon-fp16")
endif()
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(CXX_NEON_FLAG "${CXX_NEON_FLAG} -mfp16-format=ieee")
endif()
else()
set(CXX_NEON_FLAG "")
endif()
Expand Down
6 changes: 6 additions & 0 deletions ChangeLog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ ViSP 3.x.x (Version in development)
https://visp-doc.inria.fr/doxygen/visp-daily/tutorial-hsv-segmentation-pcl.html
. New tutorial: Rendering a 3D scene with Panda3D
https://visp-doc.inria.fr/doxygen/visp-daily/tutorial-panda3d.html
. New tutorial: Using Unscented Kalman Filter to filter your data
https://visp-doc.inria.fr/doxygen/visp-daily/tutorial-ukf.html
. New tutorial: Using Particle Filter to filter your data
https://visp-doc.inria.fr/doxygen/visp-daily/tutorial-pf.html
. New tutorial: Using Particle Filter to model a wire using polynomial interpolation
https://visp-doc.inria.fr/doxygen/visp-daily/tutorial-pf-curve-fitting.html
- Bug fixed
. [#1251] Bug in vpDisplay::displayFrame()
. [#1270] Build issue around std::clamp and optional header which are not found with cxx17
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/image/tutorial/misc/img-tutorial-pf-run.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
248 changes: 248 additions & 0 deletions doc/tutorial/misc/tutorial-pf-curve-fitting.dox
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
/**
\page tutorial-pf-curve-fitting Tutorial: Using Particle Filter to model a wire using polynomial interpolation
\tableofcontents

\section tuto-pf-cf-intro Introduction

We suppose that you are already familiar with the \ref tutorial-pf.

The Particle Filters (PF) are a set of Monte Carlo algorithms that
permit to approximate solutions for filtering problems even when
the state-space and/or measurement space are non-linear.

In this tutorial, we will use a PF to model a wire using polynomial interpolation . The PF is used to
filter the noisy pixels in a segmented image in order to compute a model of the wire using polynomial interpolation.
The color wire is observed by a static camera, in the following configuration:

\htmlonly <style>div.image img[src="img-tutorial-pf-cf-illustration.jpg"]{width:50%;}</style>
\endhtmlonly
\image html img-tutorial-pf-cf-illustration.jpg

\subsection tuto-pf-cf-intro-methods The maths beyond the Particle Filter

The maths beyond the Particle Filter are explained in the documentation of the vpParticleFilter class.
They are also explained in the \ref tuto-pf-cf-intro-methods .

\section tuto-pf-cf-tutorial Explanations about the tutorial

The tutorial is split in three different programs:
- \ref tutorial-pf-curve-fitting-lms.cpp : this program illustrates how to perform a polynomial interpolation using the
Least-Mean Square method, and the impact of noise on the resulting interpolated model.
- \ref tutorial-pf-curve-fitting-pf.cpp : this program illustrates how to perform a polynomial interpolation using a
Particle Filter.
- \ref tutorial-pf-curve-fitting-all.cpp : this program uses the methods mentionned above to compare their performances.

\subsection tuto-pf-cf-tutorial-howtorun How to run the tutorial

To run one of the tutorials with the default dataset, please run the following commands:

```
$ cd $VISP_WS/visp-build/tutorial/particle-filter-curve-fitting
$ ./tutorial-pf-curve-fitting-{lms, pf, all} --video data/color_image_0%03d.png
```

To see the arguments the program can take, please run:

```
$ cd $VISP_WS/visp-build/tutorial/particle-filter-curve-fitting
$ ./tutorial-pf-curve-fitting-{lms, pf, all} -h
```

You should see something similar to the following image:

\htmlonly <style>div.image img[src="img-tutorial-pf-cf-helper"]{width:50%;}</style>
\endhtmlonly
\image html img-tutorial-pf-cf-helper.jpg "Screenshot of the tutorial Graphical User Interface"

For the tutorial-pf-curve-fitting-pf.cpp and tutorial-pf-curve-fitting-all.cpp tutorials, the PF must
be initialized. You are asked if you would rather use a manual initialization (left click) or an automatic one (right click).

\htmlonly <style>div.image img[src="img-tutorial-pf-cf-init"]{width:50%;}</style>
\endhtmlonly
\image html img-tutorial-pf-cf-init.jpg "Screenshot of the tutorial initialization step"

Then, for all the tutorials, you can either display the images one-by-one (left click) or automatically switch from an
image to the next one (middle click). You can leave the program whenever you want using a right click.

\htmlonly <style>div.image img[src="img-tutorial-pf-cf-run"]{width:50%;}</style>
\endhtmlonly
\image html img-tutorial-pf-cf-run.jpg "Screenshot of the tutorial during its run step"

\subsection tuto-pf-cf-tutorial-general General explanations about the tutorials

\subsubsection tuto-pf-cf-tutorial-general-segmentation Notes about the segmentation and skeletonization of the image

The segmentation of the image using HSV encoding has been presented in the \ref tutorial-hsv-range-tuner .

A calibration file containing the segmentation parameters for the default sequence can be found in the calib folder.
If you want to use your own sequence, please run the \ref tutorial-hsv-range-tuner.cpp tutorial to extract the
parameters that correspond to your own sequence and edit the file calib/hsv-thresholds.yml .

The skeletonization of the segmented image is not the topic of this tutorial. Thus, we invite the interested readers
to read by themselves the corresponding method in the \ref vpTutoSegmentation.cpp file.

\subsubsection tuto-pf-cf-tutorial-general-PF Explanations about the Particle Filter

The internal state of the PF contains the coefficients of the interpolation polynomial. Be
\f$ v(u) = \sum_{i=0}^N a_i u^i \f$ the interpolation polynomial whose highest degree is N.
The internal state of the PF is of size N + 1 such as:

\f[
\begin{array}{lcl}
\textbf{x}[i] &=& a_i
\end{array}
\f]

The measurement \f$ \textbf{z} \f$ corresponds to the vector of vpImagePoint that forms the skeletonized version of the
segmented image.
Be \f$ u_i \f$ and \f$ v_i \f$ the horizontal and vertical pixel coordinates of the \f$ i^{th} \f$ marker.
The measurement vector can be written as:

\f[
\begin{array}{lcl}
\textbf{z}[i] &=& vpImagePoint(v_i , u_i)
\end{array}
\f]


\subsubsection tuto-pf-cf-tutorial-general-LMS Explanations about the Least-Mean Square method

The Least-Mean Square method is a standard method to solve a polynomial interpolation problem.
The polynomial interpolation problem can be written in matrices form as follow:

\f[
\begin{array}{llcl}
& \textbf{A}\textbf{x} &=& \textbf{b} \\
\iff & \textbf{X} &=& \textbf{A}^+\textbf{b} \\
\end{array}
\f]

where \f$ \textbf{A}^+ \f$ denotes the Moore-Penrose pseudo-inverse of the matrix A, with:

\f[
\begin{array}{lcl}
\textbf{A}[i][j] &=& u_i^j
\end{array}
\\
\begin{array}{lcl}
\textbf{x}[i] &=& a_i
\end{array}
\\
\begin{array}{lcl}
\textbf{b}[i] &=& v_i
\end{array}
\f]

<b>Important note:</b> due to numerical unstability, the pixel coordinates cannot be used directly
in the Least-Mean square method. Indeed, using pixel coordinates leads to having an ill-conditionned
\f$ \textbf{A} \f$ matrix. Consequently, in all the tutorials, the pixel coordinates are normalized
by dividing them by the height and width of the image before running any interpolation.

\subsection tuto-pf-cf-tutorial-explained Detailed explanations about the tutorials

We will now present the different tutorials and explained their important parts.

\subsubsection tuto-pf-cf-tutorial-explained-lms Details on the tutorial-pf-curve-fitting-lms.cpp

This tutorial goal is to show how a Least-Mean Square method can be used to perform polynomial interpolation
and the impact of noise on such technique.

To visualize the accuracy of the method, a vpPlot is instantiated in the following part of the code:

\snippet tutorial-pf-curve-fitting-lms.cpp Init_plot

At each iteration, the new frame is read, then segmented and skeletonized in the following section of code:

\snippet tutorial-pf-curve-fitting-lms.cpp Measurements_extraction

The method addSaltAndPepperNoise permits to add a user-defined percentage of salt-and-pepper noise, to evaluate the
robustness of the method against noise.

The polynomial interpolation is performed in the following section of the code:

\snippet tutorial-pf-curve-fitting-lms.cpp LMS_interpolation

It relies on the following method of the vpTutoMeanSquareFitting class:

\snippet vpTutoMeanSquareFitting.cpp Solve_LMS_system

The matrices that form the system that needs to be solved are filled in the vpTutoParabolaModel class (we remind the
reader that normalization of the pixel coordinates is performed to avoid numerical unstability):

\snippet vpTutoParabolaModel.h Fill_LMS_system

\subsubsection tuto-pf-cf-tutorial-explained-pf Details on the tutorial-pf-curve-fitting-pf.cpp

This tutorial is meant to show how a Particle Filter could be used to model a wire thanks to
polynomial interpolation.

To initialize a Particle Filter, a guess of the initial state must be given to it. The more accurate
is the initial guess, the quicker the PF will converge. The initialization can be done either manually or
automatically thanks to the following piece of code:

\snippet tutorial-pf-curve-fitting-pf.cpp Initialization_function

A Particle Filter needs a function to evaluate the likelihood of a particle. We decided to use a Gaussian-based function
that penalizes particles whose polynomial model has a Root Mean Square Error with regard to the measurement points greater than a given threshold.
To be robust against outliers, we use the Tukey M-estimator. The likelihood function is implemented in a functor
to be able to pass additional information such as the height and width of the input image:

\snippet tutorial-pf-curve-fitting-pf.cpp Likelihood_functor

This likelihood functor compute the residuals using the following evaluation functions:

\snippet tutorial-pf-curve-fitting-pf.cpp Evaluation_functions

A Particle Filter needs to perform a weighted average to compute the filtered state. Performing a weighted average of
the particles polynomial coefficients would not lead to satisfying results, as it is not mathematically correct.
Instead, we decided to generate a given number of "control points" by each particle. The number of control points generated
by a particle is dictated by its associated weight. Then, we compute the polynomial coefficients that best fit all these
control points using a Least-Square minimization technique. The weighted average is performed thanks to the following
functor:

\snippet tutorial-pf-curve-fitting-pf.cpp Average_functor

A Particle Filter needs a process function to project the particles forward in time. For this scenario,
we decided to use the identity, and let the randomness of the Particle Filter manage the potential motion
of the wire.

\snippet tutorial-pf-curve-fitting-pf.cpp Process_function

The initialization parameters of the Particle Filter are defined in the following section of code:

\snippet tutorial-pf-curve-fitting-pf.cpp Constants_for_the_PF

The initialization functions of the Particle Filter are defined in the following section of code:

\snippet tutorial-pf-curve-fitting-pf.cpp Init_functions

The Particle Filter is then constructed thanks to the following lines:

\snippet tutorial-pf-curve-fitting-pf.cpp Init_PF

Finally, the filtering is performed thanks to the following line:

\snippet tutorial-pf-curve-fitting-pf.cpp Perform_filtering

The filtered state is retrieve thanks to the following line:

\snippet tutorial-pf-curve-fitting-pf.cpp Get_filtered_state

\subsubsection tuto-pf-cf-tutorial-explained-all Details on the tutorial-pf-curve-fitting-all.cpp

The \ref tutorial-pf-curve-fitting-all.cpp reuse what has already been presented in the \ref tuto-pf-cf-tutorial-explained-lms
and \ref tuto-pf-cf-tutorial-explained-pf sections.

Its main objective is to compare the time performances and robustness against noise of the two methods.
The ratio of noise can be set using the Command Line Interface using the --noise option. For instance,

\code
$ ./tutorial-pf-curve-fitting-all --video data/color_image_0%03d.png --noise <ratio in the intervall [0.; 1.[>
\endcode

will add 50% of noisy pixels to the skeletonized image.

You can experiment by varying this parameter (and others as well) to see the impact on the different methods.
With 15% noisy pixels and more, the Particle Filter tends to have a greater accuracy than the LMS method, but
it takes more times to run.
*/
Loading
Loading