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.calibration.estimators;
17
18 import com.irurueta.ar.calibration.RadialDistortion;
19 import com.irurueta.geometry.InhomogeneousPoint2D;
20 import com.irurueta.geometry.PinholeCameraIntrinsicParameters;
21 import com.irurueta.geometry.Point2D;
22 import com.irurueta.geometry.estimators.LockedException;
23 import com.irurueta.geometry.estimators.NotReadyException;
24 import com.irurueta.numerical.robust.RobustEstimatorException;
25 import com.irurueta.numerical.robust.RobustEstimatorMethod;
26
27 import java.util.List;
28
29 /**
30 * This is an abstract class for algorithms to robustly find the best
31 * RadialDistortion for provided collections of matched distorted and
32 * undistorted 2D points.
33 * Implementations of this class should be able to detect and discard outliers
34 * in order to find the best solution
35 */
36 public abstract class RadialDistortionRobustEstimator {
37 /**
38 * Default robust estimator method when none is provided.
39 */
40 public static final RobustEstimatorMethod DEFAULT_ROBUST_METHOD = RobustEstimatorMethod.PROMEDS;
41
42 /**
43 * Default amount of progress variation before notifying a change in
44 * estimation progress. By default, this is set to 5%.
45 */
46 public static final float DEFAULT_PROGRESS_DELTA = 0.05f;
47
48 /**
49 * Minimum allowed value for progress delta.
50 */
51 public static final float MIN_PROGRESS_DELTA = 0.0f;
52
53 /**
54 * Maximum allowed value for progress delta.
55 */
56 public static final float MAX_PROGRESS_DELTA = 1.0f;
57
58 /**
59 * Constant defining default confidence of the estimated result, which is
60 * 99%. This means that with a probability of 99% estimation will be
61 * accurate because chosen sub-samples will be inliers.
62 */
63 public static final double DEFAULT_CONFIDENCE = 0.99;
64
65 /**
66 * Default maximum allowed number of iterations.
67 */
68 public static final int DEFAULT_MAX_ITERATIONS = 5000;
69
70 /**
71 * Minimum allowed confidence value.
72 */
73 public static final double MIN_CONFIDENCE = 0.0;
74
75 /**
76 * Maximum allowed confidence value.
77 */
78 public static final double MAX_CONFIDENCE = 1.0;
79
80 /**
81 * Minimum allowed number of iterations.
82 */
83 public static final int MIN_ITERATIONS = 1;
84
85 /**
86 * Minimum number of required point correspondences to estimate a radial
87 * distortion.
88 */
89 public static final int MIN_NUMBER_OF_POINTS = 2;
90
91 /**
92 * Default number of radial distortion parameters.
93 */
94 public static final int DEFAULT_NUM_K_PARAMS = 2;
95
96 /**
97 * Minimum number of radial distortion parameters.
98 */
99 public static final int MIN_K_PARAMS = 1;
100
101 /**
102 * Defines default focal length if none is defined.
103 */
104 public static final double DEFAULT_FOCAL_LENGTH = 1.0;
105
106 /**
107 * Defines default skewness if none is defined.
108 */
109 public static final double DEFAULT_SKEW = 0.0;
110
111 /**
112 * List of distorted points (aka measured points).
113 */
114 protected List<Point2D> distortedPoints;
115
116 /**
117 * List of undistorted points (aka ideal points).
118 */
119 protected List<Point2D> undistortedPoints;
120
121 /**
122 * Distortion center.
123 */
124 protected Point2D distortionCenter;
125
126 /**
127 * Horizontal focal length expressed in pixels.
128 */
129 protected double horizontalFocalLength;
130
131 /**
132 * Vertical focal length expressed in pixels.
133 */
134 protected double verticalFocalLength;
135
136 /**
137 * Skew in pixels.
138 */
139 protected double skew;
140
141 /**
142 * Number of radial distortion parameters to estimate.
143 */
144 protected int numKParams;
145
146 /**
147 * Listener to be notified of events such as when estimation starts, ends
148 * or its progress significantly changes.
149 */
150 protected RadialDistortionRobustEstimatorListener listener;
151
152 /**
153 * Indicates if this estimator is locked because an estimation is being
154 * computed.
155 */
156 protected volatile boolean locked;
157
158 /**
159 * Amount of progress variation before notifying a progress change during
160 * estimation.
161 */
162 protected float progressDelta;
163
164 /**
165 * Amount of confidence expressed as a value between 0.0 and 1.0 (which is
166 * equivalent to 100%). The amount of confidence indicates the probability
167 * that the estimated result is correct. Usually this value will be close
168 * to 1.0, but not exactly 1.0.
169 */
170 protected double confidence;
171
172 /**
173 * Maximum allowed number of iterations. When the maximum number of
174 * iterations is exceeded, result will not be available, however an
175 * approximate result will be available for retrieval.
176 */
177 protected int maxIterations;
178
179 /**
180 * Constructor.
181 */
182 protected RadialDistortionRobustEstimator() {
183 progressDelta = DEFAULT_PROGRESS_DELTA;
184 confidence = DEFAULT_CONFIDENCE;
185 maxIterations = DEFAULT_MAX_ITERATIONS;
186 horizontalFocalLength = verticalFocalLength = DEFAULT_FOCAL_LENGTH;
187 skew = DEFAULT_SKEW;
188 numKParams = DEFAULT_NUM_K_PARAMS;
189 }
190
191 /**
192 * Constructor.
193 *
194 * @param listener listener to be notified of events such as when
195 * estimation starts, ends or its progress significantly changes.
196 */
197 protected RadialDistortionRobustEstimator(final RadialDistortionRobustEstimatorListener listener) {
198 this();
199 this.listener = listener;
200 }
201
202 /**
203 * Constructor.
204 *
205 * @param distortedPoints list of distorted points. Distorted points are
206 * obtained after radial distortion is applied to an undistorted point.
207 * @param undistortedPoints list of undistorted points.
208 * @throws IllegalArgumentException if provided lists of points don't have
209 * the same size or their size is smaller than MIN_NUMBER_OF_POINTS.
210 */
211 protected RadialDistortionRobustEstimator(
212 final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints) {
213 this();
214 internalSetPoints(distortedPoints, undistortedPoints);
215 }
216
217 /**
218 * Constructor.
219 *
220 * @param distortedPoints list of distorted points. Distorted points are
221 * obtained after radial distortion is applied to an undistorted point.
222 * @param undistortedPoints list of undistorted points.
223 * @param listener listener to be notified of events such as when
224 * estimation starts, ends or its progress significantly changes.
225 * @throws IllegalArgumentException if provided lists of points don't have
226 * the same size or their size is smaller than MIN_NUMBER_OF_POINTS.
227 */
228 protected RadialDistortionRobustEstimator(
229 final List<Point2D> distortedPoints,
230 final List<Point2D> undistortedPoints,
231 final RadialDistortionRobustEstimatorListener listener) {
232 this(listener);
233 internalSetPoints(distortedPoints, undistortedPoints);
234 }
235
236 /**
237 * Constructor.
238 *
239 * @param distortedPoints list of distorted points. Distorted points are
240 * obtained after radial distortion is applied to an undistorted point.
241 * @param undistortedPoints list of undistorted points.
242 * @param distortionCenter radial distortion center. If null it is assumed
243 * to be the origin of coordinates, otherwise this is typically equal to
244 * the camera principal point.
245 * @throws IllegalArgumentException if provided lists of points don't have
246 * the same size or their size is smaller than MIN_NUMBER_OF_POINTS.
247 */
248 protected RadialDistortionRobustEstimator(
249 final List<Point2D> distortedPoints,
250 final List<Point2D> undistortedPoints,
251 final Point2D distortionCenter) {
252 this(distortedPoints, undistortedPoints);
253 this.distortionCenter = distortionCenter;
254 }
255
256 /**
257 * Constructor.
258 *
259 * @param distortedPoints list of distorted points. Distorted points are
260 * obtained after radial distortion is applied to an undistorted point.
261 * @param undistortedPoints list of undistorted points.
262 * @param distortionCenter radial distortion center. If null it is assumed
263 * to be the origin of coordinates, otherwise this is typically equal to
264 * the camera principal point.
265 * @param listener listener to be notified of events such as when
266 * estimation starts, ends or its progress significantly changes.
267 * @throws IllegalArgumentException if provided lists of points don't have
268 * the same size or their size is smaller than MIN_NUMBER_OF_POINTS.
269 */
270 protected RadialDistortionRobustEstimator(
271 final List<Point2D> distortedPoints,
272 final List<Point2D> undistortedPoints,
273 final Point2D distortionCenter,
274 final RadialDistortionRobustEstimatorListener listener) {
275 this(distortedPoints, undistortedPoints, listener);
276 this.distortionCenter = distortionCenter;
277 }
278
279 /**
280 * Returns reference to listener to be notified of events such as when
281 * estimation starts, ends or its progress significantly changes.
282 *
283 * @return listener to be notified of events.
284 */
285 public RadialDistortionRobustEstimatorListener getListener() {
286 return listener;
287 }
288
289 /**
290 * Sets listener to be notified of events such as when estimation starts,
291 * ends or its progress significantly changes.
292 *
293 * @param listener listener to be notified of events.
294 * @throws LockedException if robust estimator is locked.
295 */
296 public void setListener(final RadialDistortionRobustEstimatorListener listener) throws LockedException {
297 if (isLocked()) {
298 throw new LockedException();
299 }
300 this.listener = listener;
301 }
302
303 /**
304 * Indicates whether listener has been provided and is available for
305 * retrieval.
306 *
307 * @return true if available, false otherwise.
308 */
309 public boolean isListenerAvailable() {
310 return listener != null;
311 }
312
313 /**
314 * Indicates if this instance is locked because estimation is being computed.
315 *
316 * @return true if locked, false otherwise.
317 */
318 public boolean isLocked() {
319 return locked;
320 }
321
322 /**
323 * Returns amount of progress variation before notifying a progress change
324 * during estimation.
325 *
326 * @return amount of progress variation before notifying a progress change
327 * during estimation.
328 */
329 public float getProgressDelta() {
330 return progressDelta;
331 }
332
333 /**
334 * Sets amount of progress variation before notifying a progress change
335 * during estimation.
336 *
337 * @param progressDelta amount of progress variation before notifying a
338 * progress change during estimation.
339 * @throws IllegalArgumentException if progress delta is less than zero or
340 * greater than 1.
341 * @throws LockedException if this estimator is locked because an estimation
342 * is being computed.
343 */
344 public void setProgressDelta(final float progressDelta) throws LockedException {
345 if (isLocked()) {
346 throw new LockedException();
347 }
348 if (progressDelta < MIN_PROGRESS_DELTA || progressDelta > MAX_PROGRESS_DELTA) {
349 throw new IllegalArgumentException();
350 }
351 this.progressDelta = progressDelta;
352 }
353
354 /**
355 * Returns amount of confidence expressed as a value between 0.0 and 1.0
356 * (which is equivalent to 100%). The amount of confidence indicates the
357 * probability that the estimated result is correct. Usually this value will
358 * be close to 1.0, but not exactly 1.0.
359 *
360 * @return amount of confidence as a value between 0.0 and 1.0.
361 */
362 public double getConfidence() {
363 return confidence;
364 }
365
366 /**
367 * Sets amount of confidence expressed as a value between 0.0 and 1.0 (which
368 * is equivalent to 100%). The amount of confidence indicates the
369 * probability that the estimated result is correct. Usually this value will
370 * be close to 1.0, but not exactly 1.0.
371 *
372 * @param confidence confidence to be set as a value between 0.0 and 1.0.
373 * @throws IllegalArgumentException if provided value is not between 0.0 and
374 * 1.0.
375 * @throws LockedException if this estimator is locked because an estimator
376 * is being computed.
377 */
378 public void setConfidence(final double confidence) throws LockedException {
379 if (isLocked()) {
380 throw new LockedException();
381 }
382 if (confidence < MIN_CONFIDENCE || confidence > MAX_CONFIDENCE) {
383 throw new IllegalArgumentException();
384 }
385 this.confidence = confidence;
386 }
387
388 /**
389 * Returns maximum allowed number of iterations. If maximum allowed number
390 * of iterations is achieved without converging to a result when calling
391 * estimate(), a RobustEstimatorException will be raised.
392 *
393 * @return maximum allowed number of iterations.
394 */
395 public int getMaxIterations() {
396 return maxIterations;
397 }
398
399 /**
400 * Sets maximum allowed number of iterations. When the maximum number of
401 * iterations is exceeded, result will not be available, however an
402 * approximate result will be available for retrieval
403 *
404 * @param maxIterations maximum allowed number of iterations to be set.
405 * @throws IllegalArgumentException if provided value is less than 1.
406 * @throws LockedException if this estimator is locked because an estimation
407 * is being computed.
408 */
409 public void setMaxIterations(final int maxIterations) throws LockedException {
410 if (isLocked()) {
411 throw new LockedException();
412 }
413 if (maxIterations < MIN_ITERATIONS) {
414 throw new IllegalArgumentException();
415 }
416 this.maxIterations = maxIterations;
417 }
418
419 /**
420 * Sets list of corresponding distorted and undistorted points.
421 *
422 * @param distortedPoints list of distorted points. Distorted points are
423 * obtained after radial distortion is applied to an undistorted point.
424 * @param undistortedPoints list of undistorted points.
425 * @throws LockedException if estimator is locked.
426 * @throws IllegalArgumentException if provided lists of points don't have
427 * the same size.
428 */
429 public void setPoints(final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints)
430 throws LockedException {
431 if (isLocked()) {
432 throw new LockedException();
433 }
434
435 internalSetPoints(distortedPoints, undistortedPoints);
436 }
437
438 /**
439 * Returns list of distorted points. Distorted points are obtained after
440 * radial distortion is applied to an undistorted point.
441 *
442 * @return list of distorted points.
443 */
444 public List<Point2D> getDistortedPoints() {
445 return distortedPoints;
446 }
447
448 /**
449 * Returns list of undistorted points.
450 *
451 * @return list of undistorted points.
452 */
453 public List<Point2D> getUndistortedPoints() {
454 return undistortedPoints;
455 }
456
457 /**
458 * Returns distortion center. This is usually equal to the principal point
459 * of an estimated camera. If not set it is assumed to be at the origin of
460 * coordinates (0,0).
461 *
462 * @return distortion center or null.
463 */
464 public Point2D getDistortionCenter() {
465 return distortionCenter;
466 }
467
468 /**
469 * Sets distortion center. This is usually equal to the principal point of
470 * an estimated camera. If not set it is assumed to be at the origin of
471 * coordinates (0,0).
472 *
473 * @param distortionCenter distortion center, or null if set at origin of
474 * coordinates.
475 * @throws LockedException if estimator is locked.
476 */
477 public void setDistortionCenter(final Point2D distortionCenter) throws LockedException {
478 if (isLocked()) {
479 throw new LockedException();
480 }
481
482 this.distortionCenter = distortionCenter;
483 }
484
485 /**
486 * Returns horizontal focal length expressed in pixels.
487 *
488 * @return horizontal focal length expressed in pixels.
489 */
490 public double getHorizontalFocalLength() {
491 return horizontalFocalLength;
492 }
493
494 /**
495 * Sets horizontal focal length expressed in pixels.
496 *
497 * @param horizontalFocalLength horizontal focal length expressed in pixels.
498 * @throws LockedException if estimator is locked.
499 */
500 public void setHorizontalFocalLength(final double horizontalFocalLength) throws LockedException {
501 if (isLocked()) {
502 throw new LockedException();
503 }
504
505 this.horizontalFocalLength = horizontalFocalLength;
506 }
507
508 /**
509 * Returns vertical focal length expressed in pixels.
510 *
511 * @return vertical focal length expressed in pixels.
512 */
513 public double getVerticalFocalLength() {
514 return verticalFocalLength;
515 }
516
517 /**
518 * Sets vertical focal length expressed in pixels.
519 *
520 * @param verticalFocalLength vertical focal length expressed in pixels.
521 * @throws LockedException if estimator is locked.
522 */
523 public void setVerticalFocalLength(final double verticalFocalLength) throws LockedException {
524 if (isLocked()) {
525 throw new LockedException();
526 }
527
528 this.verticalFocalLength = verticalFocalLength;
529 }
530
531 /**
532 * Returns skew expressed in pixels.
533 *
534 * @return skew expressed in pixels.
535 */
536 public double getSkew() {
537 return skew;
538 }
539
540 /**
541 * Sets skew expressed in pixels.
542 *
543 * @param skew skew expressed in pixels.
544 * @throws LockedException if estimator is locked.
545 */
546 public void setSkew(final double skew) throws LockedException {
547 if (isLocked()) {
548 throw new LockedException();
549 }
550
551 this.skew = skew;
552 }
553
554 /**
555 * Returns pinhole camera intrinsic parameters associated to this estimator.
556 *
557 * @return pinhole camera intrinsic parameters associated to this estimator.
558 */
559 public PinholeCameraIntrinsicParameters getIntrinsic() {
560 return new PinholeCameraIntrinsicParameters(horizontalFocalLength,
561 verticalFocalLength,
562 distortionCenter != null ? distortionCenter.getInhomX() : 0.0,
563 distortionCenter != null ? distortionCenter.getInhomY() : 0.0,
564 skew);
565 }
566
567 /**
568 * Sets intrinsic parameters for this estimator from pinhole camera
569 * intrinsic parameters.
570 *
571 * @param intrinsic intrinsic parameters.
572 * @throws LockedException if estimator is locked.
573 */
574 public void setIntrinsic(final PinholeCameraIntrinsicParameters intrinsic)
575 throws LockedException {
576 setIntrinsic(new InhomogeneousPoint2D(
577 intrinsic.getHorizontalPrincipalPoint(), intrinsic.getVerticalPrincipalPoint()),
578 intrinsic.getHorizontalFocalLength(),
579 intrinsic.getVerticalFocalLength(),
580 intrinsic.getSkewness());
581 }
582
583 /**
584 * Sets intrinsic parameters for this estimator.
585 *
586 * @param distortionCenter distortion center.
587 * @param horizontalFocalLength horizontal focal length in pixels.
588 * @param verticalFocalLength vertical focal length in pixels.
589 * @param skew skew in pixels.
590 * @throws LockedException if estimator is locked.
591 */
592 public void setIntrinsic(
593 final Point2D distortionCenter, final double horizontalFocalLength, final double verticalFocalLength,
594 final double skew) throws LockedException {
595 if (isLocked()) {
596 throw new LockedException();
597 }
598
599 this.distortionCenter = distortionCenter;
600 this.horizontalFocalLength = horizontalFocalLength;
601 this.verticalFocalLength = verticalFocalLength;
602 this.skew = skew;
603 }
604
605 /**
606 * Returns number of radial distortion parameters to estimate.
607 *
608 * @return number of radial distortion parameters to estimate.
609 */
610 public int getNumKParams() {
611 return numKParams;
612 }
613
614 /**
615 * Sets number of radial distortion parameters to estimate.
616 *
617 * @param numKParams number of radial distortion parameters to estimate.
618 * @throws LockedException if estimator is locked.
619 * @throws IllegalArgumentException if number of parameters is less than 1.
620 */
621 public void setNumKParams(final int numKParams) throws LockedException {
622 if (isLocked()) {
623 throw new LockedException();
624 }
625 if (numKParams < MIN_K_PARAMS) {
626 throw new IllegalArgumentException();
627 }
628
629 this.numKParams = numKParams;
630 }
631
632 /**
633 * Indicates if lists of corresponding points have already been provided and
634 * are available for retrieval.
635 *
636 * @return true if available, false otherwise.
637 */
638 public boolean arePointsAvailable() {
639 return distortedPoints != null && undistortedPoints != null;
640 }
641
642 /**
643 * Indicates if this estimator is ready to start th estimation.
644 * This is true when lists of points are provided, having equal size and
645 * at least 2 points.
646 *
647 * @return true if estimator is ready, false otherwise.
648 */
649 public boolean isReady() {
650 return arePointsAvailable() && areValidPoints(distortedPoints, undistortedPoints);
651 }
652
653 /**
654 * Returns quality scores corresponding to each point.
655 * The larger the score value the better the quality of the point measure.
656 * This implementation always returns null.
657 * Subclasses using quality scores must implement proper behaviour.
658 *
659 * @return quality scores corresponding to each point.
660 */
661 public double[] getQualityScores() {
662 return null;
663 }
664
665 /**
666 * Sets quality scores corresponding to each point.
667 * The larger the score value the better the quality of the point sample.
668 * This implementation makes no action.
669 * Subclasses using quality scores must implement proper behaviour.
670 *
671 * @param qualityScores quality scores corresponding to each sampled point.
672 * @throws LockedException if robust estimator is locked because an
673 * estimation is already in progress.
674 * @throws IllegalArgumentException if provided quality scores length is
675 * smaller than MINIMUM_SIZE (i.e. 3 samples).
676 */
677 public void setQualityScores(final double[] qualityScores) throws LockedException {
678 }
679
680 /**
681 * Estimates a radial distortion using a robust estimator and
682 * the best set of matched 2D points found using the robust estimator.
683 *
684 * @return a radial distortion.
685 * @throws LockedException if robust estimator is locked because an
686 * estimation is already in progress.
687 * @throws NotReadyException if provided input data is not enough to start
688 * the estimation.
689 * @throws RobustEstimatorException if estimation fails for any reason
690 * (i.e. numerical instability, no solution available, etc).
691 */
692 public abstract RadialDistortion estimate() throws LockedException, NotReadyException, RobustEstimatorException;
693
694 /**
695 * Returns method being used for robust estimation.
696 *
697 * @return method being used for robust estimation.
698 */
699 public abstract RobustEstimatorMethod getMethod();
700
701 /**
702 * Creates a radial distortion robust estimator using provided robust method.
703 *
704 * @param method method of a robust estimator algorithm to estimate the best
705 * radial distortion.
706 * @return an instance of a radial distortion robust estimator.
707 */
708 public static RadialDistortionRobustEstimator create(
709 final RobustEstimatorMethod method) {
710 return switch (method) {
711 case LMEDS -> new LMedSRadialDistortionRobustEstimator();
712 case MSAC -> new MSACRadialDistortionRobustEstimator();
713 case PROSAC -> new PROSACRadialDistortionRobustEstimator();
714 case PROMEDS -> new PROMedSRadialDistortionRobustEstimator();
715 default -> new RANSACRadialDistortionRobustEstimator();
716 };
717 }
718
719 /**
720 * Creates a radial distortion robust estimator using provided distorted and
721 * undistorted points, as well as the distortion center. If no distortion
722 * center is provided, it is assumed to be at the origin of coordinates.
723 *
724 * @param distortedPoints list of distorted points. Distorted points are
725 * obtained after radial distortion is applied to an undistorted point.
726 * @param undistortedPoints list of undistorted points.
727 * @param qualityScores quality scores corresponding to each point.
728 * @param distortionCenter Distortion center. This is usually equal to the
729 * principal point of an estimated camera. If not set it is assumed to be at
730 * the origin of coordinates (0,0).
731 * @param method method of a robust estimator algorithm to estimate the best
732 * radial distortion.
733 * @return an instance of a radial distortion robust estimator.
734 * @throws IllegalArgumentException if provided lists of points don't have
735 * the same size.
736 */
737 public static RadialDistortionRobustEstimator create(
738 final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints, final double[] qualityScores,
739 final Point2D distortionCenter, final RobustEstimatorMethod method) {
740 return switch (method) {
741 case LMEDS -> new LMedSRadialDistortionRobustEstimator(distortedPoints, undistortedPoints,
742 distortionCenter);
743 case MSAC -> new MSACRadialDistortionRobustEstimator(distortedPoints, undistortedPoints, distortionCenter);
744 case PROSAC -> new PROSACRadialDistortionRobustEstimator(distortedPoints, undistortedPoints, qualityScores,
745 distortionCenter);
746 case PROMEDS -> new PROMedSRadialDistortionRobustEstimator(distortedPoints, undistortedPoints,
747 qualityScores, distortionCenter);
748 default -> new RANSACRadialDistortionRobustEstimator(distortedPoints, undistortedPoints, distortionCenter);
749 };
750 }
751
752 /**
753 * Creates a radial distortion robust estimator using provided distorted and
754 * undistorted points, as well as the distortion center. If no distortion
755 * center is provided, it is assumed to be at the origin of coordinates.
756 *
757 * @param distortedPoints list of distorted points. Distorted points are
758 * obtained after radial distortion is applied to an undistorted point.
759 * @param undistortedPoints list of undistorted points.
760 * @param distortionCenter Distortion center. This is usually equal to the
761 * principal point of an estimated camera. If not set it is assumed to be at
762 * the origin of coordinates (0,0).
763 * @param method method of a robust estimator algorithm to estimate the best
764 * radial distortion.
765 * @return an instance of a radial distortion robust estimator.
766 * @throws IllegalArgumentException if provided lists of points don't have
767 * the same size.
768 */
769 public static RadialDistortionRobustEstimator create(
770 final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints, final Point2D distortionCenter,
771 final RobustEstimatorMethod method) {
772 return switch (method) {
773 case LMEDS -> new LMedSRadialDistortionRobustEstimator(distortedPoints, undistortedPoints,
774 distortionCenter);
775 case MSAC -> new MSACRadialDistortionRobustEstimator(distortedPoints, undistortedPoints, distortionCenter);
776 case PROSAC -> new PROSACRadialDistortionRobustEstimator(distortedPoints, undistortedPoints,
777 distortionCenter);
778 case PROMEDS -> new PROMedSRadialDistortionRobustEstimator(distortedPoints, undistortedPoints,
779 distortionCenter);
780 default -> new RANSACRadialDistortionRobustEstimator(distortedPoints, undistortedPoints, distortionCenter);
781 };
782 }
783
784 /**
785 * Creates a radial distortion robust estimator using provided distorted and
786 * undistorted points and assuming that distortion center is at origin of
787 * coordinates.
788 *
789 * @param distortedPoints list of distorted points. Distorted points are
790 * obtained after radial distortion is applied to an undistorted point.
791 * @param undistortedPoints list of undistorted points.
792 * @param qualityScores quality scores corresponding to each point.
793 * @param method method of a robust estimator algorithm to estimate the best
794 * radial distortion.
795 * @return an instance of a radial distortion robust estimator.
796 * @throws IllegalArgumentException if provided lists of points don't have
797 * the same size.
798 */
799 public static RadialDistortionRobustEstimator create(
800 final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints, final double[] qualityScores,
801 final RobustEstimatorMethod method) {
802 return create(distortedPoints, undistortedPoints, qualityScores, null, method);
803 }
804
805 /**
806 * Creates a radial distortion robust estimator using provided distorted and
807 * undistorted points and assuming that distortion center is at origin of
808 * coordinates.
809 *
810 * @param distortedPoints list of distorted points. Distorted points are
811 * obtained after radial distortion is applied to an undistorted point.
812 * @param undistortedPoints list of undistorted points.
813 * @param method method of a robust estimator algorithm to estimate the best
814 * radial distortion.
815 * @return an instance of a radial distortion robust estimator.
816 * @throws IllegalArgumentException if provided lists of points don't have
817 * the same size.
818 */
819 public static RadialDistortionRobustEstimator create(
820 final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints,
821 final RobustEstimatorMethod method) {
822 return create(distortedPoints, undistortedPoints, (Point2D) null, method);
823 }
824
825 /**
826 * Creates a radial distortion robust estimator using default robust method.
827 *
828 * @return an instance of a radial distortion robust estimator.
829 */
830 public static RadialDistortionRobustEstimator create() {
831 return create(DEFAULT_ROBUST_METHOD);
832 }
833
834
835 /**
836 * Creates a radial distortion robust estimator using provided distorted and
837 * undistorted points assuming that distortion center is at origin of
838 * coordinates and using default robust estimation method.
839 *
840 * @param distortedPoints list of distorted points. Distorted points are
841 * obtained after radial distortion is applied to an undistorted point.
842 * @param undistortedPoints list of undistorted points.
843 * @param qualityScores quality scores corresponding to each point
844 * @return an instance of a radial distortion robust estimator.
845 * @throws IllegalArgumentException if provided lists of points don't have
846 * the same size.
847 */
848 public static RadialDistortionRobustEstimator create(
849 final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints, final double[] qualityScores) {
850 return create(distortedPoints, undistortedPoints, qualityScores, DEFAULT_ROBUST_METHOD);
851 }
852
853 /**
854 * Creates a radial distortion robust estimator using provided distorted and
855 * undistorted points assuming that distortion center is at origin of
856 * coordinates and using default robust estimation method.
857 *
858 * @param distortedPoints list of distorted points. Distorted points are
859 * obtained after radial distortion is applied to an undistorted point.
860 * @param undistortedPoints list of undistorted points.
861 * @return an instance of a radial distortion robust estimator.
862 * @throws IllegalArgumentException if provided lists of points don't have
863 * the same size.
864 */
865 public static RadialDistortionRobustEstimator create(
866 final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints) {
867 return create(distortedPoints, undistortedPoints, DEFAULT_ROBUST_METHOD);
868 }
869
870 /**
871 * Creates a radial distortion robust estimator using provided distorted and
872 * undistorted points, as well as the distortion center using the default
873 * robust estimation method. If no distortion center is provided, it is
874 * assumed to be at the origin of coordinates.
875 *
876 * @param distortedPoints list of distorted points. Distorted points are
877 * obtained after radial distortion is applied to an undistorted point.
878 * @param undistortedPoints list of undistorted points.
879 * @param qualityScores quality scores corresponding to each point.
880 * @param distortionCenter Distortion center. This is usually equal to the
881 * principal point of an estimated camera. If not set it is assumed to be at
882 * the origin of coordinates (0,0).
883 * @return an instance of a radial distortion robust estimator.
884 * @throws IllegalArgumentException if provided lists of points don't have
885 * the same size.
886 */
887 public static RadialDistortionRobustEstimator create(
888 final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints, final double[] qualityScores,
889 final Point2D distortionCenter) {
890 return create(distortedPoints, undistortedPoints, qualityScores, distortionCenter, DEFAULT_ROBUST_METHOD);
891 }
892
893 /**
894 * Creates a radial distortion robust estimator using provided distorted and
895 * undistorted points, as well as the distortion center using the default
896 * robust estimation method. If no distortion center is provided, it is
897 * assumed to be at the origin of coordinates.
898 *
899 * @param distortedPoints list of distorted points. Distorted points are
900 * obtained after radial distortion is applied to an undistorted point.
901 * @param undistortedPoints list of undistorted points.
902 * @param distortionCenter Distortion center. This is usually equal to the
903 * principal point of an estimated camera. If not set it is assumed to be at
904 * the origin of coordinates (0,0).
905 * @return an instance of a radial distortion robust estimator.
906 * @throws IllegalArgumentException if provided lists of points don't have
907 * the same size.
908 */
909 public static RadialDistortionRobustEstimator create(
910 final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints,
911 final Point2D distortionCenter) {
912 return create(distortedPoints, undistortedPoints, distortionCenter, DEFAULT_ROBUST_METHOD);
913 }
914
915 /**
916 * Indicates if lists of corresponding distorted and undistorted points are
917 * valid.
918 * Lists are considered valid if they have the same number of points and
919 * both have more than the required minimum of correspondences (which is 2).
920 *
921 * @param distortedPoints list of distorted points. Distorted points are
922 * obtained after radial distortion is applied to an undistorted point.
923 * @param undistortedPoints list of undistorted points.
924 * @return true if lists of points are valid, false otherwise.
925 */
926 public static boolean areValidPoints(final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints) {
927 if (distortedPoints == null || undistortedPoints == null) {
928 return false;
929 }
930 return distortedPoints.size() == undistortedPoints.size() && distortedPoints.size() >= MIN_NUMBER_OF_POINTS;
931 }
932
933 /**
934 * Sets list of corresponding distorted and undistorted points.
935 * This method does not check whether estimator is locked.
936 *
937 * @param distortedPoints list of distorted points. Distorted points are
938 * obtained after radial distortion is applied to an undistorted point.
939 * @param undistortedPoints list of undistorted points.
940 * @throws IllegalArgumentException if provided lists of points don't have
941 * the same size.
942 */
943 private void internalSetPoints(final List<Point2D> distortedPoints, final List<Point2D> undistortedPoints) {
944
945 if (distortedPoints == null || undistortedPoints == null) {
946 throw new IllegalArgumentException();
947 }
948
949 if (!areValidPoints(distortedPoints, undistortedPoints)) {
950 throw new IllegalArgumentException();
951 }
952
953 this.distortedPoints = distortedPoints;
954 this.undistortedPoints = undistortedPoints;
955 }
956 }