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.PROMedSRobustEstimator;
23  import com.irurueta.numerical.robust.PROMedSRobustEstimatorListener;
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 PROMedS algorithm.
34   */
35  public class PROMedSFundamentalMatrixRobustEstimator extends FundamentalMatrixRobustEstimator {
36  
37      /**
38       * Default non-robust method to estimate a fundamental matrix.
39       */
40      public static final FundamentalMatrixEstimatorMethod DEFAULT_PROMEDS_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD =
41              FundamentalMatrixEstimatorMethod.SEVEN_POINTS_ALGORITHM;
42  
43      /**
44       * Default value to be used for stop threshold. Stop threshold can be used
45       * to keep the algorithm iterating in case that best estimated threshold
46       * using median of residuals is not small enough. Once a solution is found
47       * that generates a threshold below this value, the algorithm will stop.
48       * The stop threshold can be used to prevent the LMedS algorithm iterating
49       * too many times in cases where samples have a very similar accuracy.
50       * For instance, in cases where proportion of outliers is very small (close
51       * to 0%), and samples are very accurate (i.e. 1e-6), the algorithm would
52       * iterate for a long time trying to find the best solution when indeed
53       * there is no need to do that if a reasonable threshold has already been
54       * reached.
55       * Because of this behaviour the stop threshold can be set to a value much
56       * lower than the one typically used in RANSAC, and yet the algorithm could
57       * still produce even smaller thresholds in estimated results.
58       */
59      public static final double DEFAULT_STOP_THRESHOLD = 1e-3;
60  
61      /**
62       * Minimum allowed stop threshold value.
63       */
64      public static final double MIN_STOP_THRESHOLD = 0.0;
65  
66      /**
67       * Threshold to be used to keep the algorithm iterating in case that best
68       * estimated threshold using median of residuals is not small enough. Once
69       * a solution is found that generates a threshold below this value, the
70       * algorithm will stop.
71       * The stop threshold can be used to prevent the LMedS algorithm iterating
72       * too many times in cases where samples have a very similar accuracy.
73       * For instance, in cases where proportion of outliers is very small (close
74       * to 0%), and samples are very accurate (i.e. 1e-6), the algorithm would
75       * iterate for a long time trying to find the best solution when indeed
76       * there is no need to do that if a reasonable threshold has already been
77       * reached.
78       * Because of this behaviour the stop threshold can be set to a value much
79       * lower than the one typically used in RANSAC, and yet the algorithm could
80       * still produce even smaller thresholds in estimated results.
81       */
82      private double stopThreshold;
83  
84      /**
85       * Quality scores corresponding to each provided point.
86       * The larger the score value the better the quality of the sample.
87       */
88      private double[] qualityScores;
89  
90      /**
91       * Constructor.
92       *
93       * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
94       *                                  estimator.
95       */
96      public PROMedSFundamentalMatrixRobustEstimator(final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod) {
97          super(fundMatrixEstimatorMethod);
98          stopThreshold = DEFAULT_STOP_THRESHOLD;
99      }
100 
101     /**
102      * Constructor.
103      *
104      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
105      *                                  estimator.
106      * @param listener                  listener to be notified of events such as when
107      *                                  estimation starts, ends or its progress significantly changes.
108      */
109     public PROMedSFundamentalMatrixRobustEstimator(
110             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod,
111             final FundamentalMatrixRobustEstimatorListener listener) {
112         super(fundMatrixEstimatorMethod, listener);
113         stopThreshold = DEFAULT_STOP_THRESHOLD;
114     }
115 
116     /**
117      * Constructor.
118      *
119      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
120      *                                  estimator.
121      * @param leftPoints                2D points on left view.
122      * @param rightPoints               2D points on right view.
123      * @throws IllegalArgumentException if provided list of points do not have
124      *                                  the same length or their length is less than 8 points.
125      */
126     public PROMedSFundamentalMatrixRobustEstimator(
127             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod,
128             final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
129         super(fundMatrixEstimatorMethod, leftPoints, rightPoints);
130         if (leftPoints.size() < EightPointsFundamentalMatrixEstimator.MIN_REQUIRED_POINTS) {
131             throw new IllegalArgumentException();
132         }
133         stopThreshold = DEFAULT_STOP_THRESHOLD;
134     }
135 
136     /**
137      * Constructor.
138      *
139      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
140      *                                  estimator.
141      * @param leftPoints                2D points on left view.
142      * @param rightPoints               2D points on right view.
143      * @param listener                  listener to be notified of events such as when estimation
144      *                                  starts, ends or its progress significantly changes.
145      * @throws IllegalArgumentException if provided list of points do not have
146      *                                  the same length or their length is less than 8 points.
147      */
148     public PROMedSFundamentalMatrixRobustEstimator(
149             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod,
150             final List<Point2D> leftPoints, final List<Point2D> rightPoints,
151             final FundamentalMatrixRobustEstimatorListener listener) {
152         super(fundMatrixEstimatorMethod, leftPoints, rightPoints, listener);
153         if (leftPoints.size() < EightPointsFundamentalMatrixEstimator.MIN_REQUIRED_POINTS) {
154             throw new IllegalArgumentException();
155         }
156         stopThreshold = DEFAULT_STOP_THRESHOLD;
157     }
158 
159     /**
160      * Constructor.
161      *
162      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
163      *                                  estimator.
164      * @param qualityScores             quality scores corresponding to each provided pair
165      *                                  of matched points.
166      * @throws IllegalArgumentException if provided quality scores length is
167      *                                  smaller than required size (i.e. 7 matched pair of points).
168      */
169     public PROMedSFundamentalMatrixRobustEstimator(
170             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod, final double[] qualityScores) {
171         this(fundMatrixEstimatorMethod);
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 PROMedSFundamentalMatrixRobustEstimator(
188             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod, final double[] qualityScores,
189             final FundamentalMatrixRobustEstimatorListener listener) {
190         this(fundMatrixEstimatorMethod, listener);
191         internalSetQualityScores(qualityScores);
192     }
193 
194     /**
195      * Constructor.
196      *
197      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
198      *                                  estimator.
199      * @param qualityScores             quality scores corresponding to each provided pair
200      *                                  of matched points.
201      * @param leftPoints                2D points on left view.
202      * @param rightPoints               2D points on right view.
203      * @throws IllegalArgumentException if provided list of points or quality
204      *                                  scores do not have the same length or their length is less
205      *                                  than 7 points.
206      */
207     public PROMedSFundamentalMatrixRobustEstimator(
208             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod, final double[] qualityScores,
209             final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
210         this(fundMatrixEstimatorMethod, leftPoints, rightPoints);
211         internalSetQualityScores(qualityScores);
212     }
213 
214     /**
215      * Constructor.
216      *
217      * @param fundMatrixEstimatorMethod method for non-robust fundamental matrix
218      *                                  estimator.
219      * @param qualityScores             quality scores corresponding to each provided pair
220      *                                  of matched points.
221      * @param leftPoints                2D points on left view.
222      * @param rightPoints               2D points on right view.
223      * @param listener                  listener to be notified of events such as when estimation
224      *                                  starts, ends or its progress significantly changes.
225      * @throws IllegalArgumentException if provided list of points or quality
226      *                                  scores do not have the same length or their length is less
227      *                                  than 7 points.
228      */
229     public PROMedSFundamentalMatrixRobustEstimator(
230             final FundamentalMatrixEstimatorMethod fundMatrixEstimatorMethod, final double[] qualityScores,
231             final List<Point2D> leftPoints, final List<Point2D> rightPoints,
232             final FundamentalMatrixRobustEstimatorListener listener) {
233         this(fundMatrixEstimatorMethod, leftPoints, rightPoints, listener);
234         internalSetQualityScores(qualityScores);
235     }
236 
237     /**
238      * Constructor.
239      */
240     public PROMedSFundamentalMatrixRobustEstimator() {
241         this(DEFAULT_PROMEDS_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD);
242     }
243 
244     /**
245      * Constructor.
246      *
247      * @param listener listener to be notified of events such as when
248      *                 estimation starts, ends or its progress significantly changes.
249      */
250     public PROMedSFundamentalMatrixRobustEstimator(final FundamentalMatrixRobustEstimatorListener listener) {
251         this(DEFAULT_PROMEDS_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, listener);
252     }
253 
254     /**
255      * Constructor.
256      *
257      * @param leftPoints  2D points on left view.
258      * @param rightPoints 2D points on right view.
259      * @throws IllegalArgumentException if provided list of points do not have
260      *                                  the same length or their length is less than 8 points.
261      */
262     public PROMedSFundamentalMatrixRobustEstimator(final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
263         this(DEFAULT_PROMEDS_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, leftPoints, rightPoints);
264     }
265 
266     /**
267      * Constructor.
268      *
269      * @param leftPoints  2D points on left view.
270      * @param rightPoints 2D points on right view.
271      * @param listener    listener to be notified of events such as when estimation
272      *                    starts, ends or its progress significantly changes.
273      * @throws IllegalArgumentException if provided list of points do not have
274      *                                  the same length or their length is less than 8 points.
275      */
276     public PROMedSFundamentalMatrixRobustEstimator(final List<Point2D> leftPoints, final List<Point2D> rightPoints,
277                                                    final FundamentalMatrixRobustEstimatorListener listener) {
278         this(DEFAULT_PROMEDS_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, leftPoints, rightPoints, listener);
279     }
280 
281     /**
282      * Constructor.
283      *
284      * @param qualityScores quality scores corresponding to each provided pair
285      *                      of matched points.
286      * @throws IllegalArgumentException if provided quality scores length is
287      *                                  smaller than required size (i.e. 7 matched pair of points).
288      */
289     public PROMedSFundamentalMatrixRobustEstimator(final double[] qualityScores) {
290         this(DEFAULT_PROMEDS_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, qualityScores);
291     }
292 
293     /**
294      * Constructor.
295      *
296      * @param qualityScores quality scores corresponding to each provided pair
297      *                      of matched points.
298      * @param listener      listener to be notified of events such as when
299      *                      estimation starts, ends or its progress significantly changes.
300      * @throws IllegalArgumentException if provided quality scores length is
301      *                                  smaller than required size (i.e. 7 matched pair of points).
302      */
303     public PROMedSFundamentalMatrixRobustEstimator(
304             final double[] qualityScores, final FundamentalMatrixRobustEstimatorListener listener) {
305         this(DEFAULT_PROMEDS_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, qualityScores, listener);
306     }
307 
308     /**
309      * Constructor.
310      *
311      * @param qualityScores quality scores corresponding to each provided pair
312      *                      of matched points.
313      * @param leftPoints    2D points on left view.
314      * @param rightPoints   2D points on right view.
315      * @throws IllegalArgumentException if provided list of points or quality
316      *                                  scores do not have the same length or their length is less
317      *                                  than 7 points.
318      */
319     public PROMedSFundamentalMatrixRobustEstimator(
320             final double[] qualityScores, final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
321         this(DEFAULT_PROMEDS_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, qualityScores, leftPoints, rightPoints);
322     }
323 
324     /**
325      * Constructor.
326      *
327      * @param qualityScores quality scores corresponding to each provided pair
328      *                      of matched points.
329      * @param leftPoints    2D points on left view.
330      * @param rightPoints   2D points on right view.
331      * @param listener      listener to be notified of events such as when estimation
332      *                      starts, ends or its progress significantly changes.
333      * @throws IllegalArgumentException if provided list of points or quality
334      *                                  scores do not have the same length or their length is less
335      *                                  than 7 points.
336      */
337     public PROMedSFundamentalMatrixRobustEstimator(
338             final double[] qualityScores, final List<Point2D> leftPoints, final List<Point2D> rightPoints,
339             final FundamentalMatrixRobustEstimatorListener listener) {
340         this(DEFAULT_PROMEDS_FUNDAMENTAL_MATRIX_ESTIMATOR_METHOD, qualityScores, leftPoints, rightPoints, listener);
341     }
342 
343     /**
344      * Sets matched 2D points on both left and right views.
345      *
346      * @param leftPoints  matched 2D points on left view.
347      * @param rightPoints matched 2D points on right view.
348      * @throws LockedException          if this fundamental matrix estimator is locked.
349      * @throws IllegalArgumentException if provided matched points on left and
350      *                                  right views do not have the same length or if their length is
351      *                                  less than 8 points.
352      */
353     @Override
354     public void setPoints(final List<Point2D> leftPoints, final List<Point2D> rightPoints) throws LockedException {
355         if (isLocked()) {
356             throw new LockedException();
357         }
358         if (leftPoints.size() < EightPointsFundamentalMatrixEstimator.MIN_REQUIRED_POINTS) {
359             throw new IllegalArgumentException();
360         }
361         super.setPoints(leftPoints, rightPoints);
362     }
363 
364 
365     /**
366      * Returns threshold to be used to keep the algorithm iterating in case that
367      * best estimated threshold using median of residuals is not small enough.
368      * Once a solution is found that generates a threshold below this value, the
369      * algorithm will stop.
370      * The stop threshold can be used to prevent the LMedS algorithm iterating
371      * too many times in cases where samples have a very similar accuracy.
372      * For instance, in cases where proportion of outliers is very small (close
373      * to 0%), and samples are very accurate (i.e. 1e-6), the algorithm would
374      * iterate for a long time trying to find the best solution when indeed
375      * there is no need to do that if a reasonable threshold has already been
376      * reached.
377      * Because of this behaviour the stop threshold can be set to a value much
378      * lower than the one typically used in RANSAC, and yet the algorithm could
379      * still produce even smaller thresholds in estimated results.
380      *
381      * @return stop threshold to stop the algorithm prematurely when a certain
382      * accuracy has been reached.
383      */
384     public double getStopThreshold() {
385         return stopThreshold;
386     }
387 
388     /**
389      * Sets threshold to be used to keep the algorithm iterating in case that
390      * best estimated threshold using median of residuals is not small enough.
391      * Once a solution is found that generates a threshold below this value, the
392      * algorithm will stop.
393      * The stop threshold can be used to prevent the LMedS algorithm iterating
394      * too many times in cases where samples have a very similar accuracy.
395      * For instance, in cases where proportion of outliers is very small (close
396      * to 0%), and samples are very accurate (i.e. 1e-6), the algorithm would
397      * iterate for a long time trying to find the best solution when indeed
398      * there is no need to do that if a reasonable threshold has already been
399      * reached.
400      * Because of this behaviour the stop threshold can be set to a value much
401      * lower than the one typically used in RANSAC, and yet the algorithm could
402      * still produce even smaller thresholds in estimated results.
403      *
404      * @param stopThreshold stop threshold to stop the algorithm prematurely
405      *                      when a certain accuracy has been reached.
406      * @throws IllegalArgumentException if provided value is zero or negative.
407      * @throws LockedException          if robust estimator is locked because an
408      *                                  estimation is already in progress.
409      */
410     public void setStopThreshold(final double stopThreshold) throws LockedException {
411         if (isLocked()) {
412             throw new LockedException();
413         }
414         if (stopThreshold <= MIN_STOP_THRESHOLD) {
415             throw new IllegalArgumentException();
416         }
417 
418         this.stopThreshold = stopThreshold;
419     }
420 
421     /**
422      * Returns quality scores corresponding to each provided pair of points.
423      * The larger the score value the better the quality of the sampled matched
424      * pair of points.
425      *
426      * @return quality scores corresponding to each pair of points.
427      */
428     @Override
429     public double[] getQualityScores() {
430         return qualityScores;
431     }
432 
433     /**
434      * Sets quality scores corresponding to each provided pair of points.
435      * The larger the score value the better the quality of the sampled matched
436      * pair of points.
437      *
438      * @param qualityScores quality scores corresponding to each pair of points.
439      * @throws LockedException          if robust estimator is locked because an
440      *                                  estimation is already in progress.
441      * @throws IllegalArgumentException if provided quality scores length is
442      *                                  smaller than MINIMUM_SIZE (i.e. 3 samples).
443      */
444     @Override
445     public void setQualityScores(final double[] qualityScores) throws LockedException {
446         if (isLocked()) {
447             throw new LockedException();
448         }
449         internalSetQualityScores(qualityScores);
450     }
451 
452     /**
453      * Returns value indicating whether required data has been provided so that
454      * fundamental matrix estimation can start.
455      * This is true when input data (i.e. 7 pairs of matched 2D points and their
456      * quality scores) are provided.
457      * If true, estimator is ready to compute a fundamental matrix, otherwise
458      * more data needs to be provided.
459      *
460      * @return true if estimator is ready, false otherwise.
461      */
462     @Override
463     public boolean isReady() {
464         return super.isReady() && qualityScores != null && qualityScores.length == leftPoints.size();
465     }
466 
467     /**
468      * Estimates a radial distortion using a robust estimator and
469      * the best set of matched 2D points found using the robust estimator.
470      *
471      * @return a radial distortion.
472      * @throws LockedException          if robust estimator is locked because an
473      *                                  estimation is already in progress.
474      * @throws NotReadyException        if provided input data is not enough to start
475      *                                  the estimation.
476      * @throws RobustEstimatorException if estimation fails for any reason
477      *                                  (i.e. numerical instability, no solution available, etc).
478      */
479     @SuppressWarnings("DuplicatedCode")
480     @Override
481     public FundamentalMatrix estimate() throws LockedException, NotReadyException, RobustEstimatorException {
482         if (isLocked()) {
483             throw new LockedException();
484         }
485         if (!isReady()) {
486             throw new NotReadyException();
487         }
488 
489         final var innerEstimator = new PROMedSRobustEstimator<FundamentalMatrix>(
490                 new PROMedSRobustEstimatorListener<>() {
491 
492                     // subset of left points
493                     private final List<Point2D> subsetLeftPoints = new ArrayList<>();
494 
495                     // subset of right points
496                     private final List<Point2D> subsetRightPoints = new ArrayList<>();
497 
498                     @Override
499                     public double getThreshold() {
500                         return stopThreshold;
501                     }
502 
503                     @Override
504                     public int getTotalSamples() {
505                         return leftPoints.size();
506                     }
507 
508                     @Override
509                     public int getSubsetSize() {
510                         return getMinRequiredPoints();
511                     }
512 
513                     @Override
514                     public void estimatePreliminarSolutions(
515                             final int[] samplesIndices, final List<FundamentalMatrix> solutions) {
516 
517                         subsetLeftPoints.clear();
518                         subsetRightPoints.clear();
519                         for (final var samplesIndex : samplesIndices) {
520                             subsetLeftPoints.add(leftPoints.get(samplesIndex));
521                             subsetRightPoints.add(rightPoints.get(samplesIndex));
522                         }
523 
524                         nonRobustEstimate(solutions, subsetLeftPoints, subsetRightPoints);
525                     }
526 
527                     @Override
528                     public double computeResidual(final FundamentalMatrix currentEstimation, final int i) {
529                         final var leftPoint = leftPoints.get(i);
530                         final var rightPoint = rightPoints.get(i);
531                         return residual(currentEstimation, leftPoint, rightPoint);
532                     }
533 
534                     @Override
535                     public boolean isReady() {
536                         return PROMedSFundamentalMatrixRobustEstimator.this.isReady();
537                     }
538 
539                     @Override
540                     public void onEstimateStart(final RobustEstimator<FundamentalMatrix> estimator) {
541                         if (listener != null) {
542                             listener.onEstimateStart(PROMedSFundamentalMatrixRobustEstimator.this);
543                         }
544                     }
545 
546                     @Override
547                     public void onEstimateEnd(final RobustEstimator<FundamentalMatrix> estimator) {
548                         if (listener != null) {
549                             listener.onEstimateEnd(PROMedSFundamentalMatrixRobustEstimator.this);
550                         }
551                     }
552 
553                     @Override
554                     public void onEstimateNextIteration(
555                             final RobustEstimator<FundamentalMatrix> estimator, final int iteration) {
556                         if (listener != null) {
557                             listener.onEstimateNextIteration(
558                                     PROMedSFundamentalMatrixRobustEstimator.this, iteration);
559                         }
560                     }
561 
562                     @Override
563                     public void onEstimateProgressChange(
564                             final RobustEstimator<FundamentalMatrix> estimator, final float progress) {
565                         if (listener != null) {
566                             listener.onEstimateProgressChange(
567                                     PROMedSFundamentalMatrixRobustEstimator.this, progress);
568                         }
569                     }
570 
571                     @Override
572                     public double[] getQualityScores() {
573                         return qualityScores;
574                     }
575                 });
576 
577         try {
578             locked = true;
579             inliersData = null;
580             innerEstimator.setConfidence(confidence);
581             innerEstimator.setMaxIterations(maxIterations);
582             innerEstimator.setProgressDelta(progressDelta);
583             final var result = innerEstimator.estimate();
584             inliersData = innerEstimator.getInliersData();
585             return attemptRefine(result);
586         } catch (final com.irurueta.numerical.LockedException e) {
587             throw new LockedException(e);
588         } catch (final com.irurueta.numerical.NotReadyException e) {
589             throw new NotReadyException(e);
590         } finally {
591             locked = false;
592         }
593     }
594 
595     /**
596      * Returns method being used for robust estimation.
597      *
598      * @return method being used for robust estimation.
599      */
600     @Override
601     public RobustEstimatorMethod getMethod() {
602         return RobustEstimatorMethod.PROMEDS;
603     }
604 
605     /**
606      * Gets standard deviation used for Levenberg-Marquardt fitting during
607      * refinement.
608      * Returned value gives an indication of how much variance each residual
609      * has.
610      * Typically, this value is related to the threshold used on each robust
611      * estimation, since residuals of found inliers are within the range of
612      * such threshold.
613      *
614      * @return standard deviation used for refinement.
615      */
616     @Override
617     protected double getRefinementStandardDeviation() {
618         final var inliersData = (PROMedSRobustEstimator.PROMedSInliersData) getInliersData();
619         return inliersData.getEstimatedThreshold();
620     }
621 
622     /**
623      * Sets quality scores corresponding to each provided pair of matched
624      * points.
625      * This method is used internally and does not check whether instance is
626      * locked or not.
627      *
628      * @param qualityScores quality scores to be set.
629      * @throws IllegalArgumentException if provided quality scores length is
630      *                                  smaller than 8 points.
631      */
632     private void internalSetQualityScores(final double[] qualityScores) {
633         if (qualityScores.length < getMinRequiredPoints()) {
634             throw new IllegalArgumentException();
635         }
636 
637         this.qualityScores = qualityScores;
638     }
639 }