1 /* 2 * Copyright (C) 2015 Alberto Irurueta Carro (alberto@irurueta.com) 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.irurueta.ar.epipolar; 17 18 import com.irurueta.geometry.Point2D; 19 import com.irurueta.geometry.estimators.LockedException; 20 import com.irurueta.geometry.estimators.NotReadyException; 21 22 import java.util.List; 23 24 /** 25 * Fixes matched pairs of points so that they perfectly follow a given epipolar 26 * geometry. 27 * When matching points typically the matching precision is about 1 pixel, 28 * however this makes that matched points under a given epipolar geometry (i.e. 29 * fundamental or essential matrix), do not lie perfectly on the corresponding 30 * epipolar plane or epipolar lines. 31 * The consequence is that triangularization of these matches will fail or 32 * produce inaccurate results. 33 * By fixing matched points using a corrector following a given epipolar 34 * geometry, this effect is alleviated. 35 * This is an abstract class, subclasses will implement different methods to 36 * fix matched points coordinates. 37 */ 38 public abstract class Corrector { 39 40 /** 41 * Default corrector type. 42 */ 43 public static final CorrectorType DEFAULT_TYPE = CorrectorType.SAMPSON_CORRECTOR; 44 45 /** 46 * Default amount of progress variation before notifying a change in 47 * estimation progress. By default, this is set to 5%. 48 */ 49 public static final float DEFAULT_PROGRESS_DELTA = 0.05f; 50 51 /** 52 * Minimum allowed value for progress delta. 53 */ 54 public static final float MIN_PROGRESS_DELTA = 0.0f; 55 56 /** 57 * Maximum allowed value for progress delta. 58 */ 59 public static final float MAX_PROGRESS_DELTA = 1.0f; 60 61 /** 62 * A fundamental matrix defining an epipolar geometry. 63 */ 64 protected FundamentalMatrix fundamentalMatrix; 65 66 /** 67 * List of points on left view to be corrected. 68 */ 69 protected List<Point2D> leftPoints; 70 71 /** 72 * List of points on right view to be corrected. 73 */ 74 protected List<Point2D> rightPoints; 75 76 /** 77 * List of points on left view after correction. 78 */ 79 protected List<Point2D> leftCorrectedPoints; 80 81 /** 82 * List of points on right view after correction. 83 */ 84 protected List<Point2D> rightCorrectedPoints; 85 86 /** 87 * Listener to notify start, stop and progress events. 88 */ 89 protected CorrectorListener listener; 90 91 /** 92 * Indicates whether this instance is locked or not while doing computations. 93 */ 94 protected boolean locked; 95 96 /** 97 * Amount of progress variation before notifying a progress change during 98 * estimation. 99 */ 100 protected float progressDelta; 101 102 /** 103 * Constructor. 104 */ 105 protected Corrector() { 106 progressDelta = DEFAULT_PROGRESS_DELTA; 107 } 108 109 /** 110 * Constructor. 111 * 112 * @param fundamentalMatrix fundamental matrix to be set. 113 */ 114 protected Corrector(final FundamentalMatrix fundamentalMatrix) { 115 this(); 116 internalSetFundamentalMatrix(fundamentalMatrix); 117 } 118 119 /** 120 * Constructor. 121 * 122 * @param leftPoints points to be corrected on left view. 123 * @param rightPoints points to be corrected on right view. 124 * @throws IllegalArgumentException if provided lists of points don't have 125 * the same size. 126 */ 127 protected Corrector(final List<Point2D> leftPoints, final List<Point2D> rightPoints) { 128 this(); 129 internalSetLeftAndRightPoints(leftPoints, rightPoints); 130 } 131 132 /** 133 * Constructor. 134 * 135 * @param leftPoints points to be corrected on left view. 136 * @param rightPoints points to be corrected on right view. 137 * @param fundamentalMatrix fundamental matrix to be set. 138 * @throws IllegalArgumentException if provided lists of points don't have 139 * the same size. 140 */ 141 protected Corrector(final List<Point2D> leftPoints, final List<Point2D> rightPoints, 142 final FundamentalMatrix fundamentalMatrix) { 143 this(); 144 internalSetLeftAndRightPoints(leftPoints, rightPoints); 145 internalSetFundamentalMatrix(fundamentalMatrix); 146 } 147 148 /** 149 * Constructor. 150 * 151 * @param listener listener to handle events generated by this class. 152 */ 153 protected Corrector(final CorrectorListener listener) { 154 this(); 155 this.listener = listener; 156 } 157 158 /** 159 * Constructor. 160 * 161 * @param fundamentalMatrix fundamental matrix to be set. 162 * @param listener listener to handle events generated by this class. 163 */ 164 protected Corrector(final FundamentalMatrix fundamentalMatrix, final CorrectorListener listener) { 165 this(fundamentalMatrix); 166 this.listener = listener; 167 } 168 169 /** 170 * Constructor. 171 * 172 * @param leftPoints points to be corrected on left view. 173 * @param rightPoints points to be corrected on right view. 174 * @param listener listener to handle events generated by this class. 175 * @throws IllegalArgumentException if provided lists of points don't have 176 * the same size. 177 */ 178 protected Corrector(final List<Point2D> leftPoints, final List<Point2D> rightPoints, 179 final CorrectorListener listener) { 180 this(leftPoints, rightPoints); 181 this.listener = listener; 182 } 183 184 /** 185 * Constructor. 186 * 187 * @param leftPoints points to be corrected on left view. 188 * @param rightPoints points to be corrected on right view. 189 * @param fundamentalMatrix fundamental matrix to be set. 190 * @param listener listener to handle events generated by this class. 191 * @throws IllegalArgumentException if provided lists of points don't have 192 * the same size. 193 */ 194 protected Corrector(final List<Point2D> leftPoints, final List<Point2D> rightPoints, 195 final FundamentalMatrix fundamentalMatrix, final CorrectorListener listener) { 196 this(leftPoints, rightPoints, fundamentalMatrix); 197 this.listener = listener; 198 } 199 200 /** 201 * Sets the fundamental matrix defining the epipolar geometry. 202 * 203 * @param fundamentalMatrix fundamental matrix to be set. 204 * @throws LockedException if this instance is locked. 205 */ 206 public final void setFundamentalMatrix(final FundamentalMatrix fundamentalMatrix) throws LockedException { 207 if (isLocked()) { 208 throw new LockedException(); 209 } 210 internalSetFundamentalMatrix(fundamentalMatrix); 211 } 212 213 /** 214 * Returns fundamental matrix defining epipolar geometry. 215 * 216 * @return fundamental matrix defining epipolar geometry. 217 */ 218 public FundamentalMatrix getFundamentalMatrix() { 219 return fundamentalMatrix; 220 } 221 222 /** 223 * Returns list of points to be corrected on left view. 224 * 225 * @return list of points to be corrected on left view. 226 */ 227 public List<Point2D> getLeftPoints() { 228 return leftPoints; 229 } 230 231 /** 232 * Returns list of points to be corrected on right view. 233 * 234 * @return list of points to be corrected on right view. 235 */ 236 public List<Point2D> getRightPoints() { 237 return rightPoints; 238 } 239 240 /** 241 * Sets lists of points to be corrected on left and right views. 242 * 243 * @param leftPoints points to be corrected on left view. 244 * @param rightPoints points to be corrected on right view. 245 * @throws IllegalArgumentException if provided lists of points don't have 246 * the same size. 247 * @throws LockedException if instance is locked doing computations. 248 */ 249 public void setLeftAndRightPoints(final List<Point2D> leftPoints, final List<Point2D> rightPoints) 250 throws LockedException { 251 if (isLocked()) { 252 throw new LockedException(); 253 } 254 internalSetLeftAndRightPoints(leftPoints, rightPoints); 255 } 256 257 /** 258 * Sets lists of points to be corrected on left and right views and 259 * fundamental matrix defining epipolar geometry. 260 * 261 * @param leftPoints points to be corrected on left view. 262 * @param rightPoints points to be corrected on right view. 263 * @param fundamentalMatrix fundamental matrix to be set. 264 * @throws IllegalArgumentException if provided lists of points don't have 265 * the same size. 266 * @throws LockedException if instance is locked doing computations. 267 */ 268 public void setPointsAndFundamentalMatrix( 269 final List<Point2D> leftPoints, final List<Point2D> rightPoints, final FundamentalMatrix fundamentalMatrix) 270 throws LockedException { 271 if (isLocked()) { 272 throw new LockedException(); 273 } 274 internalSetFundamentalMatrix(fundamentalMatrix); 275 internalSetLeftAndRightPoints(leftPoints, rightPoints); 276 } 277 278 /** 279 * Returns list of points on left view obtained after correction. 280 * 281 * @return list of points on left view obtained after correction. 282 */ 283 public List<Point2D> getLeftCorrectedPoints() { 284 return leftCorrectedPoints; 285 } 286 287 /** 288 * Returns list of points on right view obtained after correction. 289 * 290 * @return list of points on right view obtained after correction. 291 */ 292 public List<Point2D> getRightCorrectedPoints() { 293 return rightCorrectedPoints; 294 } 295 296 /** 297 * Returns boolean indicating whether this instance is locked or not doing 298 * computations. 299 * 300 * @return true if instance is locked, false otherwise. 301 */ 302 public boolean isLocked() { 303 return locked; 304 } 305 306 /** 307 * Returns amount of progress variation before notifying a progress change 308 * during estimation. 309 * 310 * @return amount of progress variation before notifying a progress change 311 * during estimation. 312 */ 313 public float getProgressDelta() { 314 return progressDelta; 315 } 316 317 /** 318 * Sets amount of progress variation before notifying a progress change 319 * during estimation. 320 * 321 * @param progressDelta amount of progress variation before notifying a 322 * progress change during estimation. 323 * @throws IllegalArgumentException if progress delta is less than zero or 324 * greater than 1. 325 * @throws LockedException if this estimator is locked because an estimation 326 * is being computed. 327 */ 328 public void setProgressDelta(final float progressDelta) throws LockedException { 329 if (isLocked()) { 330 throw new LockedException(); 331 } 332 if (progressDelta < MIN_PROGRESS_DELTA || progressDelta > MAX_PROGRESS_DELTA) { 333 throw new IllegalArgumentException(); 334 } 335 this.progressDelta = progressDelta; 336 } 337 338 /** 339 * Returns listener to handle events generated by this class. 340 * 341 * @return listener to handle events generated by this class. 342 */ 343 public CorrectorListener getListener() { 344 return listener; 345 } 346 347 /** 348 * Sets listener to handle events generated by this class. 349 * 350 * @param listener listener to handle events generated by this class. 351 * @throws LockedException if this estimator is locked because an estimation 352 * is being computed. 353 */ 354 public void setListener(final CorrectorListener listener) throws LockedException { 355 if (isLocked()) { 356 throw new LockedException(); 357 } 358 this.listener = listener; 359 } 360 361 /** 362 * Indicates whether provided lists of points to be corrected on left and 363 * right views are valid. 364 * Lists are valid when both have the same size. 365 * 366 * @param leftPoints points to be corrected on left view. 367 * @param rightPoints points to be corrected on right view. 368 * @return true if lists of points are valid, false otherwise. 369 */ 370 public static boolean areValidPoints(final List<Point2D> leftPoints, final List<Point2D> rightPoints) { 371 return leftPoints != null && rightPoints != null && leftPoints.size() == rightPoints.size(); 372 } 373 374 /** 375 * Indicates whether this instance is ready to correct provided left 376 * and right points using provided fundamental matrix. 377 * 378 * @return true if ready, false otherwise. 379 */ 380 public boolean isReady() { 381 return areValidPoints(leftPoints, rightPoints) && fundamentalMatrix != null 382 && fundamentalMatrix.isInternalMatrixAvailable(); 383 } 384 385 /** 386 * Corrects the lists of provided matched points to be corrected. 387 * 388 * @throws NotReadyException if this instance is not ready (either points or 389 * fundamental matrix has not been provided yet). 390 * @throws LockedException if this instance is locked doing computations. 391 * @throws CorrectionException if correction fails. 392 */ 393 public abstract void correct() throws NotReadyException, LockedException, CorrectionException; 394 395 /** 396 * Gets type of correction being used. 397 * 398 * @return type of correction. 399 */ 400 public abstract CorrectorType getType(); 401 402 /** 403 * Creates an instance of a corrector using provided type. 404 * 405 * @param type a corrector type. 406 * @return an instance of a corrector. 407 */ 408 public static Corrector create(final CorrectorType type) { 409 return create((CorrectorListener) null, type); 410 } 411 412 /** 413 * Creates an instance of a corrector using provided fundamental matrix 414 * and provided type. 415 * 416 * @param fundamentalMatrix fundamental matrix defining the epipolar 417 * geometry. 418 * @param type a corrector type. 419 * @return an instance of a corrector. 420 */ 421 public static Corrector create(final FundamentalMatrix fundamentalMatrix, final CorrectorType type) { 422 return create(fundamentalMatrix, null, type); 423 } 424 425 /** 426 * Creates an instance of a corrector using provided left and right points 427 * to be corrected and provided type. 428 * 429 * @param leftPoints matched points on left view to be corrected. 430 * @param rightPoints matched points on right view to be corrected. 431 * @param type a corrector type. 432 * @return an instance of a corrector. 433 */ 434 public static Corrector create( 435 final List<Point2D> leftPoints, final List<Point2D> rightPoints, final CorrectorType type) { 436 return create(leftPoints, rightPoints, (CorrectorListener) null, type); 437 } 438 439 /** 440 * Creates an instance of a corrector using provided left and right points 441 * to be corrected, provided fundamental matrix and provided type. 442 * 443 * @param leftPoints matched points on left view to be corrected. 444 * @param rightPoints matched points on right view to be corrected. 445 * @param fundamentalMatrix fundamental matrix defining the epipolar 446 * geometry. 447 * @param type a corrector type. 448 * @return an instance of a corrector. 449 */ 450 public static Corrector create( 451 final List<Point2D> leftPoints, final List<Point2D> rightPoints, 452 final FundamentalMatrix fundamentalMatrix, final CorrectorType type) { 453 return create(leftPoints, rightPoints, fundamentalMatrix, null, type); 454 } 455 456 /** 457 * Creates an instance of a corrector using provided type. 458 * 459 * @param listener listener to handle events generated by this class. 460 * @param type a corrector type. 461 * @return an instance of a corrector. 462 */ 463 public static Corrector create(final CorrectorListener listener, final CorrectorType type) { 464 return type == CorrectorType.SAMPSON_CORRECTOR 465 ? new SampsonCorrector(listener) : new GoldStandardCorrector(listener); 466 } 467 468 /** 469 * Creates an instance of a corrector using provided fundamental matrix 470 * and provided type. 471 * 472 * @param fundamentalMatrix fundamental matrix defining the epipolar 473 * geometry. 474 * @param listener listener to handle events generated by this class. 475 * @param type a corrector type. 476 * @return an instance of a corrector. 477 */ 478 public static Corrector create( 479 final FundamentalMatrix fundamentalMatrix, final CorrectorListener listener, final CorrectorType type) { 480 return type == CorrectorType.SAMPSON_CORRECTOR 481 ? new SampsonCorrector(fundamentalMatrix, listener) 482 : new GoldStandardCorrector(fundamentalMatrix, listener); 483 } 484 485 /** 486 * Creates an instance of a corrector using provided left and right points 487 * to be corrected and provided type. 488 * 489 * @param leftPoints matched points on left view to be corrected. 490 * @param rightPoints matched points on right view to be corrected. 491 * @param listener listener to handle events generated by this class. 492 * @param type a corrector type. 493 * @return an instance of a corrector. 494 */ 495 public static Corrector create( 496 final List<Point2D> leftPoints, final List<Point2D> rightPoints, final CorrectorListener listener, 497 final CorrectorType type) { 498 return type == CorrectorType.SAMPSON_CORRECTOR 499 ? new SampsonCorrector(leftPoints, rightPoints, listener) 500 : new GoldStandardCorrector(leftPoints, rightPoints, listener); 501 } 502 503 /** 504 * Creates an instance of a corrector using provided left and right points 505 * to be corrected, provided fundamental matrix and provided type. 506 * 507 * @param leftPoints matched points on left view to be corrected. 508 * @param rightPoints matched points on right view to be corrected. 509 * @param fundamentalMatrix fundamental matrix defining the epipolar 510 * geometry. 511 * @param listener listener to handle events generated by this class. 512 * @param type a corrector type. 513 * @return an instance of a corrector. 514 */ 515 public static Corrector create( 516 final List<Point2D> leftPoints, final List<Point2D> rightPoints, final FundamentalMatrix fundamentalMatrix, 517 final CorrectorListener listener, final CorrectorType type) { 518 return type == CorrectorType.SAMPSON_CORRECTOR 519 ? new SampsonCorrector(leftPoints, rightPoints, fundamentalMatrix, listener) 520 : new GoldStandardCorrector(leftPoints, rightPoints, fundamentalMatrix, listener); 521 } 522 523 /** 524 * Creates an instance of a corrector using default type. 525 * 526 * @param listener listener to handle events generated by this class. 527 * @return an instance of a corrector. 528 */ 529 public static Corrector create(final CorrectorListener listener) { 530 return create(listener, DEFAULT_TYPE); 531 } 532 533 /** 534 * Creates an instance of a corrector using provided fundamental matrix 535 * and default type. 536 * 537 * @param fundamentalMatrix fundamental matrix defining the epipolar 538 * geometry. 539 * @param listener listener to handle events generated by this class. 540 * @return an instance of a corrector. 541 */ 542 public static Corrector create(final FundamentalMatrix fundamentalMatrix, final CorrectorListener listener) { 543 return create(fundamentalMatrix, listener, DEFAULT_TYPE); 544 } 545 546 /** 547 * Creates an instance of a corrector using provided left and right points 548 * to be corrected and provided type. 549 * 550 * @param leftPoints matched points on left view to be corrected. 551 * @param rightPoints matched points on right view to be corrected. 552 * @param listener listener to handle events generated by this class. 553 * @return an instance of a corrector. 554 */ 555 public static Corrector create( 556 final List<Point2D> leftPoints, final List<Point2D> rightPoints, final CorrectorListener listener) { 557 return create(leftPoints, rightPoints, listener, DEFAULT_TYPE); 558 } 559 560 /** 561 * Creates an instance of a corrector using provided left and right points 562 * to be corrected, provided fundamental matrix and provided type. 563 * 564 * @param leftPoints matched points on left view to be corrected. 565 * @param rightPoints matched points on right view to be corrected. 566 * @param fundamentalMatrix fundamental matrix defining the epipolar 567 * geometry. 568 * @param listener listener to handle events generated by this class. 569 * @return an instance of a corrector. 570 */ 571 public static Corrector create( 572 final List<Point2D> leftPoints, final List<Point2D> rightPoints, final FundamentalMatrix fundamentalMatrix, 573 final CorrectorListener listener) { 574 return create(leftPoints, rightPoints, fundamentalMatrix, listener, DEFAULT_TYPE); 575 } 576 577 /** 578 * Creates an instance of a corrector using default type. 579 * 580 * @return an instance of a corrector. 581 */ 582 public static Corrector create() { 583 return create(DEFAULT_TYPE); 584 } 585 586 /** 587 * Creates an instance of a corrector using provided fundamental matrix 588 * and default type. 589 * 590 * @param fundamentalMatrix fundamental matrix defining the epipolar 591 * geometry. 592 * @return an instance of a corrector. 593 */ 594 public static Corrector create(final FundamentalMatrix fundamentalMatrix) { 595 return create(fundamentalMatrix, DEFAULT_TYPE); 596 } 597 598 /** 599 * Creates an instance of a corrector using provided left and right points 600 * to be corrected and default type. 601 * 602 * @param leftPoints matched points on left view to be corrected. 603 * @param rightPoints matched points on right view to be corrected. 604 * @return an instance of a corrector. 605 */ 606 public static Corrector create(final List<Point2D> leftPoints, final List<Point2D> rightPoints) { 607 return create(leftPoints, rightPoints, DEFAULT_TYPE); 608 } 609 610 /** 611 * Creates an instance of a corrector using provided left and right points 612 * to be corrected, provided fundamental matrix and default type. 613 * 614 * @param leftPoints matched points on left view to be corrected. 615 * @param rightPoints matched points on right view to be corrected. 616 * @param fundamentalMatrix fundamental matrix defining the epipolar 617 * geometry. 618 * @return an instance of a corrector. 619 */ 620 public static Corrector create( 621 final List<Point2D> leftPoints, final List<Point2D> rightPoints, 622 final FundamentalMatrix fundamentalMatrix) { 623 return create(leftPoints, rightPoints, fundamentalMatrix, DEFAULT_TYPE); 624 } 625 626 /** 627 * Internal method to set fundamental matrix defining the epipolar geometry. 628 * 629 * @param fundamentalMatrix fundamental matrix to be set. 630 */ 631 private void internalSetFundamentalMatrix(final FundamentalMatrix fundamentalMatrix) { 632 this.fundamentalMatrix = fundamentalMatrix; 633 } 634 635 /** 636 * Internal method to set lists of points to be corrected on left and right 637 * views. 638 * 639 * @param leftPoints points to be corrected on left view. 640 * @param rightPoints points to be corrected on right view. 641 * @throws IllegalArgumentException if provided lists of points don't have 642 * the same size. 643 */ 644 private void internalSetLeftAndRightPoints( 645 final List<Point2D> leftPoints, final List<Point2D> rightPoints) { 646 if (!areValidPoints(leftPoints, rightPoints)) { 647 throw new IllegalArgumentException(); 648 } 649 650 this.leftPoints = leftPoints; 651 this.rightPoints = rightPoints; 652 } 653 }