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 }