View Javadoc
1   /*
2    * Copyright (C) 2015 Alberto Irurueta Carro (alberto@irurueta.com)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.irurueta.ar.epipolar.estimators;
17  
18  import com.irurueta.ar.epipolar.FundamentalMatrix;
19  import com.irurueta.geometry.Point2D;
20  import com.irurueta.geometry.estimators.LockedException;
21  import com.irurueta.geometry.estimators.NotReadyException;
22  import com.irurueta.numerical.robust.PROSACRobustEstimator;
23  import com.irurueta.numerical.robust.PROSACRobustEstimatorListener;
24  import com.irurueta.numerical.robust.RobustEstimator;
25  import com.irurueta.numerical.robust.RobustEstimatorException;
26  import com.irurueta.numerical.robust.RobustEstimatorMethod;
27  
28  import java.util.ArrayList;
29  import java.util.List;
30  
31  /**
32   * Finds the best fundamental matrix for provided collections of matched 2D
33   * points using PROSAC algorithm.
34   */
35  public class PROSACFundamentalMatrixRobustEstimator extends FundamentalMatrixRobustEstimator {
36  
37      /**
38       * Constant defining default threshold to determine whether points are
39       * inliers or not.
40       * By default, 1.0 is considered a good value for cases where measures are
41       * done in pixels, since typically the minimum resolution is 1 pixel.
42       */
43      public static final double DEFAULT_THRESHOLD = 1.0;
44  
45      /**
46       * Minimum value that can be set as threshold.
47       * Threshold must be strictly greater than 0.0.
48       */
49      public static final double MIN_THRESHOLD = 0.0;
50  
51      /**
52       * Indicates that by default inliers will only be computed but not kept.
53       */
54      public static final boolean DEFAULT_COMPUTE_AND_KEEP_INLIERS = false;
55  
56      /**
57       * Indicates that by default residuals will only be computed but not kept.
58       */
59      public static final boolean DEFAULT_COMPUTE_AND_KEEP_RESIDUALS = false;
60  
61      /**
62       * Threshold to determine whether pairs of matched points are inliers or not
63       * when testing possible estimation solutions.
64       * The threshold refers to the amount of error (i.e. distance) a given
65       * point has respect to the epipolar line generated by its matched point.
66       */
67      private double threshold;
68  
69      /**
70       * Quality scores corresponding to each provided point.
71       * The larger the score value the better the quality of the sample.
72       */
73      private double[] qualityScores;
74  
75      /**
76       * Indicates whether inliers must be computed and kept.
77       */
78      private boolean computeAndKeepInliers;
79  
80      /**
81       * Indicates whether residuals must be computed and kept.
82       */
83      private boolean computeAndKeepResiduals;
84  
85      /**
86       * Constructor.
87       *
88       * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
89       *                                  estimator.
90       */
91      public PROSACFundamentalMatrixRobustEstimator(final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod) {
92          super(fundMatrixEstimatorMethod);
93          threshold = DEFAULT_THRESHOLD;
94          computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
95          computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
96      }
97  
98      /**
99       * Constructor.
100      *
101      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
102      *                                  estimator.
103      * @param listener                  listener to be notified of events such as when
104      *                                  estimation starts, ends or its progress significantly changes.
105      */
106     public PROSACFundamentalMatrixRobustEstimator(
107             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod,
108             final FundamentalMatrixRobustEstimatorListener listener) {
109         super(fundMatrixEstimatorMethod, listener);
110         threshold = DEFAULT_THRESHOLD;
111         computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
112         computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
113     }
114 
115     /**
116      * Constructor.
117      *
118      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
119      *                                  estimator.
120      * @param leftPoints                2D points on left view.
121      * @param rightPoints               2D points on right view.
122      * @throws IllegalArgumentException if provided list of points do not have
123      *                                  the same length or their length is less than 7 points.
124      */
125     public PROSACFundamentalMatrixRobustEstimator(
126             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod,
127             final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
128         super(fundMatrixEstimatorMethod, leftPoints, rightPoints);
129         threshold = DEFAULT_THRESHOLD;
130         computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
131         computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
132     }
133 
134     /**
135      * Constructor.
136      *
137      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
138      *                                  estimator.
139      * @param leftPoints                2D points on left view.
140      * @param rightPoints               2D points on right view.
141      * @param listener                  listener to be notified of events such as when estimation
142      *                                  starts, ends or its progress significantly changes.
143      * @throws IllegalArgumentException if provided list of points do not have
144      *                                  the same length or their length is less than 7 points.
145      */
146     public PROSACFundamentalMatrixRobustEstimator(
147             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod,
148             final List<Point2D> leftPoints, final List<Point2D> rightPoints,
149             final FundamentalMatrixRobustEstimatorListener listener) {
150         super(fundMatrixEstimatorMethod, leftPoints, rightPoints, listener);
151         threshold = DEFAULT_THRESHOLD;
152         computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
153         computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
154     }
155 
156     /**
157      * Constructor.
158      *
159      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
160      *                                  estimator.
161      * @param qualityScores             quality scores corresponding to each provided pair
162      *                                  of matched points.
163      * @throws IllegalArgumentException if provided quality scores length is
164      *                                  smaller than required size (i.e. 7 matched pair of points).
165      */
166     public PROSACFundamentalMatrixRobustEstimator(
167             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod, final double[] qualityScores) {
168         this(fundMatrixEstimatorMethod);
169         threshold = DEFAULT_THRESHOLD;
170         computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
171         computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
172         internalSetQualityScores(qualityScores);
173     }
174 
175     /**
176      * Constructor.
177      *
178      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
179      *                                  estimator.
180      * @param qualityScores             quality scores corresponding to each provided pair
181      *                                  of matched points.
182      * @param listener                  listener to be notified of events such as when
183      *                                  estimation starts, ends or its progress significantly changes.
184      * @throws IllegalArgumentException if provided quality scores length is
185      *                                  smaller than required size (i.e. 7 matched pair of points).
186      */
187     public PROSACFundamentalMatrixRobustEstimator(
188             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod, final double[] qualityScores,
189             final FundamentalMatrixRobustEstimatorListener listener) {
190         this(fundMatrixEstimatorMethod, listener);
191         threshold = DEFAULT_THRESHOLD;
192         computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
193         computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
194         internalSetQualityScores(qualityScores);
195     }
196 
197     /**
198      * Constructor.
199      *
200      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
201      *                                  estimator.
202      * @param qualityScores             quality scores corresponding to each provided pair
203      *                                  of matched points.
204      * @param leftPoints                2D points on left view.
205      * @param rightPoints               2D points on right view.
206      * @throws IllegalArgumentException if provided list of points or quality
207      *                                  scores do not have the same length or their length is less than
208      *                                  7 points.
209      */
210     public PROSACFundamentalMatrixRobustEstimator(
211             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod, final double[] qualityScores,
212             final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
213         this(fundMatrixEstimatorMethod, leftPoints, rightPoints);
214         threshold = DEFAULT_THRESHOLD;
215         computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
216         computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
217         internalSetQualityScores(qualityScores);
218     }
219 
220     /**
221      * Constructor.
222      *
223      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
224      *                                  estimator.
225      * @param qualityScores             quality scores corresponding to each provided pair
226      *                                  of matched points.
227      * @param leftPoints                2D points on left view.
228      * @param rightPoints               2D points on right view.
229      * @param listener                  listener to be notified of events such as when estimation
230      *                                  starts, ends or its progress significantly changes.
231      * @throws IllegalArgumentException if provided list of points or quality
232      *                                  scores do not have the same length or their length is less than
233      *                                  7 points.
234      */
235     public PROSACFundamentalMatrixRobustEstimator(
236             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod, final double[] qualityScores,
237             final List<Point2D> leftPoints, final List<Point2D> rightPoints,
238             final FundamentalMatrixRobustEstimatorListener listener) {
239         this(fundMatrixEstimatorMethod, leftPoints, rightPoints, listener);
240         threshold = DEFAULT_THRESHOLD;
241         computeAndKeepInliers = DEFAULT_COMPUTE_AND_KEEP_INLIERS;
242         computeAndKeepResiduals = DEFAULT_COMPUTE_AND_KEEP_RESIDUALS;
243         internalSetQualityScores(qualityScores);
244     }
245 
246     /**
247      * Constructor.
248      */
249     public PROSACFundamentalMatrixRobustEstimator() {
250         this(DEFAULT_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD);
251     }
252 
253     /**
254      * Constructor.
255      *
256      * @param listener listener to be notified of events such as when
257      *                 estimation starts, ends or its progress significantly changes.
258      */
259     public PROSACFundamentalMatrixRobustEstimator(final FundamentalMatrixRobustEstimatorListener listener) {
260         this(DEFAULT_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, listener);
261     }
262 
263     /**
264      * Constructor.
265      *
266      * @param leftPoints  2D points on left view.
267      * @param rightPoints 2D points on right view.
268      * @throws IllegalArgumentException if provided list of points do not have
269      *                                  the same length or their length is less than 7 points.
270      */
271     public PROSACFundamentalMatrixRobustEstimator(final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
272         this(DEFAULT_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, leftPoints, rightPoints);
273     }
274 
275     /**
276      * Constructor.
277      *
278      * @param leftPoints  2D points on left view.
279      * @param rightPoints 2D points on right view.
280      * @param listener    listener to be notified of events such as when estimation
281      *                    starts, ends or its progress significantly changes.
282      * @throws IllegalArgumentException if provided list of points do not have
283      *                                  the same length or their length is less than 7 points.
284      */
285     public PROSACFundamentalMatrixRobustEstimator(
286             final List<Point2D> leftPoints, final List<Point2D> rightPoints,
287             final FundamentalMatrixRobustEstimatorListener listener) {
288         this(DEFAULT_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, leftPoints, rightPoints, listener);
289     }
290 
291     /**
292      * Constructor.
293      *
294      * @param qualityScores quality scores corresponding to each provided pair
295      *                      of matched points.
296      * @throws IllegalArgumentException if provided quality scores length is
297      *                                  smaller than required size (i.e. 7 matched pair of points).
298      */
299     public PROSACFundamentalMatrixRobustEstimator(final double[] qualityScores) {
300         this(DEFAULT_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, qualityScores);
301     }
302 
303     /**
304      * Constructor.
305      *
306      * @param qualityScores quality scores corresponding to each provided pair
307      *                      of matched points.
308      * @param listener      listener to be notified of events such as when
309      *                      estimation starts, ends or its progress significantly changes.
310      * @throws IllegalArgumentException if provided quality scores length is
311      *                                  smaller than required size (i.e. 7 matched pair of points).
312      */
313     public PROSACFundamentalMatrixRobustEstimator(
314             final double[] qualityScores, final FundamentalMatrixRobustEstimatorListener listener) {
315         this(DEFAULT_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, qualityScores, listener);
316     }
317 
318     /**
319      * Constructor.
320      *
321      * @param qualityScores quality scores corresponding to each provided pair
322      *                      of matched points.
323      * @param leftPoints    2D points on left view.
324      * @param rightPoints   2D points on right view.
325      * @throws IllegalArgumentException if provided list of points or quality
326      *                                  scores do not have the same length or their length is less than
327      *                                  7 points.
328      */
329     public PROSACFundamentalMatrixRobustEstimator(
330             final double[] qualityScores, final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
331         this(DEFAULT_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, qualityScores, leftPoints, rightPoints);
332     }
333 
334     /**
335      * Constructor.
336      *
337      * @param qualityScores quality scores corresponding to each provided pair
338      *                      of matched points.
339      * @param leftPoints    2D points on left view.
340      * @param rightPoints   2D points on right view.
341      * @param listener      listener to be notified of events such as when estimation
342      *                      starts, ends or its progress significantly changes.
343      * @throws IllegalArgumentException if provided list of points or quality
344      *                                  scores do not have the same length or their length is less than
345      *                                  7 points.
346      */
347     public PROSACFundamentalMatrixRobustEstimator(
348             final double[] qualityScores, final List<Point2D> leftPoints, final List<Point2D> rightPoints,
349             final FundamentalMatrixRobustEstimatorListener listener) {
350         this(DEFAULT_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, qualityScores, leftPoints, rightPoints, listener);
351     }
352 
353     /**
354      * Returns threshold to determine whether matched pairs of points are
355      * inliers or not when testing possible estimation solutions.
356      * The threshold refers to the amount of error (i.e. distance) a given
357      * point has respect to the epipolar line generated by its matched point.
358      *
359      * @return threshold to determine whether matched pairs of points are
360      * inliers or not.
361      */
362     public double getThreshold() {
363         return threshold;
364     }
365 
366     /**
367      * Sets threshold to determine whether matched pairs of points are inliers
368      * or not when testing possible estimation solutions.
369      *
370      * @param threshold threshold to be set.
371      * @throws IllegalArgumentException if provided value is equal or less than
372      *                                  zero.
373      * @throws LockedException          if robust estimator is locked because an
374      *                                  estimation is already in progress.
375      */
376     public void setThreshold(final double threshold) throws LockedException {
377         if (isLocked()) {
378             throw new LockedException();
379         }
380         if (threshold <= MIN_THRESHOLD) {
381             throw new IllegalArgumentException();
382         }
383         this.threshold = threshold;
384     }
385 
386     /**
387      * Returns quality scores corresponding to each provided pair of points.
388      * The larger the score value the better the quality of the sampled matched
389      * pair of points.
390      *
391      * @return quality scores corresponding to each pair of points.
392      */
393     @Override
394     public double[] getQualityScores() {
395         return qualityScores;
396     }
397 
398     /**
399      * Sets quality scores corresponding to each provided pair of points.
400      * The larger the score value the better the quality of the sampled matched
401      * pair of points.
402      *
403      * @param qualityScores quality scores corresponding to each pair of points.
404      * @throws LockedException          if robust estimator is locked because an
405      *                                  estimation is already in progress.
406      * @throws IllegalArgumentException if provided quality scores length is
407      *                                  smaller than MINIMUM_SIZE (i.e. 3 samples).
408      */
409     @Override
410     public void setQualityScores(final double[] qualityScores) throws LockedException {
411         if (isLocked()) {
412             throw new LockedException();
413         }
414         internalSetQualityScores(qualityScores);
415     }
416 
417     /**
418      * Returns value indicating whether required data has been provided so that
419      * fundamental matrix estimation can start.
420      * This is true when input data (i.e. 7 pairs of matched 2D points and their
421      * quality scores) are provided.
422      * If true, estimator is ready to compute a fundamental matrix, otherwise
423      * more data needs to be provided.
424      *
425      * @return true if estimator is ready, false otherwise.
426      */
427     @Override
428     public boolean isReady() {
429         return super.isReady() && qualityScores != null && qualityScores.length == leftPoints.size();
430     }
431 
432     /**
433      * Indicates whether inliers must be computed and kept.
434      *
435      * @return true if inliers must be computed and kept, false if inliers
436      * only need to be computed but not kept.
437      */
438     public boolean isComputeAndKeepInliersEnabled() {
439         return computeAndKeepInliers;
440     }
441 
442     /**
443      * Specifies whether inliers must be computed and kept.
444      *
445      * @param computeAndKeepInliers true if inliers must be computed and kept,
446      *                              false if inliers only need to be computed but not kept.
447      * @throws LockedException if estimator is locked.
448      */
449     public void setComputeAndKeepInliersEnabled(final boolean computeAndKeepInliers) throws LockedException {
450         if (isLocked()) {
451             throw new LockedException();
452         }
453         this.computeAndKeepInliers = computeAndKeepInliers;
454     }
455 
456     /**
457      * Indicates whether residuals must be computed and kept.
458      *
459      * @return true if residuals must be computed and kept, false if residuals
460      * only need to be computed but not kept.
461      */
462     public boolean isComputeAndKeepResidualsEnabled() {
463         return computeAndKeepResiduals;
464     }
465 
466     /**
467      * Specifies whether residuals must be computed and kept.
468      *
469      * @param computeAndKeepResiduals true if residuals must be computed and
470      *                                kept, false if residuals only need to be computed but not kept.
471      * @throws LockedException if estimator is locked.
472      */
473     public void setComputeAndKeepResidualsEnabled(final boolean computeAndKeepResiduals) throws LockedException {
474         if (isLocked()) {
475             throw new LockedException();
476         }
477         this.computeAndKeepResiduals = computeAndKeepResiduals;
478     }
479 
480     /**
481      * Estimates a radial distortion using a robust estimator and
482      * the best set of matched 2D points found using the robust estimator.
483      *
484      * @return a radial distortion.
485      * @throws LockedException          if robust estimator is locked because an
486      *                                  estimation is already in progress.
487      * @throws NotReadyException        if provided input data is not enough to start
488      *                                  the estimation.
489      * @throws RobustEstimatorException if estimation fails for any reason
490      *                                  (i.e. numerical instability, no solution available, etc).
491      */
492     @SuppressWarnings("DuplicatedCode")
493     @Override
494     public FundamentalMatrix estimate() throws LockedException, NotReadyException, RobustEstimatorException {
495         if (isLocked()) {
496             throw new LockedException();
497         }
498         if (!isReady()) {
499             throw new NotReadyException();
500         }
501 
502         final var innerEstimator = new PROSACRobustEstimator<FundamentalMatrix>(new PROSACRobustEstimatorListener<>() {
503 
504             // subset of left points
505             private final List<Point2D> subsetLeftPoints = new ArrayList<>();
506 
507             // subset of right points
508             private final List<Point2D> subsetRightPoints = new ArrayList<>();
509 
510             @Override
511             public double getThreshold() {
512                 return threshold;
513             }
514 
515             @Override
516             public int getTotalSamples() {
517                 return leftPoints.size();
518             }
519 
520             @Override
521             public int getSubsetSize() {
522                 return getMinRequiredPoints();
523             }
524 
525             @Override
526             public void estimatePreliminarSolutions(
527                     final int[] samplesIndices, final List<FundamentalMatrix> solutions) {
528 
529                 subsetLeftPoints.clear();
530                 subsetRightPoints.clear();
531                 for (final var samplesIndex : samplesIndices) {
532                     subsetLeftPoints.add(leftPoints.get(samplesIndex));
533                     subsetRightPoints.add(rightPoints.get(samplesIndex));
534                 }
535 
536                 nonRobustEstimate(solutions, subsetLeftPoints, subsetRightPoints);
537             }
538 
539             @Override
540             public double computeResidual(final FundamentalMatrix currentEstimation, final int i) {
541                 final var leftPoint = leftPoints.get(i);
542                 final var rightPoint = rightPoints.get(i);
543                 return residual(currentEstimation, leftPoint, rightPoint);
544             }
545 
546             @Override
547             public boolean isReady() {
548                 return PROSACFundamentalMatrixRobustEstimator.this.isReady();
549             }
550 
551             @Override
552             public void onEstimateStart(final RobustEstimator<FundamentalMatrix> estimator) {
553                 if (listener != null) {
554                     listener.onEstimateStart(PROSACFundamentalMatrixRobustEstimator.this);
555                 }
556             }
557 
558             @Override
559             public void onEstimateEnd(final RobustEstimator<FundamentalMatrix> estimator) {
560                 if (listener != null) {
561                     listener.onEstimateEnd(PROSACFundamentalMatrixRobustEstimator.this);
562                 }
563             }
564 
565             @Override
566             public void onEstimateNextIteration(
567                     final RobustEstimator<FundamentalMatrix> estimator, final int iteration) {
568                 if (listener != null) {
569                     listener.onEstimateNextIteration(PROSACFundamentalMatrixRobustEstimator.this, iteration);
570                 }
571             }
572 
573             @Override
574             public void onEstimateProgressChange(
575                     final RobustEstimator<FundamentalMatrix> estimator, final float progress) {
576                 if (listener != null) {
577                     listener.onEstimateProgressChange(PROSACFundamentalMatrixRobustEstimator.this, progress);
578                 }
579             }
580 
581             @Override
582             public double[] getQualityScores() {
583                 return qualityScores;
584             }
585         });
586 
587         try {
588             locked = true;
589             inliersData = null;
590             innerEstimator.setComputeAndKeepInliersEnabled(computeAndKeepInliers || refineResult);
591             innerEstimator.setComputeAndKeepResidualsEnabled(computeAndKeepResiduals || refineResult);
592             innerEstimator.setConfidence(confidence);
593             innerEstimator.setMaxIterations(maxIterations);
594             innerEstimator.setProgressDelta(progressDelta);
595             final var result = innerEstimator.estimate();
596             inliersData = innerEstimator.getInliersData();
597             return attemptRefine(result);
598         } catch (final com.irurueta.numerical.LockedException e) {
599             throw new LockedException(e);
600         } catch (final com.irurueta.numerical.NotReadyException e) {
601             throw new NotReadyException(e);
602         } finally {
603             locked = false;
604         }
605     }
606 
607     /**
608      * Returns method being used for robust estimation.
609      *
610      * @return method being used for robust estimation.
611      */
612     @Override
613     public RobustEstimatorMethod getMethod() {
614         return RobustEstimatorMethod.PROSAC;
615     }
616 
617     /**
618      * Gets standard deviation used for Levenberg-Marquardt fitting during
619      * refinement.
620      * Returned value gives an indication of how much variance each residual
621      * has.
622      * Typically, this value is related to the threshold used on each robust
623      * estimation, since residuals of found inliers are within the range of
624      * such threshold.
625      *
626      * @return standard deviation used for refinement.
627      */
628     @Override
629     protected double getRefinementStandardDeviation() {
630         return threshold;
631     }
632 
633     /**
634      * Sets quality scores corresponding to each provided pair of matched
635      * points.
636      * This method is used internally and does not check whether instance is
637      * locked or not.
638      *
639      * @param qualityScores quality scores to be set.
640      * @throws IllegalArgumentException if provided quality scores length is
641      *                                  smaller than 7 points.
642      */
643     private void internalSetQualityScores(final double[] qualityScores) {
644         if (qualityScores.length < getMinRequiredPoints()) {
645             throw new IllegalArgumentException();
646         }
647 
648         this.qualityScores = qualityScores;
649     }
650 }