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.Plane;
19  import com.irurueta.geometry.ProjectiveTransformation3D;
20  import com.irurueta.geometry.refiners.PlaneCorrespondenceProjectiveTransformation3DRefiner;
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 collections of matching planes.
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 PlaneCorrespondenceProjectiveTransformation3DRobustEstimator
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 planes to be used to estimate a projective 3D transformation.
41       * Each line in the list of input lines must be matched with the
42       * corresponding line in the list of output lines located at the same
43       * position. Hence, both input lines and output lines must have the
44       * same size, and their size must be greater or equal than MINIMUM_SIZE.
45       */
46      protected List<Plane> inputPlanes;
47  
48      /**
49       * List of planes to be used to estimate a projective 3D transformation.
50       * Each point in the list of output lines must be matched with the
51       * corresponding line in the list of input lines located at the same
52       * position. Hence, both input lines and output lines must have the
53       * same size, and their size must be greater or equal than MINIMUM_SIZE.
54       */
55      protected List<Plane> outputPlanes;
56  
57      /**
58       * Constructor.
59       */
60      protected PlaneCorrespondenceProjectiveTransformation3DRobustEstimator() {
61          super();
62      }
63  
64      /**
65       * Constructor with lists of planes to be used to estimate a projective 3D
66       * transformation.
67       * Planes 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 inputPlanes  list of input planes to be used to estimate a
72       *                     projective 3D transformation.
73       * @param outputPlanes list of output planes ot be used to estimate a
74       *                     projective 3D transformation.
75       * @throws IllegalArgumentException if provided lists of planes don't have
76       *                                  the same size or their size is smaller than MINIMUM_SIZE.
77       */
78      protected PlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
79              final List<Plane> inputPlanes, final List<Plane> outputPlanes) {
80          super();
81          internalSetPlanes(inputPlanes, outputPlanes);
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 PlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
91              final ProjectiveTransformation3DRobustEstimatorListener listener) {
92          super(listener);
93      }
94  
95      /**
96       * Constructor with listener and lists of planes to be used to estimate
97       * projective 3D transformation.
98       * Planes 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 inputPlanes  list of input planes to be used to estimate a
105      *                     projective 3D transformation.
106      * @param outputPlanes list of output planes to be used to estimate a
107      *                     projective 3D transformation.
108      * @throws IllegalArgumentException if provided lists of planes don't have
109      *                                  the same size or their size is smaller than MINIMUM_SIZE.
110      */
111     protected PlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
112             final ProjectiveTransformation3DRobustEstimatorListener listener,
113             final List<Plane> inputPlanes, final List<Plane> outputPlanes) {
114         super(listener);
115         internalSetPlanes(inputPlanes, outputPlanes);
116     }
117 
118     /**
119      * Returns list of input planes to be used to estimate a projective 3D
120      * transformation.
121      * Each plane in the list of input planes must be matched with the
122      * corresponding planes in the list of output planes located at the same
123      * position. Hence, both input planes and output planes must have the same
124      * size, and their size must be greater or equal than MINIMUM_SIZE
125      *
126      * @return list of input planes to be used to estimate an affine 3D
127      * transformation.
128      */
129     public List<Plane> getInputPlanes() {
130         return inputPlanes;
131     }
132 
133     /**
134      * Returns list of output planes to be used to estimate a projective 3D
135      * transformation.
136      * Each plane in the list of output planes must be matched with the
137      * corresponding plane in the list of input planes located at the same
138      * position. Hence, both input planes and output planes must have the same
139      * size, and their size must be greater or equal than MINIMUM_SIZE.
140      *
141      * @return list of output planes to be used to estimate a projective 3D
142      * transformation.
143      */
144     public List<Plane> getOutputPlanes() {
145         return outputPlanes;
146     }
147 
148     /**
149      * Sets lists of planes to be used to estimate a projective 3D
150      * transformation.
151      * Planes 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 inputPlanes  list of input planes to be used to estimate a
156      *                     projective 3D transformation.
157      * @param outputPlanes list of output planes to be used to estimate a
158      *                     projective 3D transformation.
159      * @throws IllegalArgumentException if provided lists of planes 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     protected final void setPlanes(final List<Plane> inputPlanes, final List<Plane> outputPlanes)
165             throws LockedException {
166         if (isLocked()) {
167             throw new LockedException();
168         }
169         internalSetPlanes(inputPlanes, outputPlanes);
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 planes) are provided
176      * and a minimum of MINIMUM_SIZE lines are available.
177      *
178      * @return true if estimator is ready, false otherwise.
179      */
180     public boolean isReady() {
181         return inputPlanes != null && outputPlanes != null && inputPlanes.size() == outputPlanes.size()
182                 && inputPlanes.size() >= MINIMUM_SIZE;
183     }
184 
185     /**
186      * Returns quality scores corresponding to each pair of matched planes.
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 planes.
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 3D plane
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 PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
222             final RobustEstimatorMethod method) {
223         return switch (method) {
224             case LMEDS -> new LMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator();
225             case MSAC -> new MSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator();
226             case PROSAC -> new PROSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator();
227             case PROMEDS -> new PROMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator();
228             default -> new RANSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator();
229         };
230     }
231 
232     /**
233      * Creates a projective 3D transformation estimator based on 3D plane
234      * correspondences and using provided robust estimator method.
235      *
236      * @param inputPlanes  list of input planes to be used to estimate a
237      *                     projective 3D transformation.
238      * @param outputPlanes list of output planes 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 lines don't have
244      *                                  the same size or their size is smaller than MINIMUM_SIZE.
245      */
246     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
247             final List<Plane> inputPlanes, final List<Plane> outputPlanes, final RobustEstimatorMethod method) {
248         return switch (method) {
249             case LMEDS -> new LMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
250                     inputPlanes, outputPlanes);
251             case MSAC -> new MSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
252                     inputPlanes, outputPlanes);
253             case PROSAC -> new PROSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
254                     inputPlanes, outputPlanes);
255             case PROMEDS -> new PROMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
256                     inputPlanes, outputPlanes);
257             default -> new RANSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
258                     inputPlanes, outputPlanes);
259         };
260     }
261 
262     /**
263      * Creates a projective 3D transformation estimator based on 3D plane
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 best
269      *                 projective 3D transformation.
270      * @return an instance of projective 3D transformation estimator.
271      */
272     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
273             final ProjectiveTransformation3DRobustEstimatorListener listener, final RobustEstimatorMethod method) {
274         return switch (method) {
275             case LMEDS -> new LMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(listener);
276             case MSAC -> new MSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(listener);
277             case PROSAC -> new PROSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(listener);
278             case PROMEDS -> new PROMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(listener);
279             default -> new RANSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(listener);
280         };
281     }
282 
283     /**
284      * Creates a projective 3D transformation estimator based on 3D line
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 inputPlanes  list of input lines to be used to estimate a
290      *                     projective 3D transformation.
291      * @param outputPlanes list of output lines to be used to estimate a
292      *                     projective 3D transformation.
293      * @param method       method of a robust estimator algorithm to estimate best
294      *                     projective 3D transformation.
295      * @return an instance of projective 3D transformation estimator.
296      * @throws IllegalArgumentException if provided lists of lines don't have
297      *                                  the same size or their size is smaller than MINIMUM_SIZE.
298      */
299     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
300             final ProjectiveTransformation3DRobustEstimatorListener listener,
301             final List<Plane> inputPlanes, List<Plane> outputPlanes, final RobustEstimatorMethod method) {
302         return switch (method) {
303             case LMEDS -> new LMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
304                     listener, inputPlanes, outputPlanes);
305             case MSAC -> new MSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
306                     listener, inputPlanes, outputPlanes);
307             case PROSAC -> new PROSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
308                     listener, inputPlanes, outputPlanes);
309             case PROMEDS -> new PROMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
310                     listener, inputPlanes, outputPlanes);
311             default -> new RANSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
312                     listener, inputPlanes, outputPlanes);
313         };
314     }
315 
316     /**
317      * Creates a projective 3D transformation estimator based on 3D plane
318      * correspondences and using provided robust estimator method.
319      *
320      * @param qualityScores quality scores corresponding to each pair of matched
321      *                      planes.
322      * @param method        method of a robust estimator algorithm to estimate best
323      *                      projective 3D transformation.
324      * @return an instance of projective 3D transformation estimator.
325      */
326     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
327             final double[] qualityScores, final RobustEstimatorMethod method) {
328         return switch (method) {
329             case LMEDS -> new LMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator();
330             case MSAC -> new MSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator();
331             case PROSAC -> new PROSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(qualityScores);
332             case PROMEDS -> new PROMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(qualityScores);
333             default -> new RANSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator();
334         };
335     }
336 
337     /**
338      * Creates a projective 3D transformation estimator based on plane
339      * correspondences and using provided robust estimator method.
340      *
341      * @param inputPlanes   list of input planes to be used to estimate a
342      *                      projective 3D transformation.
343      * @param outputPlanes  list of output planes to be used to estimate a
344      *                      projective 3D transformation.
345      * @param qualityScores quality scores corresponding to each pair of matched
346      *                      planes.
347      * @param method        method of a robust estimator algorithm to estimate best
348      *                      projective 3D transformation.
349      * @return an instance of projective 3D transformation estimator.
350      * @throws IllegalArgumentException if provided lists of lines don't have
351      *                                  the same size or their size is smaller than MINIMUM_SIZE.
352      */
353     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
354             final List<Plane> inputPlanes, final List<Plane> outputPlanes, final double[] qualityScores,
355             final RobustEstimatorMethod method) {
356         return switch (method) {
357             case LMEDS -> new LMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
358                     inputPlanes, outputPlanes);
359             case MSAC -> new MSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
360                     inputPlanes, outputPlanes);
361             case PROSAC -> new PROSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
362                     inputPlanes, outputPlanes, qualityScores);
363             case PROMEDS -> new PROMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
364                     inputPlanes, outputPlanes, qualityScores);
365             default -> new RANSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
366                     inputPlanes, outputPlanes);
367         };
368     }
369 
370     /**
371      * Creates a projective 3D transformation estimator based on plane
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      *                      lines.
378      * @param method        method of a robust estimator algorithm to estimate best
379      *                      projective 3D transformation.
380      * @return an instance of projective 3D transformation estimator.
381      */
382     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
383             final ProjectiveTransformation3DRobustEstimatorListener listener, final double[] qualityScores,
384             final RobustEstimatorMethod method) {
385         return switch (method) {
386             case LMEDS -> new LMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(listener);
387             case MSAC -> new MSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(listener);
388             case PROSAC -> new PROSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
389                     listener, qualityScores);
390             case PROMEDS -> new PROMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
391                     listener, qualityScores);
392             default -> new RANSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(listener);
393         };
394     }
395 
396     /**
397      * Creates a projective 3D transformation estimator based on plane
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 inputPlanes   list of input planes to be used to estimate a
403      *                      projective 3D transformation.
404      * @param outputPlanes  list of output planes to be used to estimate a
405      *                      projective 3D transformation.
406      * @param qualityScores quality scores corresponding to each pair of matched
407      *                      planes.
408      * @param method        method of a robust estimator algorithm to estimate best
409      *                      projective 3D transformation.
410      * @return an instance of projective 3D transformation estimator.
411      * @throws IllegalArgumentException if provided lists of lines don't have
412      *                                  the same size or their size is smaller than MINIMUM_SIZE.
413      */
414     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
415             final ProjectiveTransformation3DRobustEstimatorListener listener,
416             final List<Plane> inputPlanes, final List<Plane> outputPlanes, final double[] qualityScores,
417             final RobustEstimatorMethod method) {
418         return switch (method) {
419             case LMEDS -> new LMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
420                     listener, inputPlanes, outputPlanes);
421             case MSAC -> new MSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
422                     listener, inputPlanes, outputPlanes);
423             case PROSAC -> new PROSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
424                     listener, inputPlanes, outputPlanes, qualityScores);
425             case PROMEDS -> new PROMedSPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
426                     listener, inputPlanes, outputPlanes, qualityScores);
427             default -> new RANSACPlaneCorrespondenceProjectiveTransformation3DRobustEstimator(
428                     listener, inputPlanes, outputPlanes);
429         };
430     }
431 
432     /**
433      * Creates a projective 3D transformation estimator based on plane
434      * correspondences and using default robust estimator method.
435      *
436      * @return an instance of projective 3D transformation estimator.
437      */
438     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create() {
439         return create(DEFAULT_ROBUST_METHOD);
440     }
441 
442     /**
443      * Creates a projective 3D transformation estimator based on plane
444      * correspondences and using default robust estimator method.
445      *
446      * @param inputPlanes  list of input planes to be used to estimate a
447      *                     projective 3D transformation.
448      * @param outputPlanes list of output planes to be used to estimate a
449      *                     projective 3D transformation.
450      * @return an instance of projective 3D transformation estimator.
451      * @throws IllegalArgumentException if provided lists of planes don't have
452      *                                  the same size or their size is smaller than MINIMUM_SIZE.
453      */
454     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
455             final List<Plane> inputPlanes, final List<Plane> outputPlanes) {
456         return create(inputPlanes, outputPlanes, DEFAULT_ROBUST_METHOD);
457     }
458 
459     /**
460      * Creates a projective 3D transformation estimator based on plane
461      * correspondences and using default robust estimator method.
462      *
463      * @param listener listener to be notified of events such as when estimation
464      *                 starts, ends or its progress significantly changes.
465      * @return an instance of projective 3D transformation estimator.
466      */
467     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
468             final ProjectiveTransformation3DRobustEstimatorListener listener) {
469         return create(listener, DEFAULT_ROBUST_METHOD);
470     }
471 
472     /**
473      * Creates a projective 3D transformation estimator based on plane
474      * correspondences and using default robust estimator method.
475      *
476      * @param listener     listener to be notified of events such as when estimation
477      *                     starts, ends or its progress significantly changes.
478      * @param inputPlanes  list of input planes to be used to estimate a
479      *                     projective 3D transformation.
480      * @param outputPlanes list of output planes to be used to estimate a
481      *                     projective 3D transformation.
482      * @return an instance of projective 3D transformation estimator.
483      * @throws IllegalArgumentException if provided lists of lines don't have
484      *                                  the same size or their size is smaller than MINIMUM_SIZE.
485      */
486     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
487             final ProjectiveTransformation3DRobustEstimatorListener listener,
488             final List<Plane> inputPlanes, final List<Plane> outputPlanes) {
489         return create(listener, inputPlanes, outputPlanes, DEFAULT_ROBUST_METHOD);
490     }
491 
492     /**
493      * Creates a projective 3D transformation estimator based on plane
494      * correspondences and using default robust estimator method.
495      *
496      * @param qualityScores quality scores corresponding to each pair of matched
497      *                      planes.
498      * @return an instance of projective 3D transformation estimator.
499      */
500     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(final double[] qualityScores) {
501         return create(qualityScores, DEFAULT_ROBUST_METHOD);
502     }
503 
504     /**
505      * Creates a projective 3D transformation estimator based on 3D line
506      * correspondences and using default robust estimator method.
507      *
508      * @param inputPlanes   list of input planes to be used to estimate a
509      *                      projective 3D transformation.
510      * @param outputPlanes  list of output planes to be used to estimate a
511      *                      projective 3D transformation.
512      * @param qualityScores quality scores corresponding to each pair of matched
513      *                      planes.
514      * @return an instance of projective 3D transformation estimator.
515      * @throws IllegalArgumentException if provided lists of lines don't have
516      *                                  the same size or their size is smaller than MINIMUM_SIZE.
517      */
518     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
519             final List<Plane> inputPlanes, final List<Plane> outputPlanes, final double[] qualityScores) {
520         return create(inputPlanes, outputPlanes, qualityScores, DEFAULT_ROBUST_METHOD);
521     }
522 
523     /**
524      * Creates a projective 3D transformation estimator based on 3D line
525      * correspondences and using default robust estimator method.
526      *
527      * @param listener      listener to be notified of events such as when estimation
528      *                      starts, ends or its progress significantly changes.
529      * @param qualityScores quality scores corresponding to each pair of matched
530      *                      points.
531      * @return an instance of projective 3D transformation estimator.
532      */
533     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
534             final ProjectiveTransformation3DRobustEstimatorListener listener, final double[] qualityScores) {
535         return create(listener, qualityScores, DEFAULT_ROBUST_METHOD);
536     }
537 
538     /**
539      * Creates a projective 3D transformation estimator based on plane
540      * correspondences and using default robust estimator method.
541      *
542      * @param listener      listener to be notified of events such as when estimation
543      *                      starts, ends or its progress significantly changes.
544      * @param inputPlanes   list of input planes to be used to estimate a
545      *                      projective 3D transformation.
546      * @param outputPlanes  list of output planes to be used to estimate a
547      *                      projective 3D transformation.
548      * @param qualityScores quality scores corresponding to each pair of matched
549      *                      lines.
550      * @return an instance of projective 3D transformation estimator.
551      * @throws IllegalArgumentException if provided lists of lines don't have
552      *                                  the same size or their size is smaller than MINIMUM_SIZE.
553      */
554     public static PlaneCorrespondenceProjectiveTransformation3DRobustEstimator create(
555             final ProjectiveTransformation3DRobustEstimatorListener listener,
556             final List<Plane> inputPlanes, final List<Plane> outputPlanes, final double[] qualityScores) {
557         return create(listener, inputPlanes, outputPlanes, qualityScores, DEFAULT_ROBUST_METHOD);
558     }
559 
560     /**
561      * Internal method to set lists of planes to be used to estimate a
562      * projective 3D transformation.
563      * This method does not check whether estimator is locked or not
564      *
565      * @param inputPlanes  list of input planes to be used to estimate a
566      *                     projective 3D transformation.
567      * @param outputPlanes list of output planes to be used to estimate a
568      *                     projective 3D transformation.
569      * @throws IllegalArgumentException if provided lists of lines don't have
570      *                                  the same size or their size is smaller than MINIMUM_SIZE.
571      */
572     private void internalSetPlanes(final List<Plane> inputPlanes, final List<Plane> outputPlanes) {
573         if (inputPlanes.size() < MINIMUM_SIZE) {
574             throw new IllegalArgumentException();
575         }
576         if (inputPlanes.size() != outputPlanes.size()) {
577             throw new IllegalArgumentException();
578         }
579         this.inputPlanes = inputPlanes;
580         this.outputPlanes = outputPlanes;
581     }
582 
583     /**
584      * Computes residual by comparing two lines algebraically by doing the
585      * dot product of their parameters.
586      * A residual of 0 indicates that dot product was 1 or -1 and lines were
587      * equal.
588      * A residual of 1 indicates that dot product was 0 and lines were
589      * orthogonal.
590      * If dot product was -1, then although their director vectors are opposed,
591      * lines are considered equal, since sign changes are not taken into account.
592      *
593      * @param plane            originally sampled output plane.
594      * @param transformedPlane estimated output plane obtained after using
595      *                         estimated transformation.
596      * @return computed residual.
597      */
598     @SuppressWarnings("DuplicatedCode")
599     protected static double getResidual(final Plane plane, final Plane transformedPlane) {
600         return PlaneCorrespondenceAffineTransformation3DRobustEstimator.getResidual(plane, transformedPlane);
601     }
602 
603     /**
604      * Attempts to refine provided solution if refinement is requested.
605      * This method returns a refined solution of the same provided solution
606      * if refinement is not requested or has failed.
607      * If refinement is enabled, and it is requested to keep covariance, this
608      * method will also keep covariance of refined transformation.
609      *
610      * @param transformation transformation estimated by a robust estimator
611      *                       without refinement.
612      * @return solution after refinement (if requested) or the provided
613      * non-refined solution if not requested or refinement failed.
614      */
615     @SuppressWarnings("DuplicatedCode")
616     protected ProjectiveTransformation3D attemptRefine(final ProjectiveTransformation3D transformation) {
617         if (refineResult) {
618             final var refiner = new PlaneCorrespondenceProjectiveTransformation3DRefiner(transformation,
619                     keepCovariance, getInliersData(), inputPlanes, outputPlanes, getRefinementStandardDeviation());
620 
621             try {
622                 final var result = new ProjectiveTransformation3D();
623                 final var improved = refiner.refine(result);
624 
625                 if (keepCovariance) {
626                     // keep covariance
627                     covariance = refiner.getCovariance();
628                 }
629 
630                 return improved ? result : transformation;
631             } catch (final Exception e) {
632                 // refinement failed, so we return input value
633                 return transformation;
634             }
635         } else {
636             return transformation;
637         }
638     }
639 }