1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.irurueta.ar.sfm;
18
19 import com.irurueta.ar.calibration.estimators.LMSEImageOfAbsoluteConicEstimator;
20 import com.irurueta.ar.epipolar.Corrector;
21 import com.irurueta.ar.epipolar.EpipolarException;
22 import com.irurueta.ar.epipolar.EssentialMatrix;
23 import com.irurueta.ar.epipolar.FundamentalMatrix;
24 import com.irurueta.ar.epipolar.estimators.EightPointsFundamentalMatrixEstimator;
25 import com.irurueta.ar.epipolar.estimators.FundamentalMatrixEstimatorMethod;
26 import com.irurueta.ar.epipolar.estimators.FundamentalMatrixRobustEstimator;
27 import com.irurueta.ar.epipolar.estimators.LMedSFundamentalMatrixRobustEstimator;
28 import com.irurueta.ar.epipolar.estimators.MSACFundamentalMatrixRobustEstimator;
29 import com.irurueta.ar.epipolar.estimators.PROMedSFundamentalMatrixRobustEstimator;
30 import com.irurueta.ar.epipolar.estimators.PROSACFundamentalMatrixRobustEstimator;
31 import com.irurueta.ar.epipolar.estimators.RANSACFundamentalMatrixRobustEstimator;
32 import com.irurueta.ar.epipolar.estimators.SevenPointsFundamentalMatrixEstimator;
33 import com.irurueta.geometry.PinholeCamera;
34 import com.irurueta.geometry.PinholeCameraIntrinsicParameters;
35 import com.irurueta.geometry.Point2D;
36 import com.irurueta.geometry.Point3D;
37 import com.irurueta.geometry.Transformation2D;
38 import com.irurueta.geometry.estimators.LMedSPointCorrespondenceProjectiveTransformation2DRobustEstimator;
39 import com.irurueta.geometry.estimators.MSACPointCorrespondenceProjectiveTransformation2DRobustEstimator;
40 import com.irurueta.geometry.estimators.NotReadyException;
41 import com.irurueta.geometry.estimators.PROMedSPointCorrespondenceProjectiveTransformation2DRobustEstimator;
42 import com.irurueta.geometry.estimators.PROSACPointCorrespondenceProjectiveTransformation2DRobustEstimator;
43 import com.irurueta.geometry.estimators.PointCorrespondenceProjectiveTransformation2DRobustEstimator;
44 import com.irurueta.geometry.estimators.ProjectiveTransformation2DRobustEstimator;
45 import com.irurueta.geometry.estimators.RANSACPointCorrespondenceProjectiveTransformation2DRobustEstimator;
46
47 import java.util.ArrayList;
48 import java.util.List;
49
50
51
52
53
54
55
56
57
58 @SuppressWarnings("DuplicatedCode")
59 public abstract class BaseTwoViewsSparseReconstructor<
60 C extends BaseTwoViewsSparseReconstructorConfiguration<C>,
61 R extends BaseTwoViewsSparseReconstructor<C, R, L>,
62 L extends BaseTwoViewsSparseReconstructorListener<R>> {
63
64
65
66
67 public static final int NUMBER_OF_VIEWS = 2;
68
69
70
71
72 protected EstimatedFundamentalMatrix estimatedFundamentalMatrix;
73
74
75
76
77 protected EstimatedCamera estimatedCamera1;
78
79
80
81
82 protected EstimatedCamera estimatedCamera2;
83
84
85
86
87 protected List<ReconstructedPoint3D> reconstructedPoints;
88
89
90
91
92 protected C configuration;
93
94
95
96
97
98
99 protected L listener;
100
101
102
103
104 protected volatile boolean failed;
105
106
107
108
109 protected volatile boolean running;
110
111
112
113
114 private volatile boolean cancelled;
115
116
117
118
119 private int viewCount;
120
121
122
123
124 private boolean finished = false;
125
126
127
128
129 private List<Sample2D> firstViewSamples = null;
130
131
132
133
134 private List<Sample2D> currentViewSamples;
135
136
137
138
139 private final List<MatchedSamples> matches = new ArrayList<>();
140
141
142
143
144 private int firstViewId = 0;
145
146
147
148
149
150
151
152
153
154 protected BaseTwoViewsSparseReconstructor(final C configuration, final L listener) {
155 if (configuration == null || listener == null) {
156 throw new NullPointerException();
157 }
158 this.configuration = configuration;
159 this.listener = listener;
160 }
161
162
163
164
165
166
167 public C getConfiguration() {
168 return configuration;
169 }
170
171
172
173
174
175
176
177
178 public BaseTwoViewsSparseReconstructorListener<R> getListener() {
179 return listener;
180 }
181
182
183
184
185
186
187
188 public boolean isRunning() {
189 return running;
190 }
191
192
193
194
195
196
197 public boolean isCancelled() {
198 return cancelled;
199 }
200
201
202
203
204
205
206 public boolean hasFailed() {
207 return failed;
208 }
209
210
211
212
213
214
215 public boolean isFinished() {
216 return finished;
217 }
218
219
220
221
222
223
224 public int getViewCount() {
225 return viewCount;
226 }
227
228
229
230
231
232
233 public EstimatedFundamentalMatrix getEstimatedFundamentalMatrix() {
234 return estimatedFundamentalMatrix;
235 }
236
237
238
239
240
241
242 public EstimatedCamera getEstimatedCamera1() {
243 return estimatedCamera1;
244 }
245
246
247
248
249
250
251 public EstimatedCamera getEstimatedCamera2() {
252 return estimatedCamera2;
253 }
254
255
256
257
258
259
260 public List<ReconstructedPoint3D> getReconstructedPoints() {
261 return reconstructedPoints;
262 }
263
264
265
266
267
268
269
270
271 public boolean processOneView() {
272 if (viewCount == 0) {
273 if (running) {
274
275 return true;
276 }
277
278 reset();
279 running = true;
280
281
282 listener.onStart((R) this);
283 }
284
285
286 if (!listener.hasMoreViewsAvailable((R) this)) {
287 return false;
288 }
289
290 estimatedFundamentalMatrix = null;
291 currentViewSamples = new ArrayList<>();
292
293 listener.onRequestSamplesForCurrentView((R) this, viewCount, currentViewSamples);
294
295 if (firstViewSamples == null) {
296
297 if (hasEnoughSamples(currentViewSamples)) {
298
299 listener.onSamplesAccepted((R) this, viewCount, currentViewSamples);
300 firstViewSamples = currentViewSamples;
301 firstViewId = viewCount;
302 }
303
304 } else {
305
306
307 if (hasEnoughSamples(currentViewSamples)) {
308
309
310 matches.clear();
311
312 listener.onRequestMatches((R) this, firstViewSamples, currentViewSamples, firstViewId, viewCount,
313 matches);
314
315 if (hasEnoughMatches(matches)) {
316
317
318 if ((configuration.isGeneralSceneAllowed()
319 && estimateFundamentalMatrix(matches, firstViewId, viewCount))
320 || (configuration.isPlanarSceneAllowed()
321 && estimatePlanarFundamentalMatrix(matches, firstViewId, viewCount))) {
322
323
324 listener.onSamplesAccepted((R) this, viewCount, currentViewSamples);
325 var secondViewId = viewCount;
326
327
328 listener.onFundamentalMatrixEstimated((R) this, estimatedFundamentalMatrix);
329
330 if (estimateInitialCamerasAndPoints()) {
331
332
333 listener.onCamerasEstimated((R) this, firstViewId, secondViewId, estimatedCamera1,
334 estimatedCamera2);
335
336 listener.onReconstructedPointsEstimated((R) this, matches, reconstructedPoints);
337 if (postProcessOne()) {
338
339 listener.onFinish((R) this);
340 running = false;
341 finished = true;
342 }
343 } else {
344
345 failed = true;
346
347 listener.onFail((R) this);
348 }
349 } else {
350
351
352 listener.onSamplesRejected((R) this, viewCount, currentViewSamples);
353 }
354 }
355 }
356 }
357
358 viewCount++;
359
360 if (cancelled) {
361
362 listener.onCancel((R) this);
363 }
364
365 return !finished;
366 }
367
368
369
370
371
372
373 public void start() {
374 while (processOneView()) {
375 if (cancelled) {
376 break;
377 }
378 }
379 }
380
381
382
383
384
385
386 public void cancel() {
387 if (cancelled) {
388
389 return;
390 }
391
392 cancelled = true;
393 }
394
395
396
397
398
399 public void reset() {
400 firstViewSamples = currentViewSamples = null;
401
402 cancelled = failed = false;
403 viewCount = 0;
404 running = false;
405
406 estimatedFundamentalMatrix = null;
407 estimatedCamera1 = estimatedCamera2 = null;
408 reconstructedPoints = null;
409
410 finished = false;
411 }
412
413
414
415
416
417
418
419 protected abstract boolean postProcessOne();
420
421
422
423
424
425
426
427
428 private boolean hasEnoughSamples(final List<Sample2D> samples) {
429 return hasEnoughSamplesOrMatches(samples != null ? samples.size() : 0);
430 }
431
432
433
434
435
436
437
438
439 private boolean hasEnoughMatches(final List<MatchedSamples> matches) {
440 return hasEnoughSamplesOrMatches(matches != null ? matches.size() : 0);
441 }
442
443
444
445
446
447
448
449
450 private boolean hasEnoughSamplesOrMatches(final int count) {
451 if (configuration.isGeneralSceneAllowed()) {
452 if (configuration.getNonRobustFundamentalMatrixEstimatorMethod()
453 == FundamentalMatrixEstimatorMethod.EIGHT_POINTS_ALGORITHM) {
454 return count >= EightPointsFundamentalMatrixEstimator.MIN_REQUIRED_POINTS;
455 } else if (configuration.getNonRobustFundamentalMatrixEstimatorMethod()
456 == FundamentalMatrixEstimatorMethod.SEVEN_POINTS_ALGORITHM) {
457 return count >= SevenPointsFundamentalMatrixEstimator.MIN_REQUIRED_POINTS;
458 }
459 } else if (configuration.isPlanarSceneAllowed()) {
460 return count >= ProjectiveTransformation2DRobustEstimator.MINIMUM_SIZE;
461 }
462 return false;
463 }
464
465
466
467
468
469
470
471
472
473
474 private boolean estimateFundamentalMatrix(final List<MatchedSamples> matches, final int viewId1,
475 final int viewId2) {
476 if (matches == null) {
477 return false;
478 }
479
480 final var count = matches.size();
481 final var leftSamples = new ArrayList<Sample2D>(count);
482 final var rightSamples = new ArrayList<Sample2D>(count);
483 final var leftPoints = new ArrayList<Point2D>(count);
484 final var rightPoints = new ArrayList<Point2D>(count);
485 final var qualityScores = new double[count];
486 final double principalPointX;
487 final double principalPointY;
488 if (configuration.getInitialCamerasEstimatorMethod() == InitialCamerasEstimatorMethod.DUAL_ABSOLUTE_QUADRIC
489 || configuration.getInitialCamerasEstimatorMethod()
490 == InitialCamerasEstimatorMethod.DUAL_ABSOLUTE_QUADRIC_AND_ESSENTIAL_MATRIX) {
491 principalPointX = configuration.getPrincipalPointX();
492 principalPointY = configuration.getPrincipalPointY();
493 } else {
494 principalPointX = principalPointY = 0.0;
495 }
496
497 var i = 0;
498 for (final var match : matches) {
499 final var samples = match.getSamples();
500 if (samples.length != NUMBER_OF_VIEWS) {
501 return false;
502 }
503
504 leftSamples.add(samples[0]);
505 rightSamples.add(samples[1]);
506
507 final var leftPoint = Point2D.create();
508 leftPoint.setInhomogeneousCoordinates(
509 samples[0].getPoint().getInhomX() - principalPointX,
510 samples[0].getPoint().getInhomY() - principalPointY);
511 leftPoints.add(leftPoint);
512
513 final var rightPoint = Point2D.create();
514 rightPoint.setInhomogeneousCoordinates(
515 samples[1].getPoint().getInhomX() - principalPointX,
516 samples[1].getPoint().getInhomY() - principalPointY);
517 rightPoints.add(rightPoint);
518
519 qualityScores[i] = match.getQualityScore();
520 i++;
521 }
522
523 try {
524 final var estimator = FundamentalMatrixRobustEstimator.create(leftPoints, rightPoints, qualityScores,
525 configuration.getRobustFundamentalMatrixEstimatorMethod());
526 estimator.setNonRobustFundamentalMatrixEstimatorMethod(
527 configuration.getNonRobustFundamentalMatrixEstimatorMethod());
528 estimator.setResultRefined(configuration.isFundamentalMatrixRefined());
529 estimator.setCovarianceKept(configuration.isFundamentalMatrixCovarianceKept());
530 estimator.setConfidence(configuration.getFundamentalMatrixConfidence());
531 estimator.setMaxIterations(configuration.getFundamentalMatrixMaxIterations());
532
533 switch (configuration.getRobustFundamentalMatrixEstimatorMethod()) {
534 case LMEDS:
535 ((LMedSFundamentalMatrixRobustEstimator) estimator)
536 .setStopThreshold(configuration.getFundamentalMatrixThreshold());
537 break;
538 case MSAC:
539 ((MSACFundamentalMatrixRobustEstimator) estimator)
540 .setThreshold(configuration.getFundamentalMatrixThreshold());
541 break;
542 case PROMEDS:
543 ((PROMedSFundamentalMatrixRobustEstimator) estimator)
544 .setStopThreshold(configuration.getFundamentalMatrixThreshold());
545 break;
546 case PROSAC:
547 var prosacEstimator = (PROSACFundamentalMatrixRobustEstimator) estimator;
548 prosacEstimator.setThreshold(configuration.getFundamentalMatrixThreshold());
549 prosacEstimator.setComputeAndKeepInliersEnabled(
550 configuration.getFundamentalMatrixComputeAndKeepInliers());
551 prosacEstimator.setComputeAndKeepResidualsEnabled(
552 configuration.getFundamentalMatrixComputeAndKeepResiduals());
553 break;
554 case RANSAC:
555 var ransacEstimator = (RANSACFundamentalMatrixRobustEstimator) estimator;
556 ransacEstimator.setThreshold(configuration.getFundamentalMatrixThreshold());
557 ransacEstimator.setComputeAndKeepInliersEnabled(
558 configuration.getFundamentalMatrixComputeAndKeepInliers());
559 ransacEstimator.setComputeAndKeepResidualsEnabled(
560 configuration.getFundamentalMatrixComputeAndKeepResiduals());
561 break;
562 default:
563 break;
564 }
565
566
567 final var fundamentalMatrix = estimator.estimate();
568
569 estimatedFundamentalMatrix = new EstimatedFundamentalMatrix();
570 estimatedFundamentalMatrix.setFundamentalMatrix(fundamentalMatrix);
571 estimatedFundamentalMatrix.setViewId1(viewId1);
572 estimatedFundamentalMatrix.setViewId2(viewId2);
573 estimatedFundamentalMatrix.setCovariance(estimator.getCovariance());
574
575
576 final var inliersData = estimator.getInliersData();
577 if (inliersData != null) {
578 final var numInliers = inliersData.getNumInliers();
579 final var inliers = inliersData.getInliers();
580 final var length = inliers.length();
581 var fundamentalMatrixQualityScore = 0.0;
582 for (i = 0; i < length; i++) {
583 if (inliers.get(i)) {
584
585 fundamentalMatrixQualityScore += qualityScores[i] / numInliers;
586 }
587 }
588 estimatedFundamentalMatrix.setQualityScore(fundamentalMatrixQualityScore);
589 estimatedFundamentalMatrix.setInliers(inliers);
590 }
591
592
593 estimatedFundamentalMatrix.setLeftSamples(leftSamples);
594 estimatedFundamentalMatrix.setRightSamples(rightSamples);
595
596 return true;
597 } catch (final Exception e) {
598 return false;
599 }
600 }
601
602
603
604
605
606
607
608
609
610
611 private boolean estimatePlanarFundamentalMatrix(
612 final List<MatchedSamples> matches, final int viewId1, final int viewId2) {
613 if (matches == null) {
614 return false;
615 }
616
617 final var count = matches.size();
618 final var leftSamples = new ArrayList<Sample2D>();
619 final var rightSamples = new ArrayList<Sample2D>();
620 final var leftPoints = new ArrayList<Point2D>();
621 final var rightPoints = new ArrayList<Point2D>();
622 final var qualityScores = new double[count];
623 final double principalPointX;
624 final double principalPointY;
625 if (configuration.getInitialCamerasEstimatorMethod() == InitialCamerasEstimatorMethod.DUAL_ABSOLUTE_QUADRIC
626 || configuration.getInitialCamerasEstimatorMethod()
627 == InitialCamerasEstimatorMethod.DUAL_ABSOLUTE_QUADRIC_AND_ESSENTIAL_MATRIX) {
628 principalPointX = configuration.getPrincipalPointX();
629 principalPointY = configuration.getPrincipalPointY();
630 } else {
631 principalPointX = principalPointY = 0.0;
632 }
633
634 var i = 0;
635 for (final var match : matches) {
636 final var samples = match.getSamples();
637 if (samples.length != NUMBER_OF_VIEWS) {
638 return false;
639 }
640
641 leftSamples.add(samples[0]);
642 rightSamples.add(samples[1]);
643
644 final var leftPoint = Point2D.create();
645 leftPoint.setInhomogeneousCoordinates(
646 samples[0].getPoint().getInhomX() - principalPointX,
647 samples[0].getPoint().getInhomY() - principalPointY);
648 leftPoints.add(leftPoint);
649
650 final var rightPoint = Point2D.create();
651 rightPoint.setInhomogeneousCoordinates(
652 samples[1].getPoint().getInhomX() - principalPointX,
653 samples[1].getPoint().getInhomY() - principalPointY);
654 rightPoints.add(rightPoint);
655
656 qualityScores[i] = match.getQualityScore();
657 i++;
658 }
659
660 try {
661 final var homographyEstimator = PointCorrespondenceProjectiveTransformation2DRobustEstimator.create(
662 configuration.getRobustPlanarHomographyEstimatorMethod());
663 homographyEstimator.setResultRefined(configuration.isPlanarHomographyRefined());
664 homographyEstimator.setCovarianceKept(configuration.isPlanarHomographyCovarianceKept());
665 homographyEstimator.setConfidence(configuration.getPlanarHomographyConfidence());
666 homographyEstimator.setMaxIterations(configuration.getPlanarHomographyMaxIterations());
667
668 switch (configuration.getRobustPlanarHomographyEstimatorMethod()) {
669 case LMEDS:
670 ((LMedSPointCorrespondenceProjectiveTransformation2DRobustEstimator) homographyEstimator)
671 .setStopThreshold(configuration.getPlanarHomographyThreshold());
672 break;
673 case MSAC:
674 ((MSACPointCorrespondenceProjectiveTransformation2DRobustEstimator) homographyEstimator)
675 .setThreshold(configuration.getPlanarHomographyThreshold());
676 break;
677 case PROMEDS:
678 ((PROMedSPointCorrespondenceProjectiveTransformation2DRobustEstimator) homographyEstimator)
679 .setStopThreshold(configuration.getPlanarHomographyThreshold());
680 break;
681 case PROSAC:
682 final var prosacHomographyEstimator =
683 (PROSACPointCorrespondenceProjectiveTransformation2DRobustEstimator) homographyEstimator;
684
685 prosacHomographyEstimator.setThreshold(configuration.getPlanarHomographyThreshold());
686 prosacHomographyEstimator.setComputeAndKeepInliersEnabled(
687 configuration.getPlanarHomographyComputeAndKeepInliers());
688 prosacHomographyEstimator.setComputeAndKeepResidualsEnabled(
689 configuration.getPlanarHomographyComputeAndKeepResiduals());
690 break;
691 case RANSAC:
692 default:
693 final var ransacHomographyEstimator =
694 (RANSACPointCorrespondenceProjectiveTransformation2DRobustEstimator) homographyEstimator;
695
696 ransacHomographyEstimator.setThreshold(configuration.getPlanarHomographyThreshold());
697 ransacHomographyEstimator.setComputeAndKeepInliersEnabled(
698 configuration.getPlanarHomographyComputeAndKeepInliers());
699 ransacHomographyEstimator.setComputeAndKeepResidualsEnabled(
700 configuration.getPlanarHomographyComputeAndKeepResiduals());
701 break;
702 }
703
704 final var fundamentalMatrixEstimator = new PlanarBestFundamentalMatrixEstimatorAndReconstructor();
705 fundamentalMatrixEstimator.setHomographyEstimator(homographyEstimator);
706 fundamentalMatrixEstimator.setLeftAndRightPoints(leftPoints, rightPoints);
707 fundamentalMatrixEstimator.setQualityScores(qualityScores);
708
709 var intrinsic1 = configuration.getInitialIntrinsic1();
710 var intrinsic2 = configuration.getInitialIntrinsic1();
711 if (intrinsic1 == null && intrinsic2 == null) {
712
713 final var homography = homographyEstimator.estimate();
714
715
716
717 final var homographies = new ArrayList<Transformation2D>();
718 homographies.add(homography);
719
720 final var iacEstimator = new LMSEImageOfAbsoluteConicEstimator(homographies);
721 final var iac = iacEstimator.estimate();
722
723 intrinsic1 = intrinsic2 = iac.getIntrinsicParameters();
724
725 } else if (intrinsic1 == null) {
726 intrinsic1 = intrinsic2;
727 } else if (intrinsic2 == null) {
728 intrinsic2 = intrinsic1;
729 }
730 fundamentalMatrixEstimator.setLeftIntrinsics(intrinsic1);
731 fundamentalMatrixEstimator.setRightIntrinsics(intrinsic2);
732
733 fundamentalMatrixEstimator.estimateAndReconstruct();
734
735 final var fundamentalMatrix = fundamentalMatrixEstimator.getFundamentalMatrix();
736
737 estimatedFundamentalMatrix = new EstimatedFundamentalMatrix();
738 estimatedFundamentalMatrix.setFundamentalMatrix(fundamentalMatrix);
739 estimatedFundamentalMatrix.setViewId1(viewId1);
740 estimatedFundamentalMatrix.setViewId2(viewId2);
741
742
743 final var inliersData = homographyEstimator.getInliersData();
744 if (inliersData != null) {
745 final var numInliers = inliersData.getNumInliers();
746 final var inliers = inliersData.getInliers();
747 final var length = inliers.length();
748 var fundamentalMatrixQualityScore = 0.0;
749 for (i = 0; i < length; i++) {
750 if (inliers.get(i)) {
751
752 fundamentalMatrixQualityScore += qualityScores[i] / numInliers;
753 }
754 }
755 estimatedFundamentalMatrix.setQualityScore(fundamentalMatrixQualityScore);
756 estimatedFundamentalMatrix.setInliers(inliers);
757 }
758
759
760 estimatedFundamentalMatrix.setLeftSamples(leftSamples);
761 estimatedFundamentalMatrix.setRightSamples(rightSamples);
762
763 return true;
764 } catch (final Exception e) {
765 return false;
766 }
767 }
768
769
770
771
772
773
774
775 private boolean estimateInitialCamerasAndPoints() {
776 return switch (configuration.getInitialCamerasEstimatorMethod()) {
777 case ESSENTIAL_MATRIX -> estimateInitialCamerasAndPointsEssential();
778 case DUAL_IMAGE_OF_ABSOLUTE_CONIC -> estimateInitialCamerasAndPointsDIAC();
779 case DUAL_ABSOLUTE_QUADRIC -> estimateInitialCamerasAndPointsDAQ();
780 default -> estimateInitialCamerasAndPointsDAQAndEssential();
781 };
782 }
783
784
785
786
787
788
789
790
791
792 private boolean estimateInitialCamerasAndPointsDAQAndEssential() {
793 try {
794 final var fundamentalMatrix = estimatedFundamentalMatrix.getFundamentalMatrix();
795
796 final var estimator = new DualAbsoluteQuadricInitialCamerasEstimator(fundamentalMatrix);
797 estimator.setAspectRatio(configuration.getInitialCamerasAspectRatio());
798 estimator.estimate();
799
800 final var camera1 = estimator.getEstimatedLeftCamera();
801 final var camera2 = estimator.getEstimatedRightCamera();
802
803 camera1.decompose();
804 camera2.decompose();
805
806 final var intrinsicZeroPrincipalPoint1 = camera1.getIntrinsicParameters();
807 final var intrinsicZeroPrincipalPoint2 = camera2.getIntrinsicParameters();
808
809 final var principalPointX = configuration.getPrincipalPointX();
810 final var principalPointY = configuration.getPrincipalPointY();
811
812 final var intrinsic1 = new PinholeCameraIntrinsicParameters(intrinsicZeroPrincipalPoint1);
813 intrinsic1.setHorizontalPrincipalPoint(intrinsic1.getHorizontalPrincipalPoint() + principalPointX);
814 intrinsic1.setVerticalPrincipalPoint(intrinsic1.getVerticalPrincipalPoint() + principalPointY);
815
816 final var intrinsic2 = new PinholeCameraIntrinsicParameters(intrinsicZeroPrincipalPoint2);
817 intrinsic2.setHorizontalPrincipalPoint(intrinsic2.getHorizontalPrincipalPoint() + principalPointX);
818 intrinsic2.setVerticalPrincipalPoint(intrinsic2.getVerticalPrincipalPoint() + principalPointY);
819
820
821
822 fixFundamentalMatrix(fundamentalMatrix, intrinsicZeroPrincipalPoint1, intrinsicZeroPrincipalPoint2,
823 intrinsic1, intrinsic2);
824
825 return estimateInitialCamerasAndPointsEssential(intrinsic1, intrinsic2);
826 } catch (final Exception e) {
827 return false;
828 }
829 }
830
831
832
833
834
835
836
837
838 private boolean estimateInitialCamerasAndPointsDAQ() {
839 try {
840 final var fundamentalMatrix = estimatedFundamentalMatrix.getFundamentalMatrix();
841 fundamentalMatrix.normalize();
842
843 final var estimator = new DualAbsoluteQuadricInitialCamerasEstimator(fundamentalMatrix);
844 estimator.setAspectRatio(configuration.getInitialCamerasAspectRatio());
845 estimator.estimate();
846
847 final var camera1 = estimator.getEstimatedLeftCamera();
848 final var camera2 = estimator.getEstimatedRightCamera();
849
850 camera1.decompose();
851 camera2.decompose();
852
853 final var intrinsicZeroPrincipalPoint1 = camera1.getIntrinsicParameters();
854 final var intrinsicZeroPrincipalPoint2 = camera2.getIntrinsicParameters();
855
856 final var principalPointX = configuration.getPrincipalPointX();
857 final var principalPointY = configuration.getPrincipalPointY();
858
859 final var intrinsic1 = new PinholeCameraIntrinsicParameters(intrinsicZeroPrincipalPoint1);
860 intrinsic1.setHorizontalPrincipalPoint(intrinsic1.getHorizontalPrincipalPoint() + principalPointX);
861 intrinsic1.setVerticalPrincipalPoint(intrinsic1.getVerticalPrincipalPoint() + principalPointY);
862 camera1.setIntrinsicParameters(intrinsic1);
863
864 final var intrinsic2 = new PinholeCameraIntrinsicParameters(intrinsicZeroPrincipalPoint2);
865 intrinsic2.setHorizontalPrincipalPoint(intrinsic2.getHorizontalPrincipalPoint() + principalPointX);
866 intrinsic2.setVerticalPrincipalPoint(intrinsic2.getVerticalPrincipalPoint() + principalPointY);
867 camera2.setIntrinsicParameters(intrinsic2);
868
869 estimatedCamera1 = new EstimatedCamera();
870 estimatedCamera1.setCamera(camera1);
871
872 estimatedCamera2 = new EstimatedCamera();
873 estimatedCamera2.setCamera(camera2);
874
875
876
877 fixFundamentalMatrix(fundamentalMatrix, intrinsicZeroPrincipalPoint1, intrinsicZeroPrincipalPoint2,
878 intrinsic1, intrinsic2);
879
880
881 Corrector corrector = null;
882 if (configuration.getInitialCamerasCorrectorType() != null) {
883 corrector = Corrector.create(fundamentalMatrix, configuration.getInitialCamerasCorrectorType());
884 }
885
886
887 final var samples1 = estimatedFundamentalMatrix.getLeftSamples();
888 final var samples2 = estimatedFundamentalMatrix.getRightSamples();
889
890 final var points1 = new ArrayList<Point2D>();
891 final var points2 = new ArrayList<Point2D>();
892 final var length = samples1.size();
893 for (var i = 0; i < length; i++) {
894 final var sample1 = samples1.get(i);
895 final var sample2 = samples2.get(i);
896
897 final var point1 = sample1.getPoint();
898 final var point2 = sample2.getPoint();
899
900 points1.add(point1);
901 points2.add(point2);
902 }
903
904
905 List<Point2D> correctedPoints1;
906 List<Point2D> correctedPoints2;
907 if (corrector != null) {
908 corrector.setLeftAndRightPoints(points1, points2);
909 corrector.correct();
910
911 correctedPoints1 = corrector.getLeftCorrectedPoints();
912 correctedPoints2 = corrector.getRightCorrectedPoints();
913 } else {
914 correctedPoints1 = points1;
915 correctedPoints2 = points2;
916 }
917
918
919 final SinglePoint3DTriangulator triangulator;
920 if (configuration.getDaqUseHomogeneousPointTriangulator()) {
921 triangulator = SinglePoint3DTriangulator.create(Point3DTriangulatorType.LMSE_HOMOGENEOUS_TRIANGULATOR);
922 } else {
923 triangulator = SinglePoint3DTriangulator.create(
924 Point3DTriangulatorType.LMSE_INHOMOGENEOUS_TRIANGULATOR);
925 }
926
927 final var cameras = new ArrayList<PinholeCamera>();
928 cameras.add(camera1);
929 cameras.add(camera2);
930
931 reconstructedPoints = new ArrayList<>();
932 final var points = new ArrayList<Point2D>();
933 final var numPoints = correctedPoints1.size();
934 Point3D triangulatedPoint;
935 ReconstructedPoint3D reconstructedPoint;
936 for (var i = 0; i < numPoints; i++) {
937 points.clear();
938 points.add(correctedPoints1.get(i));
939 points.add(correctedPoints2.get(i));
940
941 triangulator.setPointsAndCameras(points, cameras);
942 triangulatedPoint = triangulator.triangulate();
943
944 reconstructedPoint = new ReconstructedPoint3D();
945 reconstructedPoint.setPoint(triangulatedPoint);
946
947
948
949 final var front1 = camera1.isPointInFrontOfCamera(triangulatedPoint);
950 final var front2 = camera2.isPointInFrontOfCamera(triangulatedPoint);
951 reconstructedPoint.setInlier(front1 && front2);
952
953 reconstructedPoints.add(reconstructedPoint);
954 }
955
956 return true;
957 } catch (final Exception e) {
958 return false;
959 }
960 }
961
962
963
964
965
966
967
968
969 private boolean estimateInitialCamerasAndPointsDIAC() {
970 final var fundamentalMatrix = estimatedFundamentalMatrix.getFundamentalMatrix();
971
972
973 final var samples1 = estimatedFundamentalMatrix.getLeftSamples();
974 final var samples2 = estimatedFundamentalMatrix.getRightSamples();
975
976 final var points1 = new ArrayList<Point2D>();
977 final var points2 = new ArrayList<Point2D>();
978 final var length = samples1.size();
979 for (var i = 0; i < length; i++) {
980 final var sample1 = samples1.get(i);
981 final var sample2 = samples2.get(i);
982
983 final var point1 = sample1.getPoint();
984 final var point2 = sample2.getPoint();
985
986 points1.add(point1);
987 points2.add(point2);
988 }
989
990 try {
991 final var estimator = new DualImageOfAbsoluteConicInitialCamerasEstimator(fundamentalMatrix, points1,
992 points2);
993 estimator.setPrincipalPoint(configuration.getPrincipalPointX(), configuration.getPrincipalPointY());
994 estimator.setAspectRatio(configuration.getInitialCamerasAspectRatio());
995 estimator.setCorrectorType(configuration.getInitialCamerasCorrectorType());
996 estimator.setPointsTriangulated(true);
997 estimator.setValidTriangulatedPointsMarked(configuration.getInitialCamerasMarkValidTriangulatedPoints());
998
999 estimator.estimate();
1000
1001
1002 final var camera1 = estimator.getEstimatedLeftCamera();
1003 final var camera2 = estimator.getEstimatedRightCamera();
1004
1005 estimatedCamera1 = new EstimatedCamera();
1006 estimatedCamera1.setCamera(camera1);
1007
1008 estimatedCamera2 = new EstimatedCamera();
1009 estimatedCamera2.setCamera(camera2);
1010
1011
1012 final var triangulatedPoints = estimator.getTriangulatedPoints();
1013 final var validTriangulatedPoints = estimator.getValidTriangulatedPoints();
1014
1015 reconstructedPoints = new ArrayList<>();
1016 final var size = triangulatedPoints.size();
1017 for (var i = 0; i < size; i++) {
1018 final var reconstructedPoint = new ReconstructedPoint3D();
1019 reconstructedPoint.setPoint(triangulatedPoints.get(i));
1020 reconstructedPoint.setInlier(validTriangulatedPoints.get(i));
1021 reconstructedPoints.add(reconstructedPoint);
1022 }
1023
1024 return true;
1025 } catch (final Exception e) {
1026 return false;
1027 }
1028 }
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038 private boolean estimateInitialCamerasAndPointsEssential() {
1039 final var intrinsic1 = configuration.getInitialIntrinsic1();
1040 final var intrinsic2 = configuration.getInitialIntrinsic2();
1041 return estimateInitialCamerasAndPointsEssential(intrinsic1, intrinsic2);
1042 }
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054 private boolean estimateInitialCamerasAndPointsEssential(
1055 final PinholeCameraIntrinsicParameters intrinsic1,
1056 final PinholeCameraIntrinsicParameters intrinsic2) {
1057 final var fundamentalMatrix = estimatedFundamentalMatrix.getFundamentalMatrix();
1058
1059
1060 final var samples1 = estimatedFundamentalMatrix.getLeftSamples();
1061 final var samples2 = estimatedFundamentalMatrix.getRightSamples();
1062
1063 final var points1 = new ArrayList<Point2D>();
1064 final var points2 = new ArrayList<Point2D>();
1065 final var length = samples1.size();
1066 for (var i = 0; i < length; i++) {
1067 final var sample1 = samples1.get(i);
1068 final var sample2 = samples2.get(i);
1069
1070 final var point1 = sample1.getPoint();
1071 final var point2 = sample2.getPoint();
1072
1073 points1.add(point1);
1074 points2.add(point2);
1075 }
1076
1077 try {
1078 final var estimator = new EssentialMatrixInitialCamerasEstimator(fundamentalMatrix, intrinsic1, intrinsic2,
1079 points1, points2);
1080
1081 estimator.setCorrectorType(configuration.getInitialCamerasCorrectorType());
1082 estimator.setPointsTriangulated(true);
1083 estimator.setValidTriangulatedPointsMarked(configuration.getInitialCamerasMarkValidTriangulatedPoints());
1084
1085 estimator.estimate();
1086
1087
1088 final var camera1 = estimator.getEstimatedLeftCamera();
1089 final var camera2 = estimator.getEstimatedRightCamera();
1090
1091 estimatedCamera1 = new EstimatedCamera();
1092 estimatedCamera1.setCamera(camera1);
1093
1094 estimatedCamera2 = new EstimatedCamera();
1095 estimatedCamera2.setCamera(camera2);
1096
1097
1098 final var triangulatedPoints = estimator.getTriangulatedPoints();
1099 final var validTriangulatedPoints = estimator.getValidTriangulatedPoints();
1100
1101 reconstructedPoints = new ArrayList<>();
1102 final var size = triangulatedPoints.size();
1103 for (var i = 0; i < size; i++) {
1104 final var reconstructedPoint = new ReconstructedPoint3D();
1105 reconstructedPoint.setPoint(triangulatedPoints.get(i));
1106 reconstructedPoint.setInlier(validTriangulatedPoints.get(i));
1107 reconstructedPoints.add(reconstructedPoint);
1108 }
1109
1110 return true;
1111 } catch (final Exception e) {
1112 return false;
1113 }
1114 }
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132 private void fixFundamentalMatrix(
1133 final FundamentalMatrix fundamentalMatrix,
1134 final PinholeCameraIntrinsicParameters intrinsicZeroPrincipalPoint1,
1135 final PinholeCameraIntrinsicParameters intrinsicZeroPrincipalPoint2,
1136 final PinholeCameraIntrinsicParameters intrinsicPrincipalPoint1,
1137 final PinholeCameraIntrinsicParameters intrinsicPrincipalPoint2)
1138 throws EpipolarException, NotReadyException {
1139
1140
1141 final var essential = new EssentialMatrix(fundamentalMatrix, intrinsicZeroPrincipalPoint1,
1142 intrinsicZeroPrincipalPoint2);
1143 final var fixedFundamentalMatrix = essential.toFundamentalMatrix(intrinsicPrincipalPoint1,
1144 intrinsicPrincipalPoint2);
1145 fixedFundamentalMatrix.normalize();
1146 estimatedFundamentalMatrix.setFundamentalMatrix(fixedFundamentalMatrix);
1147 estimatedFundamentalMatrix.setCovariance(null);
1148 }
1149 }