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