1 /*
2 * Copyright (C) 2017 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.sfm;
17
18 import com.irurueta.algebra.Matrix;
19 import com.irurueta.ar.epipolar.Corrector;
20 import com.irurueta.ar.epipolar.CorrectorType;
21 import com.irurueta.ar.epipolar.FundamentalMatrix;
22 import com.irurueta.ar.epipolar.estimators.FundamentalMatrixEstimatorException;
23 import com.irurueta.ar.epipolar.estimators.PlanarFundamentalMatrixEstimator;
24 import com.irurueta.geometry.PinholeCamera;
25 import com.irurueta.geometry.PinholeCameraIntrinsicParameters;
26 import com.irurueta.geometry.Point2D;
27 import com.irurueta.geometry.Point3D;
28 import com.irurueta.geometry.ProjectiveTransformation2D;
29 import com.irurueta.geometry.estimators.LockedException;
30 import com.irurueta.geometry.estimators.NotReadyException;
31 import com.irurueta.geometry.estimators.PROMedSPointCorrespondenceProjectiveTransformation2DRobustEstimator;
32 import com.irurueta.geometry.estimators.PROSACPointCorrespondenceProjectiveTransformation2DRobustEstimator;
33 import com.irurueta.geometry.estimators.PointCorrespondenceProjectiveTransformation2DRobustEstimator;
34 import com.irurueta.geometry.estimators.RANSACPointCorrespondenceProjectiveTransformation2DRobustEstimator;
35 import com.irurueta.numerical.robust.RobustEstimatorException;
36 import com.irurueta.numerical.robust.RobustEstimatorMethod;
37
38 import java.util.ArrayList;
39 import java.util.Arrays;
40 import java.util.BitSet;
41 import java.util.List;
42
43 /**
44 * This class takes matched pairs of 2D points corresponding to a planar scene,
45 * estimates an homography relating both sets of points, decomposes such
46 * homography induced by the 3D plane on the scene, and uses such decomposition
47 * to determine the best epipolar geometry (e.g. fundamental matrix) by using
48 * the essential matrix and provided intrinsic camera parameters on both views
49 * corresponding to both sets of points to reconstruct points and choose the
50 * solution that produces the largest amount of points located in front of both
51 * cameras.
52 * This class requires 2 sets of matched 2D points and the intrinsic parameters
53 * of the cameras in both views, hence cameras must be calibrated in some way
54 * before using this class.
55 * This class is similar to PlanarFundamentalMatrixEstimator but picks the best
56 * solution by reconstructing the 3D points in the scene and choosing the
57 * solution that produces the largest amount of points located in front of both
58 * cameras.
59 */
60 public class PlanarBestFundamentalMatrixEstimatorAndReconstructor {
61
62 /**
63 * Minimum number of matched points required to find a solution.
64 */
65 public static final int MINIMUM_SIZE = 4;
66
67 /**
68 * List of matched 2D points in the left view.
69 */
70 private List<Point2D> leftPoints;
71
72 /**
73 * List of matched 2D points in the right view.
74 */
75 private List<Point2D> rightPoints;
76
77 /**
78 * Intrinsic parameters for the camera on the left view.
79 */
80 private PinholeCameraIntrinsicParameters leftIntrinsics;
81
82 /**
83 * Intrinsic parameters for the camera on the right view.
84 */
85 private PinholeCameraIntrinsicParameters rightIntrinsics;
86
87 /**
88 * Listener to attend events generated by this instance.
89 */
90 private PlanarBestFundamentalMatrixEstimatorAndReconstructorListener listener;
91
92 /**
93 * Indicates whether this instance is locked while computing a solution.
94 */
95 private boolean locked;
96
97 /**
98 * Homography estimator relating both views.
99 */
100 private PointCorrespondenceProjectiveTransformation2DRobustEstimator homographyEstimator;
101
102 /**
103 * Type of corrector to use to triangulate matched points using the
104 * corresponding essential matrix or null if no corrector needs to be used.
105 */
106 private CorrectorType essentialCameraEstimatorCorrectorType = Corrector.DEFAULT_TYPE;
107
108 /**
109 * Estimated homography.
110 */
111 private ProjectiveTransformation2D homography;
112
113 /**
114 * Best estimated fundamental matrix.
115 */
116 private FundamentalMatrix fundamentalMatrix;
117
118 /**
119 * Best estimated triangulated points.
120 */
121 private List<Point3D> triangulatedPoints;
122
123 /**
124 * Contains booleans indicating which of the best triangulated points are
125 * valid (i.e. lie in front of both estimated cameras) or not.
126 */
127 private BitSet validTriangulatedPoints;
128
129 /**
130 * Best estimated camera for left view.
131 */
132 private PinholeCamera estimatedLeftCamera;
133
134 /**
135 * Best estimated camera for right view.
136 */
137 private PinholeCamera estimatedRightCamera;
138
139 /**
140 * Constructor.
141 */
142 public PlanarBestFundamentalMatrixEstimatorAndReconstructor() {
143 homographyEstimator = PointCorrespondenceProjectiveTransformation2DRobustEstimator.create();
144 }
145
146 /**
147 * Constructor.
148 *
149 * @param leftPoints list of matched 2D points in the left view.
150 * @param rightPoints list of matched 2D points in the right view.
151 * @param leftIntrinsics intrinsic parameters for the camera on the left view.
152 * @param rightIntrinsics intrinsic parameters for the camera on the right view.
153 * @throws IllegalArgumentException if provided list of matched points do
154 * not contain enough points or if they have different sizes.
155 */
156 public PlanarBestFundamentalMatrixEstimatorAndReconstructor(
157 final List<Point2D> leftPoints, final List<Point2D> rightPoints,
158 final PinholeCameraIntrinsicParameters leftIntrinsics,
159 final PinholeCameraIntrinsicParameters rightIntrinsics) {
160 this();
161 internalSetLeftAndRightPoints(leftPoints, rightPoints);
162 this.leftIntrinsics = leftIntrinsics;
163 this.rightIntrinsics = rightIntrinsics;
164 }
165
166 /**
167 * Constructor.
168 *
169 * @param leftPoints list of matched 2D points in the left view.
170 * @param rightPoints list of matched 2D points in the right view.
171 * @param leftIntrinsics intrinsic parameters for the camera on the left view.
172 * @param rightIntrinsics intrinsic parameters for the camera on the right view.
173 * @param listener listener to be notified of events generated by this instance.
174 * @throws IllegalArgumentException if provided list of matched points do
175 * not contain enough points or if they have different sizes.
176 */
177 public PlanarBestFundamentalMatrixEstimatorAndReconstructor(
178 final List<Point2D> leftPoints, final List<Point2D> rightPoints,
179 final PinholeCameraIntrinsicParameters leftIntrinsics,
180 final PinholeCameraIntrinsicParameters rightIntrinsics,
181 final PlanarBestFundamentalMatrixEstimatorAndReconstructorListener listener) {
182 this(leftPoints, rightPoints, leftIntrinsics, rightIntrinsics);
183 this.listener = listener;
184 }
185
186 /**
187 * Gets list of matched 2D points in the left view.
188 *
189 * @return list of matched 2D points in the left view.
190 */
191 public List<Point2D> getLeftPoints() {
192 return leftPoints;
193 }
194
195 /**
196 * Sets list of matched 2D points in the left view.
197 *
198 * @param leftPoints list of matched 2D points in the left view.
199 * @throws LockedException if this instance is locked.
200 * @throws IllegalArgumentException if provided points do not have enough
201 * points.
202 */
203 public void setLeftPoints(final List<Point2D> leftPoints) throws LockedException {
204 if (isLocked()) {
205 throw new LockedException();
206 }
207 if (leftPoints.size() < MINIMUM_SIZE) {
208 throw new IllegalArgumentException();
209 }
210
211 this.leftPoints = leftPoints;
212 }
213
214 /**
215 * Gets list of matched 2D points in the right view.
216 *
217 * @return list of matched 2D points in the right view.
218 */
219 public List<Point2D> getRightPoints() {
220 return rightPoints;
221 }
222
223 /**
224 * Sets list of matched 2D points in the right view.
225 *
226 * @param rightPoints list of matched 2D points in the right view.
227 * @throws LockedException if this instance is locked.
228 * @throws IllegalArgumentException if provided points do not have enough
229 * points.
230 */
231 public void setRightPoints(final List<Point2D> rightPoints) throws LockedException {
232 if (isLocked()) {
233 throw new LockedException();
234 }
235 if (rightPoints.size() < MINIMUM_SIZE) {
236 throw new IllegalArgumentException();
237 }
238
239 this.rightPoints = rightPoints;
240 }
241
242 /**
243 * Sets lists of matched 2D points in the left and right views.
244 *
245 * @param leftPoints list of matched 2D points in the left view.
246 * @param rightPoints list of matched 2D points in the right view.
247 * @throws LockedException if this instance is locked.
248 * @throws IllegalArgumentException if provided points do not have enough
249 * points or lists have different sizes.
250 */
251 public void setLeftAndRightPoints(final List<Point2D> leftPoints, final List<Point2D> rightPoints)
252 throws LockedException {
253 if (isLocked()) {
254 throw new LockedException();
255 }
256
257 internalSetLeftAndRightPoints(leftPoints, rightPoints);
258 }
259
260 /**
261 * Gets intrinsic parameters for the camera on the left view.
262 *
263 * @return intrinsic parameters for the camera on the left view.
264 */
265 public PinholeCameraIntrinsicParameters getLeftIntrinsics() {
266 return leftIntrinsics;
267 }
268
269 /**
270 * Sets intrinsic parameters for the camera on the left view.
271 *
272 * @param leftIntrinsics intrinsic parameters for the camera on the left
273 * view.
274 * @throws LockedException if estimator is locked.
275 */
276 public void setLeftIntrinsics(final PinholeCameraIntrinsicParameters leftIntrinsics) throws LockedException {
277 if (isLocked()) {
278 throw new LockedException();
279 }
280
281 this.leftIntrinsics = leftIntrinsics;
282 }
283
284 /**
285 * Gets intrinsic parameters for the camera on the right view.
286 *
287 * @return intrinsic parameters for the camera on the right view.
288 */
289 public PinholeCameraIntrinsicParameters getRightIntrinsics() {
290 return rightIntrinsics;
291 }
292
293 /**
294 * Sets intrinsic parameters for the camera on the right view.
295 *
296 * @param rightIntrinsics intrinsic parameters for the camera on the right
297 * view.
298 * @throws LockedException if estimator is locked.
299 */
300 public void setRightIntrinsics(final PinholeCameraIntrinsicParameters rightIntrinsics) throws LockedException {
301 if (isLocked()) {
302 throw new LockedException();
303 }
304
305 this.rightIntrinsics = rightIntrinsics;
306 }
307
308 /**
309 * Gets internal homography estimator.
310 *
311 * @return internal homography estimator.
312 */
313 public PointCorrespondenceProjectiveTransformation2DRobustEstimator getHomographyEstimator() {
314 return homographyEstimator;
315 }
316
317 /**
318 * Sets internal homography estimator.
319 *
320 * @param homographyEstimator internal homography estimator.
321 * @throws LockedException if estimator is locked.
322 * @throws NullPointerException if provided estimator is null.
323 */
324 public void setHomographyEstimator(
325 final PointCorrespondenceProjectiveTransformation2DRobustEstimator homographyEstimator)
326 throws LockedException {
327 if (isLocked()) {
328 throw new LockedException();
329 }
330 if (homographyEstimator == null) {
331 throw new NullPointerException();
332 }
333
334 this.homographyEstimator = homographyEstimator;
335 }
336
337 /**
338 * Gets type of corrector to use to triangulate matched points using the
339 * corresponding essential matrix or null if no corrector needs to be used.
340 *
341 * @return corrector to use for triangulation or null.
342 */
343 public CorrectorType getEssentialCameraEstimatorCorrectorType() {
344 return essentialCameraEstimatorCorrectorType;
345 }
346
347 /**
348 * Sets type of corrector to use to triangulate matched points using the
349 * corresponding essential matrix or null if no corrector needs to be used.
350 *
351 * @param correctorType corrector to use for triangulation or null.
352 * @throws LockedException if estimator is locked.
353 */
354 public void setEssentialCameraEstimatorCorrectorType(final CorrectorType correctorType) throws LockedException {
355 if (isLocked()) {
356 throw new LockedException();
357 }
358
359 essentialCameraEstimatorCorrectorType = correctorType;
360 }
361
362 /**
363 * Gets amount of confidence on homography estimation expressed as a value
364 * between 0.0 and 1.0 (which is equivalent to 100%). The amount of
365 * confidence indicates the probability that the estimated result is
366 * correct. Usually this value will be close to 1.0, but not exactly 1.0.
367 *
368 * @return amount of confidence as a value between 0.0 and 1.0.
369 */
370 public double getHomographyConfidence() {
371 return homographyEstimator.getConfidence();
372 }
373
374 /**
375 * Sets amount of confidence on homography estimation expressed as a value
376 * between 0.0 and 1.0 (which is equivalent to 100%). The amount of
377 * confidence indicates the probability that the estimated result is
378 * correct. Usually this value will be close to 1.0, but not exactly 1.0.
379 *
380 * @param confidence confidence to be set as a value between 0.0 and 1.0.
381 * @throws IllegalArgumentException if provided value is not between 0.0 and
382 * 1.0.
383 * @throws LockedException if estimator is locked.
384 */
385 public void setHomographyConfidence(final double confidence) throws LockedException {
386 if (isLocked()) {
387 throw new LockedException();
388 }
389
390 homographyEstimator.setConfidence(confidence);
391 }
392
393 /**
394 * Returns maximum allowed number of iterations for homography estimation.
395 *
396 * @return maximum allowed number of iterations.
397 */
398 public int getHomographyMaxIterations() {
399 return homographyEstimator.getMaxIterations();
400 }
401
402 /**
403 * Sets maximum allowed number of iterations for homography estimation.
404 *
405 * @param maxIterations maximum allowed number of iterations.
406 * @throws IllegalArgumentException if provided value is less than 1.
407 * @throws LockedException if estimator is locked.
408 */
409 public void setHomographyMaxIterations(final int maxIterations) throws LockedException {
410 if (isLocked()) {
411 throw new LockedException();
412 }
413
414 homographyEstimator.setMaxIterations(maxIterations);
415 }
416
417 /**
418 * Indicates whether result of homography estimation is refined.
419 *
420 * @return true to refine homography result, false to simply use result
421 * found by robust estimation without further refining.
422 */
423 public boolean isHomographyRefined() {
424 return homographyEstimator.isResultRefined();
425 }
426
427 /**
428 * Specifies whether homography estimation must be refined or not.
429 *
430 * @param refineResult true to refine homography result, false to simply use
431 * result found by robust estimator without further refining.
432 * @throws LockedException if estimator is locked.
433 */
434 public void setHomographyRefined(final boolean refineResult) throws LockedException {
435 if (isLocked()) {
436 throw new LockedException();
437 }
438
439 homographyEstimator.setResultRefined(refineResult);
440 }
441
442 /**
443 * Indicates whether homography covariance must be kept after estimation.
444 * This setting is only taken into account if homography is refined.
445 *
446 * @return true if homography covariance must be kept after estimation,
447 * false otherwise.
448 */
449 public boolean isHomographyCovarianceKept() {
450 return homographyEstimator.isCovarianceKept();
451 }
452
453 /**
454 * Specifies whether homography covariance must be kept after estimation.
455 * This setting is only taken into account if homography is refined.
456 *
457 * @param keepCovariance true if homography covariance must be kept after
458 * estimation, false otherwise.
459 * @throws LockedException if estimator is locked.
460 */
461 public void setHomographyCovarianceKept(final boolean keepCovariance) throws LockedException {
462 if (isLocked()) {
463 throw new LockedException();
464 }
465
466 homographyEstimator.setCovarianceKept(keepCovariance);
467 }
468
469 /**
470 * Gets covariance for estimated homography if available.
471 * This is only available when homography has been refined and covariance is
472 * kept.
473 *
474 * @return estimated homography covariance or null.
475 */
476 public Matrix getHomographyCovariance() {
477 return homographyEstimator.getCovariance();
478 }
479
480 /**
481 * Returns method being used for homography robust estimation.
482 *
483 * @return method being used for homography robust estimation.
484 */
485 public RobustEstimatorMethod getHomographyMethod() {
486 return homographyEstimator.getMethod();
487 }
488
489 /**
490 * Returns quality scores corresponding to each pair of matched points.
491 * This is used for homography estimation.
492 * The larger the score value the better the quality of the matching.
493 *
494 * @return quality scores for each pair of matched points.
495 */
496 public double[] getQualityScores() {
497 return homographyEstimator.getQualityScores();
498 }
499
500 /**
501 * Sets quality scores corresponding to each pair of matched points.
502 * This is used for homography estimation.
503 * The larger the score value the better the quality of the matching.
504 *
505 * @param qualityScore quality scores corresponding to eac pair of matched
506 * points.
507 * @throws LockedException if estimator is locked.
508 * @throws IllegalArgumentException if provided quality scores length is
509 * smaller than minimum required size (4 points).
510 */
511 public void setQualityScores(final double[] qualityScore) throws LockedException {
512 if (isLocked()) {
513 throw new LockedException();
514 }
515
516 homographyEstimator.setQualityScores(qualityScore);
517 }
518
519 /**
520 * Gets listener to attend events generated by this instance.
521 *
522 * @return listener to attend events generated by this instance.
523 */
524 public PlanarBestFundamentalMatrixEstimatorAndReconstructorListener getListener() {
525 return listener;
526 }
527
528 /**
529 * Sets listener to attend events generated by this instance.
530 *
531 * @param listener listener to attend events generated by this instance.
532 */
533 public void setListener(final PlanarBestFundamentalMatrixEstimatorAndReconstructorListener listener) {
534 this.listener = listener;
535 }
536
537 /**
538 * Indicates whether this instance is locked while computing a solution.
539 *
540 * @return true if this instance is locked, false otherwise.
541 */
542 public boolean isLocked() {
543 return locked;
544 }
545
546 /**
547 * Indicates whether this instance is ready to start the estimation when all
548 * required data has been provided.
549 *
550 * @return true if this instance is ready, false otherwise.
551 */
552 public boolean isReady() {
553 return leftPoints != null && leftPoints.size() >= MINIMUM_SIZE && rightPoints != null
554 && rightPoints.size() >= MINIMUM_SIZE && leftPoints.size() == rightPoints.size()
555 && leftIntrinsics != null && rightIntrinsics != null && homographyEstimator.isReady();
556 }
557
558 /**
559 * Gets estimated homography.
560 *
561 * @return estimated homography.
562 */
563 public ProjectiveTransformation2D getHomography() {
564 return homography;
565 }
566
567 /**
568 * Gets best estimated fundamental matrix.
569 *
570 * @return best estimated fundamental matrix.
571 */
572 public FundamentalMatrix getFundamentalMatrix() {
573 return fundamentalMatrix;
574 }
575
576 /**
577 * Gets best estimated triangulated points.
578 *
579 * @return best estimated triangulated points.
580 */
581 public List<Point3D> getTriangulatedPoints() {
582 return triangulatedPoints;
583 }
584
585 /**
586 * Gets set containing booleans indicating which of the best triangulated
587 * points are valid (i.e. lie in front of both estimated cameras) or not.
588 *
589 * @return set indicating which of the best triangulated points are valid.
590 */
591 public BitSet getValidTriangulatedPoints() {
592 return validTriangulatedPoints;
593 }
594
595 /**
596 * Gets best estimated camera for left view.
597 *
598 * @return best estimated camera for left view.
599 */
600 public PinholeCamera getEstimatedLeftCamera() {
601 return estimatedLeftCamera;
602 }
603
604 /**
605 * Gets best estimated camera for right view.
606 *
607 * @return best estimated camera for right view.
608 */
609 public PinholeCamera getEstimatedRightCamera() {
610 return estimatedRightCamera;
611 }
612
613 /**
614 * Estimates homography, the best fundamental matrix, their cameras and
615 * reconstructs matched points.
616 *
617 * @throws LockedException if estimator is locked.
618 * @throws NotReadyException if estimator is not ready because required data
619 * is missing.
620 * @throws FundamentalMatrixEstimatorException if something fails, typically
621 * due to numerical instabilities.
622 */
623 public void estimateAndReconstruct() throws LockedException, NotReadyException,
624 FundamentalMatrixEstimatorException {
625 if (isLocked()) {
626 throw new LockedException();
627 }
628 if (!isReady()) {
629 throw new NotReadyException();
630 }
631
632 // always enable inlier estimation for homography
633 enableHomographyInliersEstimation();
634
635 try {
636 locked = true;
637
638 if (listener != null) {
639 listener.onEstimateStart(this);
640 }
641
642 // estimate homography
643 homography = homographyEstimator.estimate();
644
645 final var homographyInliers = homographyEstimator.getInliersData();
646
647 // estimate all fundamental matrices for homography
648 final var fundamentalMatrixEstimator = new PlanarFundamentalMatrixEstimator(homography, leftIntrinsics,
649 rightIntrinsics);
650
651 final var fundamentalMatrices = fundamentalMatrixEstimator.estimate();
652
653 if (fundamentalMatrices == null) {
654 throw new FundamentalMatrixEstimatorException();
655 }
656
657 // select homography inlier points
658 final var lPoints = new ArrayList<Point2D>();
659 final var rPoints = new ArrayList<Point2D>();
660 final var bitset = homographyInliers.getInliers();
661 final var bitsetLength = bitset.length();
662 for (var i = 0; i < bitsetLength; i++) {
663 if (bitset.get(i)) {
664 // is inlier
665 lPoints.add(this.leftPoints.get(i));
666 rPoints.add(this.rightPoints.get(i));
667 }
668 }
669
670 // pick best fundamental matrix
671 final var essentialCamerasEstimator = new EssentialMatrixInitialCamerasEstimator(leftIntrinsics,
672 rightIntrinsics, lPoints, rPoints);
673 essentialCamerasEstimator.setCorrectorType(essentialCameraEstimatorCorrectorType);
674 essentialCamerasEstimator.setPointsTriangulated(true);
675 essentialCamerasEstimator.setValidTriangulatedPointsMarked(true);
676
677 var numBest = 0;
678 for (final var fMatrix : fundamentalMatrices) {
679 essentialCamerasEstimator.setFundamentalMatrix(fMatrix);
680
681 essentialCamerasEstimator.estimate();
682
683 final var validPoints = essentialCamerasEstimator.getValidTriangulatedPoints();
684 final var num = validPoints.cardinality();
685 if (num > numBest) {
686 numBest = num;
687 this.fundamentalMatrix = fMatrix;
688 triangulatedPoints = essentialCamerasEstimator.getTriangulatedPoints();
689 validTriangulatedPoints = validPoints;
690 estimatedLeftCamera = essentialCamerasEstimator.getEstimatedLeftCamera();
691 estimatedRightCamera = essentialCamerasEstimator.getEstimatedRightCamera();
692 }
693 }
694
695 if (listener != null) {
696 listener.onEstimateEnd(this);
697 }
698
699 } catch (final RobustEstimatorException | InitialCamerasEstimationFailedException e) {
700 throw new FundamentalMatrixEstimatorException(e);
701 } finally {
702 locked = false;
703 }
704 }
705
706 /**
707 * Internal method that sets list of matched 2D points in the left and right
708 * views.
709 *
710 * @param leftPoints list of matched 2D points in the left view.
711 * @param rightPoints list of matched 2D points in the right view.
712 * @throws IllegalArgumentException if provided points do not have enough
713 * points or lists have different sizes.
714 */
715 private void internalSetLeftAndRightPoints(final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
716 if (leftPoints.size() < MINIMUM_SIZE || rightPoints.size() < MINIMUM_SIZE
717 || leftPoints.size() != rightPoints.size()) {
718 throw new IllegalArgumentException();
719 }
720
721 this.leftPoints = leftPoints;
722 this.rightPoints = rightPoints;
723 try {
724 homographyEstimator.setPoints(leftPoints, rightPoints);
725
726 if (homographyEstimator.getMethod() == RobustEstimatorMethod.PROMEDS) {
727 final var promedsEstimator =
728 (PROMedSPointCorrespondenceProjectiveTransformation2DRobustEstimator) homographyEstimator;
729 if (promedsEstimator.getQualityScores() == null) {
730 final var qualityScores = new double[leftPoints.size()];
731 Arrays.fill(qualityScores, 1.0);
732 promedsEstimator.setQualityScores(qualityScores);
733 }
734 } else if (homographyEstimator.getMethod() == RobustEstimatorMethod.PROSAC) {
735 final var prosacEstimator =
736 (PROSACPointCorrespondenceProjectiveTransformation2DRobustEstimator) homographyEstimator;
737 if (prosacEstimator.getQualityScores() == null) {
738 final var qualityScores = new double[leftPoints.size()];
739 Arrays.fill(qualityScores, 1.0);
740 prosacEstimator.setQualityScores(qualityScores);
741 }
742 }
743 } catch (final LockedException ignore) {
744 // never happens
745 }
746 }
747
748 /**
749 * Ensures that inlier estimation is enabled on homography estimator.
750 */
751 private void enableHomographyInliersEstimation() {
752 try {
753 if (homographyEstimator.getMethod() == RobustEstimatorMethod.RANSAC) {
754 final var ransacHomographyEstimator =
755 (RANSACPointCorrespondenceProjectiveTransformation2DRobustEstimator) homographyEstimator;
756 ransacHomographyEstimator.setComputeAndKeepInliersEnabled(true);
757 ransacHomographyEstimator.setComputeAndKeepResidualsEnabled(true);
758 } else if (homographyEstimator.getMethod() == RobustEstimatorMethod.PROSAC) {
759 final var prosacHomographyEstimator =
760 (PROSACPointCorrespondenceProjectiveTransformation2DRobustEstimator) homographyEstimator;
761 prosacHomographyEstimator.setComputeAndKeepInliersEnabled(true);
762 prosacHomographyEstimator.setComputeAndKeepResidualsEnabled(true);
763 }
764 } catch (final LockedException ignore) {
765 // never happens
766 }
767 }
768 }