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 }