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 }