View Javadoc
1   /*
2    * Copyright (C) 2015 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.ar.epipolar;
17  
18  import com.irurueta.geometry.CoordinatesType;
19  import com.irurueta.geometry.Point2D;
20  import com.irurueta.geometry.estimators.LockedException;
21  import com.irurueta.geometry.estimators.NotReadyException;
22  
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  /**
27   * Fixes matched pairs of points so that they perfectly follow a given epipolar
28   * geometry.
29   * When matching points typically the matching precision is about 1 pixel,
30   * however this makes that matched points under a given epipolar geometry (i.e.
31   * fundamental or essential matrix), do not lie perfectly on the corresponding
32   * epipolar plane or epipolar liens.
33   * The consequence is that triangularization of these matches will fail or
34   * produce inaccurate results.
35   * By fixing matched points using a corrector following a given epipolar
36   * geometry, this effect is alleviated.
37   * This corrector uses the Gold Standard method, which is more expensive to
38   * compute than the Sampson approximation, but is capable to remove larger
39   * errors assuming their gaussianity. Contrary to the Sampson corrector, the
40   * Gold Standard method might fail in some situations, while in those cases
41   * probably the Sampson corrector produces wrong results without failing.
42   */
43  public class GoldStandardCorrector extends Corrector {
44  
45      /**
46       * Indicates that correction must use Sampson method as a fallback if Gold
47       * Standard correction fails.
48       */
49      public static final boolean DEFAULT_FALLBACK_TO_SAMPSON_ENABLED = true;
50  
51      /**
52       * Indicates whether correction must use Sampson method as a fallback if Gold
53       * Standard correction fails.
54       */
55      private boolean fallbackToSampsonEnabled;
56  
57      /**
58       * Constructor.
59       */
60      public GoldStandardCorrector() {
61          super();
62          fallbackToSampsonEnabled = DEFAULT_FALLBACK_TO_SAMPSON_ENABLED;
63      }
64  
65      /**
66       * Constructor.
67       *
68       * @param fundamentalMatrix fundamental matrix to be set.
69       */
70      public GoldStandardCorrector(final FundamentalMatrix fundamentalMatrix) {
71          super(fundamentalMatrix);
72          fallbackToSampsonEnabled = DEFAULT_FALLBACK_TO_SAMPSON_ENABLED;
73      }
74  
75      /**
76       * Constructor.
77       *
78       * @param leftPoints  points to be corrected on left view.
79       * @param rightPoints points to be corrected on right view.
80       * @throws IllegalArgumentException if provided lists of points don't have
81       *                                  the same size.
82       */
83      public GoldStandardCorrector(final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
84          super(leftPoints, rightPoints);
85          fallbackToSampsonEnabled = DEFAULT_FALLBACK_TO_SAMPSON_ENABLED;
86      }
87  
88      /**
89       * Constructor.
90       *
91       * @param leftPoints        points to be corrected on left view.
92       * @param rightPoints       points to be corrected on right view.
93       * @param fundamentalMatrix fundamental matrix to be set.
94       * @throws IllegalArgumentException if provided lists of points don't have
95       *                                  the same size.
96       */
97      public GoldStandardCorrector(final List<Point2D> leftPoints, final List<Point2D> rightPoints,
98                                   final FundamentalMatrix fundamentalMatrix) {
99          super(leftPoints, rightPoints, fundamentalMatrix);
100         fallbackToSampsonEnabled = DEFAULT_FALLBACK_TO_SAMPSON_ENABLED;
101     }
102 
103     /**
104      * Constructor.
105      *
106      * @param listener listener to handle events generated by this class.
107      */
108     public GoldStandardCorrector(final CorrectorListener listener) {
109         super(listener);
110         fallbackToSampsonEnabled = DEFAULT_FALLBACK_TO_SAMPSON_ENABLED;
111     }
112 
113     /**
114      * Constructor.
115      *
116      * @param fundamentalMatrix fundamental matrix to be set.
117      * @param listener          listener to handle events generated by this class.
118      */
119     public GoldStandardCorrector(final FundamentalMatrix fundamentalMatrix, final CorrectorListener listener) {
120         super(fundamentalMatrix, listener);
121         fallbackToSampsonEnabled = DEFAULT_FALLBACK_TO_SAMPSON_ENABLED;
122     }
123 
124     /**
125      * Constructor.
126      *
127      * @param leftPoints  points to be corrected on left view.
128      * @param rightPoints points to be corrected on right view.
129      * @param listener    listener to handle events generated by this class.
130      * @throws IllegalArgumentException if provided lists of points don't have
131      *                                  the same size.
132      */
133     public GoldStandardCorrector(final List<Point2D> leftPoints, final List<Point2D> rightPoints,
134                                  final CorrectorListener listener) {
135         super(leftPoints, rightPoints, listener);
136         fallbackToSampsonEnabled = DEFAULT_FALLBACK_TO_SAMPSON_ENABLED;
137     }
138 
139     /**
140      * Constructor.
141      *
142      * @param leftPoints        points to be corrected on left view.
143      * @param rightPoints       points to be corrected on right view.
144      * @param fundamentalMatrix fundamental matrix to be set.
145      * @param listener          listener to handle events generated by this class.
146      * @throws IllegalArgumentException if provided lists of points don't have
147      *                                  the same size.
148      */
149     public GoldStandardCorrector(
150             final List<Point2D> leftPoints, final List<Point2D> rightPoints, final FundamentalMatrix fundamentalMatrix,
151             final CorrectorListener listener) {
152         super(leftPoints, rightPoints, fundamentalMatrix, listener);
153         fallbackToSampsonEnabled = DEFAULT_FALLBACK_TO_SAMPSON_ENABLED;
154     }
155 
156     /**
157      * Indicates whether correction must use Sampson method as a fallback if Gold
158      * Standard correction fails.
159      * If true, whenever the correction of a matched pair of points fails,
160      * its correction will be done with Sampson method instead. This allows
161      * to continue correcting all points at the expense of getting worse
162      * results in those points where Gold Standard method failed.
163      * If false, whenever a single pair of matched pair of points fails to
164      * be corrected, the algorithm stops and no points are corrected at all.
165      * By default, fallback is enabled.
166      *
167      * @return true if fallback is enabled, false otherwise.
168      */
169     public boolean isFallbackToSampsonEnabled() {
170         return fallbackToSampsonEnabled;
171     }
172 
173     /**
174      * Sets boolean indicating whether correction must use Sampson
175      * method as a fallback if Gold Standard correction fails.
176      * If true, whenever the correction of a matched pair of points fails,
177      * its correction will be done with Sampson method instead. This allows
178      * to continue correcting all points at the expense of getting worse
179      * results in those points where Gold Standard method failed.
180      * If false, whenever a single pair of matched pair of points fails to
181      * be corrected, the algorithm stops and no points are corrected at all.
182      * By default, fallback is enabled.
183      *
184      * @param fallback true to enable fallback, false otherwise.
185      * @throws LockedException if this instance is locked doing computations.
186      */
187     public void setFallbackToSampsonEnabled(final boolean fallback) throws LockedException {
188         if (isLocked()) {
189             throw new LockedException();
190         }
191 
192         fallbackToSampsonEnabled = fallback;
193     }
194 
195     /**
196      * Corrects the lists of provided matched points to be corrected.
197      *
198      * @throws NotReadyException   if this instance is not ready (either points or
199      *                             fundamental matrix has not been provided yet).
200      * @throws LockedException     if this instance is locked doing computations.
201      * @throws CorrectionException if correction fails.
202      */
203     @SuppressWarnings("DuplicatedCode")
204     @Override
205     public void correct() throws NotReadyException, LockedException, CorrectionException {
206         if (isLocked()) {
207             throw new LockedException();
208         }
209         if (!isReady()) {
210             throw new NotReadyException();
211         }
212 
213         locked = true;
214 
215         if (listener != null) {
216             listener.onCorrectStart(this);
217         }
218 
219         leftCorrectedPoints = new ArrayList<>();
220         rightCorrectedPoints = new ArrayList<>();
221 
222         final var size = leftPoints.size();
223         float progress;
224         var previousProgress = 0.0f;
225         for (var i = 0; i < size; i++) {
226             final var leftPoint = leftPoints.get(i);
227             final var rightPoint = rightPoints.get(i);
228 
229             final var leftCorrectedPoint = Point2D.create(CoordinatesType.HOMOGENEOUS_COORDINATES);
230             final var rightCorrectedPoint = Point2D.create(CoordinatesType.HOMOGENEOUS_COORDINATES);
231 
232             // correct single pair
233             try {
234                 GoldStandardSingleCorrector.correct(leftPoint, rightPoint, fundamentalMatrix, leftCorrectedPoint,
235                         rightCorrectedPoint);
236             } catch (final CorrectionException e) {
237                 if (fallbackToSampsonEnabled) {
238                     // try using Sampson method instead
239                     SampsonSingleCorrector.correct(leftPoint, rightPoint, fundamentalMatrix, leftCorrectedPoint,
240                             rightCorrectedPoint);
241                 } else {
242                     // let algorithm fail
243                     throw e;
244                 }
245             }
246 
247             leftCorrectedPoints.add(leftCorrectedPoint);
248             rightCorrectedPoints.add(rightCorrectedPoint);
249 
250             if (listener != null) {
251                 progress = i / (float) size;
252                 if (progress - previousProgress > progressDelta) {
253                     // progress has changed significantly
254                     previousProgress = progress;
255                     listener.onCorrectProgressChange(this, progress);
256                 }
257             }
258         }
259 
260         if (listener != null) {
261             listener.onCorrectEnd(this);
262         }
263 
264         locked = false;
265     }
266 
267     /**
268      * Gets type of correction being used.
269      *
270      * @return type of correction.
271      */
272     @Override
273     public CorrectorType getType() {
274         return CorrectorType.GOLD_STANDARD;
275     }
276 }