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.AffineTransformation3D;
19 import com.irurueta.geometry.Point3D;
20 import com.irurueta.geometry.refiners.PointCorrespondenceAffineTransformation3DRefiner;
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 * 3D transformation for collections of matching 3D 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 PointCorrespondenceAffineTransformation3DRobustEstimator
32 extends AffineTransformation3DRobustEstimator {
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 3D 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<Point3D> inputPoints;
47
48 /**
49 * List of points to be used to estimate an affine 3D 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<Point3D> outputPoints;
56
57 /**
58 * Constructor.
59 */
60 protected PointCorrespondenceAffineTransformation3DRobustEstimator() {
61 super();
62 }
63
64 /**
65 * Constructor with lists of points to be used to estimate an affine 3D
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 3D transformation.
73 * @param outputPoints list of output points to be used to estimate an
74 * affine 3D 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 PointCorrespondenceAffineTransformation3DRobustEstimator(
79 final List<Point3D> inputPoints, final List<Point3D> 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 * stars, ends or its progress significantly changes.
89 */
90 protected PointCorrespondenceAffineTransformation3DRobustEstimator(
91 final AffineTransformation3DRobustEstimatorListener listener) {
92 super(listener);
93 }
94
95 /**
96 * Constructor with listener and lists of points to be used to estimate an
97 * affine 3D 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 3D transformation.
106 * @param outputPoints list of output points to be used to estimate an
107 * affine 3D 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 PointCorrespondenceAffineTransformation3DRobustEstimator(
112 final AffineTransformation3DRobustEstimatorListener listener,
113 final List<Point3D> inputPoints, final List<Point3D> outputPoints) {
114 super(listener);
115 internalSetPoints(inputPoints, outputPoints);
116 }
117
118 /**
119 * Returns list of input points to be used to estimate an affine 3D
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 3D
127 * transformation.
128 */
129 public List<Point3D> getInputPoints() {
130 return inputPoints;
131 }
132
133 /**
134 * Returns list of output points to be used to estimate an affine 3D
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<Point3D> getOutputPoints() {
145 return outputPoints;
146 }
147
148 /**
149 * Sets lists of points to be used to estimate an affine 3D 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 3D transformation.
156 * @param outputPoints list of output points to be used to estimate an
157 * affine 3D 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<Point3D> inputPoints, final List<Point3D> 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 3D 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 3D 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 3D transformation.
218 * @return an instance of affine 3D transformation estimator.
219 */
220 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(final RobustEstimatorMethod method) {
221 return switch (method) {
222 case LMEDS -> new LMedSPointCorrespondenceAffineTransformation3DRobustEstimator();
223 case MSAC -> new MSACPointCorrespondenceAffineTransformation3DRobustEstimator();
224 case PROSAC -> new PROSACPointCorrespondenceAffineTransformation3DRobustEstimator();
225 case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation3DRobustEstimator();
226 default -> new RANSACPointCorrespondenceAffineTransformation3DRobustEstimator();
227 };
228 }
229
230 /**
231 * Creates an affine 3D transformation estimator based on 3D 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 3D transformation.
236 * @param outputPoints list of output points to be used to estimate an
237 * affine 3D transformation.
238 * @param method method of a robust estimator algorithm to estimate
239 * the best affine 3D transformation.
240 * @return an instance of affine 3D 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 PointCorrespondenceAffineTransformation3DRobustEstimator create(
245 final List<Point3D> inputPoints, final List<Point3D> outputPoints, final RobustEstimatorMethod method) {
246 return switch (method) {
247 case LMEDS -> new LMedSPointCorrespondenceAffineTransformation3DRobustEstimator(inputPoints, outputPoints);
248 case MSAC -> new MSACPointCorrespondenceAffineTransformation3DRobustEstimator(inputPoints, outputPoints);
249 case PROSAC -> new PROSACPointCorrespondenceAffineTransformation3DRobustEstimator(
250 inputPoints, outputPoints);
251 case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation3DRobustEstimator(
252 inputPoints, outputPoints);
253 default -> new RANSACPointCorrespondenceAffineTransformation3DRobustEstimator(inputPoints, outputPoints);
254 };
255 }
256
257 /**
258 * Creates an affine 3D transformation estimator based on 3D 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 3D transformation.
265 * @return an instance of affine 3D transformation estimator.
266 */
267 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(
268 final AffineTransformation3DRobustEstimatorListener listener, final RobustEstimatorMethod method) {
269 return switch (method) {
270 case LMEDS -> new LMedSPointCorrespondenceAffineTransformation3DRobustEstimator(listener);
271 case MSAC -> new MSACPointCorrespondenceAffineTransformation3DRobustEstimator(listener);
272 case PROSAC -> new PROSACPointCorrespondenceAffineTransformation3DRobustEstimator(listener);
273 case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation3DRobustEstimator(listener);
274 default -> new RANSACPointCorrespondenceAffineTransformation3DRobustEstimator(listener);
275 };
276 }
277
278 /**
279 * Creates an affine 3D transformation estimator based on 3D 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 3D transformation.
286 * @param outputPoints list of output points to be used to estimate an
287 * affine 3D transformation.
288 * @param method method of a robust estimator algorithm to estimate
289 * the best affine 3D transformation.
290 * @return an instance of affine 3D 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 PointCorrespondenceAffineTransformation3DRobustEstimator create(
295 final AffineTransformation3DRobustEstimatorListener listener, final List<Point3D> inputPoints,
296 final List<Point3D> outputPoints, final RobustEstimatorMethod method) {
297 return switch (method) {
298 case LMEDS -> new LMedSPointCorrespondenceAffineTransformation3DRobustEstimator(
299 listener, inputPoints, outputPoints);
300 case MSAC -> new MSACPointCorrespondenceAffineTransformation3DRobustEstimator(
301 listener, inputPoints, outputPoints);
302 case PROSAC -> new PROSACPointCorrespondenceAffineTransformation3DRobustEstimator(
303 listener, inputPoints, outputPoints);
304 case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation3DRobustEstimator(
305 listener, inputPoints, outputPoints);
306 default -> new RANSACPointCorrespondenceAffineTransformation3DRobustEstimator(
307 listener, inputPoints, outputPoints);
308 };
309 }
310
311 /**
312 * Creates an affine 3D transformation estimator based on 3D 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 3D transformation.
319 * @return an instance of affine 3D transformation estimator.
320 */
321 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(
322 final double[] qualityScores, final RobustEstimatorMethod method) {
323 return switch (method) {
324 case LMEDS -> new LMedSPointCorrespondenceAffineTransformation3DRobustEstimator();
325 case MSAC -> new MSACPointCorrespondenceAffineTransformation3DRobustEstimator();
326 case PROSAC -> new PROSACPointCorrespondenceAffineTransformation3DRobustEstimator(qualityScores);
327 case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation3DRobustEstimator(qualityScores);
328 default -> new RANSACPointCorrespondenceAffineTransformation3DRobustEstimator();
329 };
330 }
331
332 /**
333 * Creates an affine 3D transformation estimator based on 3D point
334 * correspondences and using provided robust estimator method.
335 *
336 * @param inputPoints list of input points to be used to estimate an
337 * affine 3D transformation.
338 * @param outputPoints list of output points to be used to estimate an
339 * affine 3D transformation.
340 * @param qualityScores quality scores corresponding to each pair of matched
341 * points.
342 * @param method method of a robust estimator algorithm to estimate
343 * the best affine 3D transformation.
344 * @return an instance of affine 3D transformation estimator.
345 * @throws IllegalArgumentException if provided lists of points don't have
346 * the same size or their size is smaller than MINIMUM_SIZE.
347 */
348 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(
349 final List<Point3D> inputPoints, final List<Point3D> outputPoints, final double[] qualityScores,
350 final RobustEstimatorMethod method) {
351 return switch (method) {
352 case LMEDS -> new LMedSPointCorrespondenceAffineTransformation3DRobustEstimator(inputPoints, outputPoints);
353 case MSAC -> new MSACPointCorrespondenceAffineTransformation3DRobustEstimator(inputPoints, outputPoints);
354 case PROSAC -> new PROSACPointCorrespondenceAffineTransformation3DRobustEstimator(
355 inputPoints, outputPoints, qualityScores);
356 case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation3DRobustEstimator(
357 inputPoints, outputPoints, qualityScores);
358 default -> new RANSACPointCorrespondenceAffineTransformation3DRobustEstimator(inputPoints, outputPoints);
359 };
360 }
361
362 /**
363 * Creates an affine 3D transformation estimator based on 3D point
364 * correspondences and using provided robust estimator method.
365 *
366 * @param listener listener to be notified of events such as when estimation
367 * starts, ends or its progress significantly changes.
368 * @param qualityScores quality scores corresponding to each pair of matched
369 * points.
370 * @param method method of a robust estimator algorithm to estimate
371 * the best affine 3D transformation.
372 * @return an instance of affine 3D transformation estimator.
373 */
374 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(
375 final AffineTransformation3DRobustEstimatorListener listener, final double[] qualityScores,
376 final RobustEstimatorMethod method) {
377 return switch (method) {
378 case LMEDS -> new LMedSPointCorrespondenceAffineTransformation3DRobustEstimator(listener);
379 case MSAC -> new MSACPointCorrespondenceAffineTransformation3DRobustEstimator(listener);
380 case PROSAC -> new PROSACPointCorrespondenceAffineTransformation3DRobustEstimator(listener, qualityScores);
381 case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation3DRobustEstimator(
382 listener, qualityScores);
383 default -> new RANSACPointCorrespondenceAffineTransformation3DRobustEstimator(listener);
384 };
385 }
386
387 /**
388 * Creates an affine 3D transformation estimator based on 3D point
389 * correspondences and using provided robust estimator method.
390 *
391 * @param listener listener to be notified of events such as when estimation
392 * starts, ends or its progress significantly changes.
393 * @param inputPoints list of input points to be used to estimate an
394 * affine 3D transformation.
395 * @param outputPoints list of output points to be used to estimate an
396 * affine 3D transformation.
397 * @param qualityScores quality scores corresponding to each pair of matched
398 * points.
399 * @param method method of a robust estimator algorithm to estimate
400 * the best affine 3D transformation.
401 * @return an instance of affine 3D transformation estimator.
402 * @throws IllegalArgumentException if provided lists of points don't have
403 * the same size or their size is smaller than MINIMUM_SIZE.
404 */
405 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(
406 final AffineTransformation3DRobustEstimatorListener listener,
407 final List<Point3D> inputPoints, final List<Point3D> outputPoints, final double[] qualityScores,
408 final RobustEstimatorMethod method) {
409 return switch (method) {
410 case LMEDS -> new LMedSPointCorrespondenceAffineTransformation3DRobustEstimator(
411 listener, inputPoints, outputPoints);
412 case MSAC -> new MSACPointCorrespondenceAffineTransformation3DRobustEstimator(
413 listener, inputPoints, outputPoints);
414 case PROSAC -> new PROSACPointCorrespondenceAffineTransformation3DRobustEstimator(
415 listener, inputPoints, outputPoints, qualityScores);
416 case PROMEDS -> new PROMedSPointCorrespondenceAffineTransformation3DRobustEstimator(
417 listener, inputPoints, outputPoints, qualityScores);
418 default -> new RANSACPointCorrespondenceAffineTransformation3DRobustEstimator(
419 listener, inputPoints, outputPoints);
420 };
421 }
422
423 /**
424 * Creates an affine 3D transformation estimator based on 3D point
425 * correspondences and using default robust estimator method.
426 *
427 * @return an instance of affine 3D transformation estimator.
428 */
429 public static PointCorrespondenceAffineTransformation3DRobustEstimator create() {
430 return create(DEFAULT_ROBUST_METHOD);
431 }
432
433 /**
434 * Creates an affine 3D transformation estimator based on 3D point
435 * correspondences and using default robust estimator method.
436 *
437 * @param inputPoints list of input points to be used to estimate an
438 * affine 3D transformation.
439 * @param outputPoints list of output points to be used to estimate an
440 * affine 3D transformation.
441 * @return an instance of affine 3D transformation estimator.
442 * @throws IllegalArgumentException if provided lists of points don't have
443 * the same size or their size is smaller than MINIMUM_SIZE.
444 */
445 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(
446 final List<Point3D> inputPoints, final List<Point3D> outputPoints) {
447 return create(inputPoints, outputPoints, DEFAULT_ROBUST_METHOD);
448 }
449
450 /**
451 * Creates an affine 3D transformation estimator based on 3D point
452 * correspondences and using default robust estimator method.
453 *
454 * @param listener listener to be notified of events such as when estimation
455 * starts, ends or its progress significantly changes.
456 * @return an instance of affine 3D transformation estimator.
457 */
458 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(
459 final AffineTransformation3DRobustEstimatorListener listener) {
460 return create(listener, DEFAULT_ROBUST_METHOD);
461 }
462
463 /**
464 * Creates an affine 3D transformation estimator based on 3D point
465 * correspondences and using default robust estimator method.
466 *
467 * @param listener listener to be notified of events such as when estimation
468 * starts, ends or its progress significantly changes.
469 * @param inputPoints list of input points to be used to estimate an
470 * affine 3D transformation.
471 * @param outputPoints list of output points to be used to estimate an
472 * affine 3D transformation.
473 * @return an instance of affine 3D transformation estimator.
474 * @throws IllegalArgumentException if provided lists of points don't have
475 * the same size or their size is smaller than MINIMUM_SIZE.
476 */
477 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(
478 final AffineTransformation3DRobustEstimatorListener listener,
479 final List<Point3D> inputPoints, final List<Point3D> outputPoints) {
480 return create(listener, inputPoints, outputPoints, DEFAULT_ROBUST_METHOD);
481 }
482
483 /**
484 * Creates an affine 3D transformation estimator based on 3D point
485 * correspondences and using default robust estimator method.
486 *
487 * @param qualityScores quality scores corresponding to each pair of matched
488 * points.
489 * @return an instance of affine 3D transformation estimator.
490 */
491 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(final double[] qualityScores) {
492 return create(qualityScores, DEFAULT_ROBUST_METHOD);
493 }
494
495 /**
496 * Creates an affine 3D transformation estimator based on 3D point
497 * correspondences and using default robust estimator method.
498 *
499 * @param inputPoints list of input points to be used to estimate an
500 * affine 3D transformation.
501 * @param outputPoints list of output points to be used to estimate an
502 * affine 3D transformation.
503 * @param qualityScores quality scores corresponding to each pair of matched
504 * points.
505 * @return an instance of affine 3D transformation estimator.
506 * @throws IllegalArgumentException if provided lists of points don't have
507 * the same size or their size is smaller than MINIMUM_SIZE.
508 */
509 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(
510 final List<Point3D> inputPoints, final List<Point3D> outputPoints, final double[] qualityScores) {
511 return create(inputPoints, outputPoints, qualityScores, DEFAULT_ROBUST_METHOD);
512 }
513
514 /**
515 * Creates an affine 3D transformation estimator based on 3D point
516 * correspondences and using default robust estimator method.
517 *
518 * @param listener listener to be notified of events such as when estimation
519 * starts, ends or its progress significantly changes.
520 * @param qualityScores quality scores corresponding to each pair of matched
521 * points.
522 * @return an instance of affine 3D transformation estimator.
523 */
524 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(
525 final AffineTransformation3DRobustEstimatorListener listener, final double[] qualityScores) {
526 return create(listener, qualityScores, DEFAULT_ROBUST_METHOD);
527 }
528
529 /**
530 * Creates an affine 3D transformation estimator based on 3D point
531 * correspondences and using default robust estimator method.
532 *
533 * @param listener listener to be notified of events such as when estimation
534 * starts, ends or its progress significantly changes.
535 * @param inputPoints list of input points to be used to estimate an
536 * affine 3D transformation.
537 * @param outputPoints list of output points to be used to estimate an
538 * affine 3D transformation.
539 * @param qualityScores quality scores corresponding to each pair of matched
540 * points.
541 * @return an instance of affine 3D transformation estimator.
542 * @throws IllegalArgumentException if provided lists of points don't have
543 * the same size or their size is smaller than MINIMUM_SIZE.
544 */
545 public static PointCorrespondenceAffineTransformation3DRobustEstimator create(
546 final AffineTransformation3DRobustEstimatorListener listener, final List<Point3D> inputPoints,
547 List<Point3D> outputPoints, final double[] qualityScores) {
548 return create(listener, inputPoints, outputPoints, qualityScores, DEFAULT_ROBUST_METHOD);
549 }
550
551 /**
552 * Attempts to refine provided solution if refinement is requested.
553 * This method returns a refined solution of the same provided solution
554 * if refinement is not requested or has failed.
555 * If refinement is enabled, and it is requested to keep covariance, this
556 * method will also keep covariance of refined transformation.
557 *
558 * @param transformation transformation estimated by a robust estimator
559 * without refinement.
560 * @return solution after refinement (if requested) or the provided
561 * non-refined solution if not requested or refinement failed.
562 */
563 @SuppressWarnings("DuplicatedCode")
564 protected AffineTransformation3D attemptRefine(final AffineTransformation3D transformation) {
565 if (refineResult) {
566 final var refiner = new PointCorrespondenceAffineTransformation3DRefiner(transformation, keepCovariance,
567 getInliersData(), inputPoints, outputPoints, getRefinementStandardDeviation());
568
569 try {
570 final var result = new AffineTransformation3D();
571 final var improved = refiner.refine(result);
572
573 if (keepCovariance) {
574 // keep covariance
575 covariance = refiner.getCovariance();
576 }
577
578 return improved ? result : transformation;
579 } catch (final Exception e) {
580 // refinement failed, so we return input value
581 return transformation;
582 }
583 } else {
584 return transformation;
585 }
586 }
587
588 /**
589 * Internal method to set lists of points to be used to estimate an affine
590 * 3D transformation.
591 * This method does not check whether estimator is locked or not.
592 *
593 * @param inputPoints list of input points to be used to estimate an
594 * affine 3D transformation.
595 * @param outputPoints list of output points to be used to estimate an
596 * affine 3D transformation.
597 * @throws IllegalArgumentException if provided lists of points don't have
598 * the same size or their size is smaller than MINIMUM_SIZE.
599 */
600 private void internalSetPoints(final List<Point3D> inputPoints, final List<Point3D> outputPoints) {
601 if (inputPoints.size() < MINIMUM_SIZE) {
602 throw new IllegalArgumentException();
603 }
604 if (inputPoints.size() != outputPoints.size()) {
605 throw new IllegalArgumentException();
606 }
607 this.inputPoints = inputPoints;
608 this.outputPoints = outputPoints;
609 }
610 }