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.geometry.estimators;
17  
18  import com.irurueta.geometry.AffineTransformation2D;
19  import com.irurueta.geometry.Point2D;
20  import com.irurueta.geometry.refiners.PointCorrespondenceAffineTransformation2DRefiner;
21  import com.irurueta.numerical.robust.RobustEstimatorMethod;
22  
23  import java.util.List;
24  
25  /**
26   * This is an abstract class for algorithms to robustly find the best affine
27   * 2D transformation for collections of matching 2D points.
28   * Implementations of this class should be able to detect and discard outliers
29   * in order to find the best solution.
30   */
31  public abstract class PointCorrespondenceAffineTransformation2DRobustEstimator
32          extends AffineTransformation2DRobustEstimator {
33  
34      /**
35       * Default robust estimator method when none is provided.
36       */
37      public static final RobustEstimatorMethod DEFAULT_ROBUST_METHOD = RobustEstimatorMethod.PROMEDS;
38  
39      /**
40       * List of points to be used to estimate an affine 2D transformation.
41       * Each point in the list of input points must be matched with the
42       * corresponding point in the list of output points located at the same
43       * position. Hence, both input points and output points must have the same
44       * size, and their size must be greater or equal than MINIMUM_SIZE.
45       */
46      protected List<Point2D> inputPoints;
47  
48      /**
49       * List of points to be used to estimate an affine 2D transformation.
50       * Each point in the list of output points must be matched with the
51       * corresponding point in the list of input points located at the same
52       * position. Hence, both input points and output points must have the same
53       * size, and their size must be greater or equal than MINIMUM_SIZE.
54       */
55      protected List<Point2D> outputPoints;
56  
57      /**
58       * Constructor.
59       */
60      protected PointCorrespondenceAffineTransformation2DRobustEstimator() {
61          super();
62      }
63  
64      /**
65       * Constructor with lists of points to be used to estimate an affine 2D
66       * transformation.
67       * Points in the list located at the same position are considered to be
68       * matched. Hence, both lists must have the same size, and their size must
69       * be greater or equal than MINIMUM_SIZE.
70       *
71       * @param inputPoints  list of input points to be used to estimate an
72       *                     affine 2D transformation.
73       * @param outputPoints list of output points to be used to estimate an
74       *                     affine 2D transformation.
75       * @throws IllegalArgumentException if provided lists of points don't have
76       *                                  the same size or their size is smaller than MINIMUM_SIZE.
77       */
78      protected PointCorrespondenceAffineTransformation2DRobustEstimator(
79              final List<Point2D> inputPoints, final List<Point2D> outputPoints) {
80          super();
81          internalSetPoints(inputPoints, outputPoints);
82      }
83  
84      /**
85       * Constructor.
86       *
87       * @param listener listener to be notified of events such as when estimation
88       *                 starts, ends or its progress significantly changes.
89       */
90      protected PointCorrespondenceAffineTransformation2DRobustEstimator(
91              final AffineTransformation2DRobustEstimatorListener listener) {
92          super(listener);
93      }
94  
95      /**
96       * Constructor with listener and lists of points to be used to estimate an
97       * affine 2D transformation.
98       * Points in the list located at the same position are considered to be
99       * matched. Hence, both lists must have the same size, and their size must
100      * be greater or equal than MINIMUM_SIZE.
101      *
102      * @param listener     listener to be notified of events such as when estimation
103      *                     starts, ends or its progress significantly changes.
104      * @param inputPoints  list of input points to be used to estimate an
105      *                     affine 2D transformation.
106      * @param outputPoints list of output points to be used to estimate an
107      *                     affine 2D transformation.
108      * @throws IllegalArgumentException if provided lists of points don't have
109      *                                  the same size or their size is smaller than MINIMUM_SIZE.
110      */
111     protected PointCorrespondenceAffineTransformation2DRobustEstimator(
112             final AffineTransformation2DRobustEstimatorListener listener,
113             final List<Point2D> inputPoints, final List<Point2D> outputPoints) {
114         super(listener);
115         internalSetPoints(inputPoints, outputPoints);
116     }
117 
118     /**
119      * Returns list of input points to be used to estimate an affine 2D
120      * transformation.
121      * Each point in the list of input points must be matched with the
122      * corresponding point in the list of output points located at the same
123      * position. Hence, both input points and output points must have the same
124      * size, and their size must be greater or equal than MINIMUM_SIZE.
125      *
126      * @return list of input points to be used to estimate an affine 2D
127      * transformation.
128      */
129     public List<Point2D> getInputPoints() {
130         return inputPoints;
131     }
132 
133     /**
134      * Returns list of output points to be used to estimate an affine 2D
135      * transformation.
136      * Each point in the list of output points must be matched with the
137      * corresponding point in the list of input points located at the same
138      * position. Hence, both input points and output points must have the same
139      * size, and their size must be greater or equal than MINIMUM_SIZE.
140      *
141      * @return list of output points to be used to estimate an affine 2D
142      * transformation.
143      */
144     public List<Point2D> getOutputPoints() {
145         return outputPoints;
146     }
147 
148     /**
149      * Sets lists of points to be used to estimate an affine 2D transformation.
150      * Points in the list located at the same position are considered to be
151      * matched. Hence, both lists must have the same size, and their size must
152      * be greater or equal than MINIMUM_SIZE.
153      *
154      * @param inputPoints  list of input points to be used to estimate an
155      *                     affine 2D transformation.
156      * @param outputPoints list of output points to be used to estimate an
157      *                     affine 2D transformation.
158      * @throws IllegalArgumentException if provided lists of points don't have
159      *                                  the same size or their size is smaller than MINIMUM_SIZE.
160      * @throws LockedException          if estimator is locked because a computation is
161      *                                  already in progress.
162      */
163     public final void setPoints(final List<Point2D> inputPoints, final List<Point2D> outputPoints)
164             throws LockedException {
165         if (isLocked()) {
166             throw new LockedException();
167         }
168         internalSetPoints(inputPoints, outputPoints);
169     }
170 
171     /**
172      * Indicates if estimator is ready to start the affine 2D transformation
173      * estimation.
174      * This is true when input data (i.e. lists of matched points) are provided
175      * and a minimum of MINIMUM_SIZE points are available.
176      *
177      * @return true if estimator is ready, false otherwise.
178      */
179     public boolean isReady() {
180         return inputPoints != null && outputPoints != null && inputPoints.size() == outputPoints.size()
181                 && inputPoints.size() >= MINIMUM_SIZE;
182     }
183 
184     /**
185      * Returns quality scores corresponding to each pair of matched points.
186      * The larger the score value the better the quality of the matching.
187      * This implementation always returns null.
188      * Subclasses using quality scores must implement proper behaviour.
189      *
190      * @return quality scores corresponding to each pair of matched points.
191      */
192     public double[] getQualityScores() {
193         return null;
194     }
195 
196     /**
197      * Sets quality scores corresponding to each pair of matched points.
198      * The larger the score value the better the quality of the matching.
199      * This implementation makes no action.
200      * Subclasses using quality scores must implement proper behaviour.
201      *
202      * @param qualityScores quality scores corresponding to each pair of matched
203      *                      points.
204      * @throws LockedException          if robust estimator is locked because an
205      *                                  estimation is already in progress.
206      * @throws IllegalArgumentException if provided quality scores length is
207      *                                  smaller than MINIMUM_SIZE (i.e. 3 samples).
208      */
209     public void setQualityScores(final double[] qualityScores) throws LockedException {
210     }
211 
212     /**
213      * Creates an affine 2D transformation estimator based on 2D point
214      * correspondences and using provided robust estimator method.
215      *
216      * @param method method of a robust estimator algorithm to estimate
217      *               the best affine 2D transformation.
218      * @return an instance of affine 2D transformation estimator.
219      */
220     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(final RobustEstimatorMethod method) {
221         return switch (method) {
222             case LMEDS -> new LMedSPointCorrespondenceAffineTransformation2DRobustEstimator();
223             case MSAC -> new MSACPointCorrespondenceAffineTransformation2DRobustEstimator();
224             case PROSAC -> new PROSACPointCorrespondenceAffineTransformation2DRobustEstimator();
225             case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation2DRobustEstimator();
226             default -> new RANSACPointCorrespondenceAffineTransformation2DRobustEstimator();
227         };
228     }
229 
230     /**
231      * Creates an affine 2D transformation estimator based on 2D point
232      * correspondences and using provided robust estimator method.
233      *
234      * @param inputPoints  list of input points to be used to estimate an
235      *                     affine 2D transformation.
236      * @param outputPoints list of output points to be used to estimate an
237      *                     affine 2D transformation.
238      * @param method       method of a robust estimator algorithm to estimate
239      *                     the best affine 2D transformation.
240      * @return an instance of affine 2D transformation estimator.
241      * @throws IllegalArgumentException if provided lists of points don't have
242      *                                  the same size or their size is smaller than MINIMUM_SIZE.
243      */
244     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
245             final List<Point2D> inputPoints, final List<Point2D> outputPoints, final RobustEstimatorMethod method) {
246         return switch (method) {
247             case LMEDS -> new LMedSPointCorrespondenceAffineTransformation2DRobustEstimator(inputPoints, outputPoints);
248             case MSAC -> new MSACPointCorrespondenceAffineTransformation2DRobustEstimator(inputPoints, outputPoints);
249             case PROSAC -> new PROSACPointCorrespondenceAffineTransformation2DRobustEstimator(
250                     inputPoints, outputPoints);
251             case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation2DRobustEstimator(
252                     inputPoints, outputPoints);
253             default -> new RANSACPointCorrespondenceAffineTransformation2DRobustEstimator(inputPoints, outputPoints);
254         };
255     }
256 
257     /**
258      * Creates an affine 2D transformation estimator based on 2D point
259      * correspondences and using provided robust estimator method.
260      *
261      * @param listener listener to be notified of events such as when estimation
262      *                 starts, ends or its progress significantly changes.
263      * @param method   method of a robust estimator algorithm to estimate
264      *                 the best affine 2D transformation.
265      * @return an instance of affine 2D transformation estimator.
266      */
267     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
268             final AffineTransformation2DRobustEstimatorListener listener, final RobustEstimatorMethod method) {
269         return switch (method) {
270             case LMEDS -> new LMedSPointCorrespondenceAffineTransformation2DRobustEstimator(listener);
271             case MSAC -> new MSACPointCorrespondenceAffineTransformation2DRobustEstimator(listener);
272             case PROSAC -> new PROSACPointCorrespondenceAffineTransformation2DRobustEstimator(listener);
273             case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation2DRobustEstimator(listener);
274             default -> new RANSACPointCorrespondenceAffineTransformation2DRobustEstimator(listener);
275         };
276     }
277 
278     /**
279      * Creates an affine 2D transformation estimator based on 2D point
280      * correspondences and using provided robust estimator method.
281      *
282      * @param listener     listener to be notified of events such as when estimation
283      *                     starts, ends or its progress significantly changes.
284      * @param inputPoints  list of input points to be used to estimate an
285      *                     affine 2D transformation.
286      * @param outputPoints list of output points to be used to estimate an
287      *                     affine 2D transformation.
288      * @param method       method of a robust estimator algorithm to estimate
289      *                     the best affine 2D transformation.
290      * @return an instance of affine 2D transformation estimator.
291      * @throws IllegalArgumentException if provided lists of points don't have
292      *                                  the same size or their size is smaller than MINIMUM_SIZE.
293      */
294     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
295             final AffineTransformation2DRobustEstimatorListener listener, final List<Point2D> inputPoints,
296             final List<Point2D> outputPoints, final RobustEstimatorMethod method) {
297         return switch (method) {
298             case LMEDS -> new LMedSPointCorrespondenceAffineTransformation2DRobustEstimator(
299                     listener, inputPoints, outputPoints);
300             case MSAC -> new MSACPointCorrespondenceAffineTransformation2DRobustEstimator(
301                     listener, inputPoints, outputPoints);
302             case PROSAC -> new PROSACPointCorrespondenceAffineTransformation2DRobustEstimator(
303                     listener, inputPoints, outputPoints);
304             case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation2DRobustEstimator(
305                     listener, inputPoints, outputPoints);
306             default -> new RANSACPointCorrespondenceAffineTransformation2DRobustEstimator(
307                     listener, inputPoints, outputPoints);
308         };
309     }
310 
311     /**
312      * Creates an affine 2D transformation estimator based on 2D point
313      * correspondences and using provided robust estimator method.
314      *
315      * @param qualityScores quality scores corresponding to each pair of matched
316      *                      points.
317      * @param method        method of a robust estimator algorithm to estimate
318      *                      the best affine 2D transformation.
319      * @return an instance of affine 2D transformation estimator.
320      * @throws IllegalArgumentException if provided quality scores length is
321      *                                  smaller than MINIMUM_SIZE (i.e. 3 matched points).
322      */
323     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
324             final double[] qualityScores, final RobustEstimatorMethod method) {
325         return switch (method) {
326             case LMEDS -> new LMedSPointCorrespondenceAffineTransformation2DRobustEstimator();
327             case MSAC -> new MSACPointCorrespondenceAffineTransformation2DRobustEstimator();
328             case PROSAC -> new PROSACPointCorrespondenceAffineTransformation2DRobustEstimator(qualityScores);
329             case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation2DRobustEstimator(qualityScores);
330             default -> new RANSACPointCorrespondenceAffineTransformation2DRobustEstimator();
331         };
332     }
333 
334     /**
335      * Creates an affine 2D transformation estimator based on 2D point
336      * correspondences and using provided robust estimator method.
337      *
338      * @param inputPoints   list of input points to be used to estimate an
339      *                      affine 2D transformation.
340      * @param outputPoints  list of output points to be used to estimate an
341      *                      affine 2D transformation.
342      * @param qualityScores quality scores corresponding to each pair of matched
343      *                      points.
344      * @param method        method of a robust estimator algorithm to estimate
345      *                      the best affine 2D transformation.
346      * @return an instance of affine 2D transformation estimator.
347      * @throws IllegalArgumentException if provided lists of points or quality
348      *                                  scores don't have the same size or their size is smaller than
349      *                                  MINIMUM_SIZE.
350      */
351     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
352             final List<Point2D> inputPoints, final List<Point2D> outputPoints, final double[] qualityScores,
353             final RobustEstimatorMethod method) {
354         return switch (method) {
355             case LMEDS -> new LMedSPointCorrespondenceAffineTransformation2DRobustEstimator(inputPoints, outputPoints);
356             case MSAC -> new MSACPointCorrespondenceAffineTransformation2DRobustEstimator(inputPoints, outputPoints);
357             case PROSAC -> new PROSACPointCorrespondenceAffineTransformation2DRobustEstimator(
358                     inputPoints, outputPoints, qualityScores);
359             case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation2DRobustEstimator(
360                     inputPoints, outputPoints, qualityScores);
361             default -> new RANSACPointCorrespondenceAffineTransformation2DRobustEstimator(inputPoints, outputPoints);
362         };
363     }
364 
365     /**
366      * Creates an affine 2D transformation estimator based on 2D point
367      * correspondences and using provided robust estimator method.
368      *
369      * @param listener      listener to be notified of events such as when estimation
370      *                      starts, ends or its progress significantly changes.
371      * @param qualityScores quality scores corresponding to each pair of matched
372      *                      points.
373      * @param method        method of a robust estimator algorithm to estimate
374      *                      the best affine 2D transformation.
375      * @return an instance of affine 2D transformation estimator.
376      * @throws IllegalArgumentException if provided quality scores don't have
377      *                                  the required minimum size.
378      */
379     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
380             final AffineTransformation2DRobustEstimatorListener listener, final double[] qualityScores,
381             final RobustEstimatorMethod method) {
382         return switch (method) {
383             case LMEDS -> new LMedSPointCorrespondenceAffineTransformation2DRobustEstimator(listener);
384             case MSAC -> new MSACPointCorrespondenceAffineTransformation2DRobustEstimator(listener);
385             case PROSAC -> new PROSACPointCorrespondenceAffineTransformation2DRobustEstimator(listener, qualityScores);
386             case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation2DRobustEstimator(
387                     listener, qualityScores);
388             default -> new RANSACPointCorrespondenceAffineTransformation2DRobustEstimator(listener);
389         };
390     }
391 
392     /**
393      * Creates an affine 2D transformation estimator based on 2D point
394      * correspondences and using provided robust estimator method.
395      *
396      * @param listener      listener to be notified of events such as when estimation
397      *                      starts, ends or its progress significantly changes.
398      * @param inputPoints   list of input points to be used to estimate an
399      *                      affine 2D transformation.
400      * @param outputPoints  list of output points to be used to estimate an
401      *                      affine 2D transformation.
402      * @param qualityScores quality scores corresponding to each pair of matched
403      *                      points.
404      * @param method        method of a robust estimator algorithm to estimate
405      *                      the best affine 2D transformation.
406      * @return an instance of affine 2D transformation estimator.
407      * @throws IllegalArgumentException if provided lists of points don't have
408      *                                  the same size or their size is smaller than MINIMUM_SIZE.
409      */
410     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
411             final AffineTransformation2DRobustEstimatorListener listener, final List<Point2D> inputPoints,
412             final List<Point2D> outputPoints, final double[] qualityScores, final RobustEstimatorMethod method) {
413         return switch (method) {
414             case LMEDS -> new LMedSPointCorrespondenceAffineTransformation2DRobustEstimator(
415                     listener, inputPoints, outputPoints);
416             case MSAC -> new MSACPointCorrespondenceAffineTransformation2DRobustEstimator(
417                     listener, inputPoints, outputPoints);
418             case PROSAC -> new PROSACPointCorrespondenceAffineTransformation2DRobustEstimator(
419                     listener, inputPoints, outputPoints, qualityScores);
420             case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation2DRobustEstimator(
421                     listener, inputPoints, outputPoints, qualityScores);
422             default -> new RANSACPointCorrespondenceAffineTransformation2DRobustEstimator(
423                     listener, inputPoints, outputPoints);
424         };
425     }
426 
427     /**
428      * Creates an affine 2D transformation estimator based on 2D point
429      * correspondences and using default robust estimator method.
430      *
431      * @return an instance of affine 2D transformation estimator.
432      */
433     public static PointCorrespondenceAffineTransformation2DRobustEstimator create() {
434         return create(DEFAULT_ROBUST_METHOD);
435     }
436 
437     /**
438      * Creates an affine 2D transformation estimator based on 2D point
439      * correspondences and using default robust estimator method.
440      *
441      * @param inputPoints  list of input points to be used to estimate an
442      *                     affine 2D transformation.
443      * @param outputPoints list of output points to be used to estimate an
444      *                     affine 2D transformation.
445      * @return an instance of affine 2D transformation estimator.
446      * @throws IllegalArgumentException if provided lists of points don't have
447      *                                  the same size or their size is smaller than MINIMUM_SIZE.
448      */
449     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
450             final List<Point2D> inputPoints, final List<Point2D> outputPoints) {
451         return create(inputPoints, outputPoints, DEFAULT_ROBUST_METHOD);
452     }
453 
454     /**
455      * Creates an affine 2D transformation estimator based on 2D point
456      * correspondences and using default robust estimator method.
457      *
458      * @param listener listener to be notified of events such as when estimation
459      *                 starts, ends or its progress significantly changes.
460      * @return an instance of affine 2D transformation estimator.
461      */
462     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
463             final AffineTransformation2DRobustEstimatorListener listener) {
464         return create(listener, DEFAULT_ROBUST_METHOD);
465     }
466 
467     /**
468      * Creates an affine 2D transformation estimator based on 2D point
469      * correspondences and using default robust estimator method.
470      *
471      * @param listener     listener to be notified of events such as when estimation
472      *                     starts, ends or its progress significantly changes.
473      * @param inputPoints  list of input points to be used to estimate an
474      *                     affine 2D transformation.
475      * @param outputPoints list of output points to be used to estimate an
476      *                     affine 2D transformation.
477      * @return an instance of affine 2D transformation estimator.
478      * @throws IllegalArgumentException if provided lists of points don't have
479      *                                  the same size or their size is smaller than MINIMUM_SIZE.
480      */
481     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
482             final AffineTransformation2DRobustEstimatorListener listener,
483             final List<Point2D> inputPoints, final List<Point2D> outputPoints) {
484         return create(listener, inputPoints, outputPoints, DEFAULT_ROBUST_METHOD);
485     }
486 
487     /**
488      * Creates an affine 2D transformation estimator based on 2D point
489      * correspondences and using default robust estimator method.
490      *
491      * @param qualityScores quality scores corresponding to each pair of matched
492      *                      points.
493      * @return an instance of affine 2D transformation estimator.
494      */
495     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(final double[] qualityScores) {
496         return create(qualityScores, DEFAULT_ROBUST_METHOD);
497     }
498 
499     /**
500      * Creates an affine 2D transformation estimator based on 2D point
501      * correspondences and using default robust estimator method.
502      *
503      * @param inputPoints   list of input points to be used to estimate an
504      *                      affine 2D transformation.
505      * @param outputPoints  list of output points to be used to estimate an
506      *                      affine 2D transformation.
507      * @param qualityScores quality scores corresponding to each pair of matched
508      *                      points.
509      * @return an instance of affine 2D transformation estimator.
510      * @throws IllegalArgumentException if provided lists of points don't have
511      *                                  the same size or their size is smaller than MINIMUM_SIZE.
512      */
513     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
514             final List<Point2D> inputPoints, final List<Point2D> outputPoints, final double[] qualityScores) {
515         return create(inputPoints, outputPoints, qualityScores, DEFAULT_ROBUST_METHOD);
516     }
517 
518     /**
519      * Creates an affine 2D transformation estimator based on 2D point
520      * correspondences and using default robust estimator method.
521      *
522      * @param listener      listener to be notified of events such as when estimation
523      *                      starts, ends or its progress significantly changes.
524      * @param qualityScores quality scores corresponding to each pair of matched
525      *                      points.
526      * @return an instance of affine 2D transformation estimator.
527      */
528     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
529             final AffineTransformation2DRobustEstimatorListener listener, final double[] qualityScores) {
530         return create(listener, qualityScores, DEFAULT_ROBUST_METHOD);
531     }
532 
533     /**
534      * Creates an affine 2D transformation estimator based on 2D point
535      * correspondences and using default robust estimator method.
536      *
537      * @param listener      listener to be notified of events such as when estimation
538      *                      starts, ends or its progress significantly changes.
539      * @param inputPoints   list of input points to be used to estimate an
540      *                      affine 2D transformation.
541      * @param outputPoints  list of output points to be used to estimate an
542      *                      affine 2D transformation.
543      * @param qualityScores quality scores corresponding to each pair of matched
544      *                      points.
545      * @return an instance of affine 2D transformation estimator.
546      * @throws IllegalArgumentException if provided lists of points don't have
547      *                                  the same size or their size is smaller than MINIMUM_SIZE.
548      */
549     public static PointCorrespondenceAffineTransformation2DRobustEstimator create(
550             final AffineTransformation2DRobustEstimatorListener listener,
551             final List<Point2D> inputPoints, final List<Point2D> outputPoints, final double[] qualityScores) {
552         return create(listener, inputPoints, outputPoints, qualityScores, DEFAULT_ROBUST_METHOD);
553     }
554 
555     /**
556      * Attempts to refine provided solution if refinement is requested.
557      * This method returns a refined solution of the same provided solution
558      * if refinement is not requested or has failed.
559      * If refinement is enabled, and it is requested to keep covariance, this
560      * method will also keep covariance of refined transformation.
561      *
562      * @param transformation transformation estimated by a robust estimator
563      *                       without refinement.
564      * @return solution after refinement (if requested) or the provided
565      * non-refined solution if not requested or refinement failed.
566      */
567     @SuppressWarnings("DuplicatedCode")
568     protected AffineTransformation2D attemptRefine(final AffineTransformation2D transformation) {
569         if (refineResult) {
570             final var refiner = new PointCorrespondenceAffineTransformation2DRefiner(transformation, keepCovariance,
571                     getInliersData(), inputPoints, outputPoints, getRefinementStandardDeviation());
572 
573             try {
574                 final var result = new AffineTransformation2D();
575                 final var improved = refiner.refine(result);
576 
577                 if (keepCovariance) {
578                     // keep covariance
579                     covariance = refiner.getCovariance();
580                 }
581 
582                 return improved ? result : transformation;
583             } catch (final Exception e) {
584                 // refinement failed, so we return input value
585                 return transformation;
586             }
587         } else {
588             return transformation;
589         }
590     }
591 
592     /**
593      * Internal method to set lists of points to be used to estimate an affine
594      * 2D transformation.
595      * This method does not check whether estimator is locked or not.
596      *
597      * @param inputPoints  list of input points to be used to estimate an
598      *                     affine 2D transformation.
599      * @param outputPoints list of output points to be used to estimate an
600      *                     affine 2D transformation.
601      * @throws IllegalArgumentException if provided lists of points don't have
602      *                                  the same size or their size is smaller than MINIMUM_SIZE.
603      */
604     private void internalSetPoints(final List<Point2D> inputPoints, final List<Point2D> outputPoints) {
605         if (inputPoints.size() < MINIMUM_SIZE) {
606             throw new IllegalArgumentException();
607         }
608         if (inputPoints.size() != outputPoints.size()) {
609             throw new IllegalArgumentException();
610         }
611         this.inputPoints = inputPoints;
612         this.outputPoints = outputPoints;
613     }
614 }