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