View Javadoc
1   /*
2    * Copyright (C) 2017 Alberto Irurueta Carro (alberto@irurueta.com)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.irurueta.geometry.refiners;
17  
18  import com.irurueta.geometry.Line2D;
19  import com.irurueta.geometry.Point2D;
20  import com.irurueta.geometry.estimators.LockedException;
21  import com.irurueta.numerical.robust.InliersData;
22  
23  import java.util.BitSet;
24  import java.util.List;
25  
26  /**
27   * Refines a 2D point by taking into account an initial estimation, inlier
28   * samples and their residuals.
29   * This class can be used to find a solution that minimizes error of inliers in
30   * LMSE terms.
31   * Typically, a refiner is used by a robust estimator, however it can also be
32   * useful in some other situations.
33   *
34   * @param <T> an implementation of a 2D point.
35   */
36  public abstract class Point2DRefiner<T extends Point2D> extends SamplesAndInliersDataRefiner<T, Line2D> {
37  
38      /**
39       * Standard deviation used for Levenberg-Marquardt fitting during
40       * refinement.
41       * Returned value gives an indication of how much variance each residual
42       * has.
43       * Typically, this value is related to the threshold used on each robust
44       * estimation, since residuals of found inliers are within the range of
45       * such threshold.
46       */
47      private double refinementStandardDeviation;
48  
49      /**
50       * Constructor.
51       */
52      protected Point2DRefiner() {
53      }
54  
55      /**
56       * Constructor.
57       *
58       * @param initialEstimation           initial estimation to be set.
59       * @param keepCovariance              true if covariance of estimation must be kept after
60       *                                    refinement, false otherwise.
61       * @param inliers                     set indicating which of the provided matches are inliers.
62       * @param residuals                   residuals for matched samples.
63       * @param numInliers                  number of inliers on initial estimation.
64       * @param samples                     collection of samples.
65       * @param refinementStandardDeviation standard deviation used for
66       *                                    Levenberg-Marquardt fitting.
67       */
68      protected Point2DRefiner(
69              final T initialEstimation, final boolean keepCovariance, final BitSet inliers, final double[] residuals,
70              final int numInliers, final List<Line2D> samples, final double refinementStandardDeviation) {
71          super(initialEstimation, keepCovariance, inliers, residuals, numInliers, samples);
72          this.refinementStandardDeviation = refinementStandardDeviation;
73      }
74  
75      /**
76       * Constructor.
77       *
78       * @param initialEstimation           initial estimation to be set.
79       * @param keepCovariance              true if covariance of estimation must be kept after
80       *                                    refinement, false otherwise.
81       * @param inliersData                 inlier data, typically obtained from a robust estimator.
82       * @param samples                     collection of samples.
83       * @param refinementStandardDeviation standard deviation used for
84       *                                    Levenberg-Marquardt fitting.
85       */
86      protected Point2DRefiner(
87              final T initialEstimation, final boolean keepCovariance, final InliersData inliersData,
88              final List<Line2D> samples, final double refinementStandardDeviation) {
89          super(initialEstimation, keepCovariance, inliersData, samples);
90          this.refinementStandardDeviation = refinementStandardDeviation;
91      }
92  
93      /**
94       * Gets standard deviation used for Levenberg-Marquardt fitting during
95       * refinement.
96       * Returned value gives an indication of how much variance each residual
97       * has.
98       * Typically, this value is related to the threshold used on each robust
99       * estimation, since residuals of found inliers are within the range of such
100      * threshold.
101      *
102      * @return standard deviation used for refinement.
103      */
104     public double getRefinementStandardDeviation() {
105         return refinementStandardDeviation;
106     }
107 
108     /**
109      * Sets standard deviation used for Levenberg-Marquardt fitting during
110      * refinement.
111      * Returned value gives an indication of how much variance each residual
112      * has.
113      * Typically, this value is related to the threshold used on each robust
114      * estimation, since residuals of found inliers are within the range of such
115      * threshold.
116      *
117      * @param refinementStandardDeviation standard deviation used for
118      *                                    refinement.
119      * @throws LockedException if estimator is locked.
120      */
121     public void setRefinementStandardDeviation(final double refinementStandardDeviation) throws LockedException {
122         if (isLocked()) {
123             throw new LockedException();
124         }
125         this.refinementStandardDeviation = refinementStandardDeviation;
126     }
127 
128     /**
129      * Computes the residual between a point and a line as their distance.
130      *
131      * @param point a point
132      * @param line  a line.
133      * @return residual (distance between provided point and line).
134      */
135     protected double residual(final Point2D point, final Line2D line) {
136         point.normalize();
137         line.normalize();
138         return Math.abs(line.signedDistance(point));
139     }
140 
141     /**
142      * Computes total residual among all provided inlier samples.
143      *
144      * @param point a point.
145      * @return total residual.
146      */
147     protected double totalResidual(final Point2D point) {
148         var result = 0.0;
149 
150         final var nSamples = inliers.length();
151         for (var i = 0; i < nSamples; i++) {
152             if (inliers.get(i)) {
153                 // sample is inlier
154                 final var line = samples.get(i);
155                 result += residual(point, line);
156             }
157         }
158 
159         return result;
160     }
161 }