sample_consensus/lib.rs
1#![no_std]
2
3/// A model is a best-fit of at least some of the underlying data. You can compute residuals in respect to the model.
4pub trait Model<Data> {
5 /// Note that the residual error is returned as a 64-bit float. This allows the residual to be used for things
6 /// other than sample consensus, such as optimization problems. For sample consensus, the residual should
7 /// only be used to ensure it is within a threshold that roughly distinguishes inliers from outliers.
8 ///
9 /// The returned residual should always be positive, with a lower residual being associated with higher
10 /// probability of being an inlier rather than an outlier.
11 fn residual(&self, data: &Data) -> f64;
12}
13
14/// An `Estimator` is able to create a model that best fits a set of data.
15/// It is also able to determine the residual error each data point contributes in relation to the model.
16pub trait Estimator<Data> {
17 /// `Model` is the model which is estimated from the underlying data
18 type Model: Model<Data>;
19 /// Iterator over the models produced from the data.
20 type ModelIter: IntoIterator<Item = Self::Model>;
21
22 /// The minimum number of samples that the estimator can estimate a model from.
23 const MIN_SAMPLES: usize;
24
25 /// Takes in an iterator over the data and produces a model that best fits the data.
26 ///
27 /// This must be passed at least `Self::MIN_SAMPLES` data points, otherwise `estimate` should panic
28 /// to indicate a developer error.
29 ///
30 /// `None` should be returned only if a model is impossible to estimate based on the data.
31 /// For instance, if a particle has greater than infinite mass, a point is detected behind a camera,
32 /// an equation has an imaginary answer, or non-causal events happen, then a model may not be produced.
33 fn estimate<I>(&self, data: I) -> Self::ModelIter
34 where
35 I: Iterator<Item = Data> + Clone;
36}
37
38/// A consensus algorithm extracts a consensus from an underlying model of data.
39/// This consensus includes a model of the data and which datapoints fit the model.
40///
41/// Note that all the consensus methods take a `&mut self`. This allows the consensus to store
42/// state such as an RNG or pre-allocated memory. This means multiple threads will be forced
43/// to create their own `Consensus` instance, which is most efficient.
44pub trait Consensus<E, Data>
45where
46 E: Estimator<Data>,
47{
48 /// Iterator over the indices of the inliers in the clonable iterator.
49 type Inliers: IntoIterator<Item = usize>;
50
51 /// Takes a slice over the data and an estimator instance.
52 /// It returns `None` if no valid model could be found for the data and
53 /// `Some` if a model was found.
54 ///
55 /// Make sure to shuffle your `data` before calling this. You can use
56 /// [`SliceRandom::shuffle`](https://docs.rs/rand/0.8.4/rand/seq/trait.SliceRandom.html#tymethod.shuffle).
57 fn model<I>(&mut self, estimator: &E, data: I) -> Option<E::Model>
58 where
59 I: Iterator<Item = Data> + Clone;
60
61 /// Takes a slice over the data and an estimator instance.
62 /// It returns `None` if no valid model could be found for the data and
63 /// `Some` if a model was found. It includes the inliers consistent with the model.
64 ///
65 /// Make sure to shuffle your `data` before calling this. You can use
66 /// [`SliceRandom::shuffle`](https://docs.rs/rand/0.8.4/rand/seq/trait.SliceRandom.html#tymethod.shuffle).
67 fn model_inliers<I>(&mut self, estimator: &E, data: I) -> Option<(E::Model, Self::Inliers)>
68 where
69 I: Iterator<Item = Data> + Clone;
70}
71
72/// See [`Consensus`]. A multi-consensus can handle situations where different subsets of the data are consistent
73/// with different models. This kind of consensus also considers whether a point is part of another orthogonal
74/// model that is known before assuming it is a true outlier. In this situation there are inliers of different
75/// models and then true outliers that are actual erroneous data that should be filtered out.
76pub trait MultiConsensus<E, Data>
77where
78 E: Estimator<Data>,
79{
80 /// Iterator over the indices of the inliers in the clonable iterator.
81 type Inliers: IntoIterator<Item = usize>;
82 type Models: IntoIterator<Item = (E::Model, Self::Inliers)>;
83
84 /// Takes a slice over the data and an estimator instance.
85 /// It returns an iterator over all of the models and all of the inliers
86 /// that are consistent with that model. Every point that is not an
87 /// inlier of a given model is considered an outlier of that model.
88 ///
89 /// Make sure to shuffle your `data` before calling this. You can use
90 /// [`SliceRandom::shuffle`](https://docs.rs/rand/0.8.4/rand/seq/trait.SliceRandom.html#tymethod.shuffle).
91 fn models<I>(&mut self, estimator: &E, data: I) -> Self::Models
92 where
93 I: Iterator<Item = Data> + Clone;
94}