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