1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.irurueta.ar.sfm;
17
18 import com.irurueta.algebra.Matrix;
19 import com.irurueta.algebra.WrongSizeException;
20 import com.irurueta.ar.epipolar.Corrector;
21 import com.irurueta.ar.epipolar.CorrectorType;
22 import com.irurueta.ar.epipolar.EssentialMatrix;
23 import com.irurueta.ar.epipolar.FundamentalMatrix;
24 import com.irurueta.geometry.CameraException;
25 import com.irurueta.geometry.PinholeCamera;
26 import com.irurueta.geometry.PinholeCameraIntrinsicParameters;
27 import com.irurueta.geometry.Point2D;
28 import com.irurueta.geometry.Point3D;
29 import com.irurueta.geometry.Rotation3D;
30 import com.irurueta.geometry.estimators.LockedException;
31 import com.irurueta.geometry.estimators.NotReadyException;
32
33 import java.util.ArrayList;
34 import java.util.BitSet;
35 import java.util.List;
36
37
38
39
40
41
42
43
44
45
46 @SuppressWarnings("DuplicatedCode")
47 public class EssentialMatrixInitialCamerasEstimator extends InitialCamerasEstimator {
48
49
50
51
52 public static final boolean DEFAULT_TRIANGULATE_POINTS = false;
53
54
55
56
57
58 public static final boolean DEFAULT_MARK_VALID_TRIANGULATED_POINTS = false;
59
60
61
62
63 private PinholeCameraIntrinsicParameters leftIntrinsic;
64
65
66
67
68 private PinholeCameraIntrinsicParameters rightIntrinsic;
69
70
71
72
73 private List<Point2D> leftPoints;
74
75
76
77
78 private List<Point2D> rightPoints;
79
80
81
82
83
84 private CorrectorType correctorType = Corrector.DEFAULT_TYPE;
85
86
87
88
89 private boolean triangulatePoints = DEFAULT_TRIANGULATE_POINTS;
90
91
92
93
94
95 private boolean markValidTriangulatedPoints = DEFAULT_MARK_VALID_TRIANGULATED_POINTS;
96
97
98
99
100 private List<Point3D> triangulatedPoints;
101
102
103
104
105
106 private BitSet validTriangulatedPoints;
107
108
109
110
111 public EssentialMatrixInitialCamerasEstimator() {
112 super();
113 }
114
115
116
117
118
119
120 public EssentialMatrixInitialCamerasEstimator(final FundamentalMatrix fundamentalMatrix) {
121 super(fundamentalMatrix);
122 }
123
124
125
126
127
128
129
130
131
132 public EssentialMatrixInitialCamerasEstimator(
133 final PinholeCameraIntrinsicParameters leftIntrinsic,
134 final PinholeCameraIntrinsicParameters rightIntrinsic) {
135 super();
136 this.leftIntrinsic = leftIntrinsic;
137 this.rightIntrinsic = rightIntrinsic;
138 }
139
140
141
142
143
144
145
146
147
148
149 public EssentialMatrixInitialCamerasEstimator(
150 final FundamentalMatrix fundamentalMatrix,
151 final PinholeCameraIntrinsicParameters leftIntrinsic,
152 final PinholeCameraIntrinsicParameters rightIntrinsic) {
153 super(fundamentalMatrix);
154 this.leftIntrinsic = leftIntrinsic;
155 this.rightIntrinsic = rightIntrinsic;
156 }
157
158
159
160
161
162
163
164
165
166 public EssentialMatrixInitialCamerasEstimator(final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
167 super();
168 internalSetLeftAndRightPoints(leftPoints, rightPoints);
169 }
170
171
172
173
174
175
176
177
178
179
180 public EssentialMatrixInitialCamerasEstimator(
181 final FundamentalMatrix fundamentalMatrix, final List<Point2D> leftPoints,
182 final List<Point2D> rightPoints) {
183 super(fundamentalMatrix);
184 internalSetLeftAndRightPoints(leftPoints, rightPoints);
185 }
186
187
188
189
190
191
192
193
194
195
196
197
198
199 public EssentialMatrixInitialCamerasEstimator(
200 final PinholeCameraIntrinsicParameters leftIntrinsic,
201 final PinholeCameraIntrinsicParameters rightIntrinsic,
202 final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
203 this(leftIntrinsic, rightIntrinsic);
204 internalSetLeftAndRightPoints(leftPoints, rightPoints);
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220 public EssentialMatrixInitialCamerasEstimator(
221 final FundamentalMatrix fundamentalMatrix,
222 final PinholeCameraIntrinsicParameters leftIntrinsic,
223 final PinholeCameraIntrinsicParameters rightIntrinsic,
224 final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
225 this(fundamentalMatrix, leftIntrinsic, rightIntrinsic);
226 internalSetLeftAndRightPoints(leftPoints, rightPoints);
227 }
228
229
230
231
232
233
234 public EssentialMatrixInitialCamerasEstimator(final InitialCamerasEstimatorListener listener) {
235 super(listener);
236 }
237
238
239
240
241
242
243
244 public EssentialMatrixInitialCamerasEstimator(
245 final FundamentalMatrix fundamentalMatrix, final InitialCamerasEstimatorListener listener) {
246 super(fundamentalMatrix, listener);
247 }
248
249
250
251
252
253
254
255
256
257
258 public EssentialMatrixInitialCamerasEstimator(
259 final PinholeCameraIntrinsicParameters leftIntrinsic,
260 final PinholeCameraIntrinsicParameters rightIntrinsic,
261 final InitialCamerasEstimatorListener listener) {
262 super(listener);
263 this.leftIntrinsic = leftIntrinsic;
264 this.rightIntrinsic = rightIntrinsic;
265 }
266
267
268
269
270
271
272
273
274
275
276
277 public EssentialMatrixInitialCamerasEstimator(
278 final FundamentalMatrix fundamentalMatrix,
279 final PinholeCameraIntrinsicParameters leftIntrinsic,
280 final PinholeCameraIntrinsicParameters rightIntrinsic,
281 final InitialCamerasEstimatorListener listener) {
282 super(fundamentalMatrix, listener);
283 this.leftIntrinsic = leftIntrinsic;
284 this.rightIntrinsic = rightIntrinsic;
285 }
286
287
288
289
290
291
292
293
294
295
296 public EssentialMatrixInitialCamerasEstimator(
297 final List<Point2D> leftPoints,
298 final List<Point2D> rightPoints,
299 final InitialCamerasEstimatorListener listener) {
300 super(listener);
301 internalSetLeftAndRightPoints(leftPoints, rightPoints);
302 }
303
304
305
306
307
308
309
310
311
312
313
314 public EssentialMatrixInitialCamerasEstimator(
315 final FundamentalMatrix fundamentalMatrix,
316 final List<Point2D> leftPoints,
317 final List<Point2D> rightPoints,
318 final InitialCamerasEstimatorListener listener) {
319 super(fundamentalMatrix, listener);
320 internalSetLeftAndRightPoints(leftPoints, rightPoints);
321 }
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336 public EssentialMatrixInitialCamerasEstimator(
337 final PinholeCameraIntrinsicParameters leftIntrinsic,
338 final PinholeCameraIntrinsicParameters rightIntrinsic,
339 final List<Point2D> leftPoints,
340 final List<Point2D> rightPoints,
341 final InitialCamerasEstimatorListener listener) {
342 this(leftIntrinsic, rightIntrinsic, listener);
343 internalSetLeftAndRightPoints(leftPoints, rightPoints);
344 }
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360 public EssentialMatrixInitialCamerasEstimator(
361 final FundamentalMatrix fundamentalMatrix,
362 final PinholeCameraIntrinsicParameters leftIntrinsic,
363 final PinholeCameraIntrinsicParameters rightIntrinsic,
364 final List<Point2D> leftPoints,
365 final List<Point2D> rightPoints,
366 final InitialCamerasEstimatorListener listener) {
367 this(fundamentalMatrix, leftIntrinsic, rightIntrinsic, listener);
368 internalSetLeftAndRightPoints(leftPoints, rightPoints);
369 }
370
371
372
373
374
375
376 @Override
377 public InitialCamerasEstimatorMethod getMethod() {
378 return InitialCamerasEstimatorMethod.ESSENTIAL_MATRIX;
379 }
380
381
382
383
384
385
386 @Override
387 public boolean isReady() {
388 return fundamentalMatrix != null && leftIntrinsic != null && rightIntrinsic != null && leftPoints != null
389 && rightPoints != null && leftPoints.size() == rightPoints.size();
390 }
391
392
393
394
395
396
397
398
399
400
401 @Override
402 public void estimate() throws LockedException, NotReadyException, InitialCamerasEstimationFailedException {
403 if (isLocked()) {
404 throw new LockedException();
405 }
406
407 if (!isReady()) {
408 throw new NotReadyException();
409 }
410
411 try {
412 locked = true;
413
414 if (listener != null) {
415 listener.onStart(this);
416 }
417
418 if (triangulatePoints) {
419 triangulatedPoints = new ArrayList<>();
420 } else {
421 triangulatedPoints = null;
422 }
423
424 final var nPoints = leftPoints.size();
425 if (markValidTriangulatedPoints) {
426 validTriangulatedPoints = new BitSet(nPoints);
427 } else {
428 validTriangulatedPoints = null;
429 }
430
431 if (estimatedLeftCamera == null) {
432 estimatedLeftCamera = new PinholeCamera();
433 }
434 if (estimatedRightCamera == null) {
435 estimatedRightCamera = new PinholeCamera();
436 }
437
438 generateInitialMetricCamerasFromEssentialMatrix(fundamentalMatrix, leftIntrinsic, rightIntrinsic,
439 leftPoints, rightPoints, correctorType, estimatedLeftCamera, estimatedRightCamera,
440 triangulatedPoints, validTriangulatedPoints);
441
442 if (listener != null) {
443 listener.onFinish(this, estimatedLeftCamera, estimatedRightCamera);
444 }
445 } catch (final InitialCamerasEstimationFailedException e) {
446 if (listener != null) {
447 listener.onFail(this, e);
448 }
449 throw e;
450 } finally {
451 locked = false;
452 }
453 }
454
455
456
457
458
459
460 public PinholeCameraIntrinsicParameters getLeftIntrinsic() {
461 return leftIntrinsic;
462 }
463
464
465
466
467
468
469
470
471 public void setLeftIntrinsic(
472 final PinholeCameraIntrinsicParameters leftIntrinsic) throws LockedException {
473 if (isLocked()) {
474 throw new LockedException();
475 }
476 this.leftIntrinsic = leftIntrinsic;
477 }
478
479
480
481
482
483
484 public PinholeCameraIntrinsicParameters getRightIntrinsic() {
485 return rightIntrinsic;
486 }
487
488
489
490
491
492
493
494
495 public void setRightIntrinsic(
496 final PinholeCameraIntrinsicParameters rightIntrinsic) throws LockedException {
497 if (isLocked()) {
498 throw new LockedException();
499 }
500 this.rightIntrinsic = rightIntrinsic;
501 }
502
503
504
505
506
507
508
509
510
511
512
513 public void setLeftAndRightIntrinsics(
514 final PinholeCameraIntrinsicParameters leftIntrinsic,
515 final PinholeCameraIntrinsicParameters rightIntrinsic) throws LockedException {
516 if (isLocked()) {
517 throw new LockedException();
518 }
519 this.leftIntrinsic = leftIntrinsic;
520 this.rightIntrinsic = rightIntrinsic;
521 }
522
523
524
525
526
527
528
529
530 public void setIntrinsicsForBoth(final PinholeCameraIntrinsicParameters intrinsic) throws LockedException {
531 if (isLocked()) {
532 throw new LockedException();
533 }
534 leftIntrinsic = rightIntrinsic = intrinsic;
535 }
536
537
538
539
540
541
542 public List<Point2D> getLeftPoints() {
543 return leftPoints;
544 }
545
546
547
548
549
550
551
552 public void setLeftPoints(final List<Point2D> leftPoints) throws LockedException {
553 if (isLocked()) {
554 throw new LockedException();
555 }
556 this.leftPoints = leftPoints;
557 }
558
559
560
561
562
563
564 public List<Point2D> getRightPoints() {
565 return rightPoints;
566 }
567
568
569
570
571
572
573
574 public void setRightPoints(final List<Point2D> rightPoints) throws LockedException {
575 if (isLocked()) {
576 throw new LockedException();
577 }
578 this.rightPoints = rightPoints;
579 }
580
581
582
583
584
585
586
587
588
589
590 public void setLeftAndRightPoints(
591 final List<Point2D> leftPoints, final List<Point2D> rightPoints) throws LockedException {
592 if (isLocked()) {
593 throw new LockedException();
594 }
595 internalSetLeftAndRightPoints(leftPoints, rightPoints);
596 }
597
598
599
600
601
602
603
604 public CorrectorType getCorrectorType() {
605 return correctorType;
606 }
607
608
609
610
611
612
613
614
615 public void setCorrectorType(final CorrectorType correctorType) throws LockedException {
616 if (isLocked()) {
617 throw new LockedException();
618 }
619 this.correctorType = correctorType;
620 }
621
622
623
624
625
626
627 public boolean arePointsTriangulated() {
628 return triangulatePoints;
629 }
630
631
632
633
634
635
636
637
638 public void setPointsTriangulated(final boolean triangulatePoints) throws LockedException {
639 if (isLocked()) {
640 throw new LockedException();
641 }
642 this.triangulatePoints = triangulatePoints;
643 }
644
645
646
647
648
649
650
651
652 public boolean areValidTriangulatedPointsMarked() {
653 return markValidTriangulatedPoints;
654 }
655
656
657
658
659
660
661
662
663
664 public void setValidTriangulatedPointsMarked(final boolean markValidTriangulatedPoints) throws LockedException {
665 if (isLocked()) {
666 throw new LockedException();
667 }
668 this.markValidTriangulatedPoints = markValidTriangulatedPoints;
669 }
670
671
672
673
674
675
676 public List<Point3D> getTriangulatedPoints() {
677 return triangulatedPoints;
678 }
679
680
681
682
683
684
685
686
687 public BitSet getValidTriangulatedPoints() {
688 return validTriangulatedPoints;
689 }
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722 public static int generateInitialMetricCamerasFromEssentialMatrix(
723 final FundamentalMatrix fundamentalMatrix,
724 final PinholeCameraIntrinsicParameters leftIntrinsic,
725 final PinholeCameraIntrinsicParameters rightIntrinsic,
726 final List<Point2D> leftPoints, final List<Point2D> rightPoints,
727 final PinholeCamera leftCamera, final PinholeCamera rightCamera)
728 throws InitialCamerasEstimationFailedException {
729 return generateInitialMetricCamerasFromEssentialMatrix(
730 fundamentalMatrix, leftIntrinsic, rightIntrinsic, leftPoints,
731 rightPoints, Corrector.DEFAULT_TYPE, leftCamera, rightCamera);
732 }
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769 public static int generateInitialMetricCamerasFromEssentialMatrix(
770 final FundamentalMatrix fundamentalMatrix,
771 final PinholeCameraIntrinsicParameters leftIntrinsic,
772 final PinholeCameraIntrinsicParameters rightIntrinsic,
773 final List<Point2D> leftPoints, final List<Point2D> rightPoints,
774 final CorrectorType correctorType, final PinholeCamera leftCamera,
775 final PinholeCamera rightCamera) throws InitialCamerasEstimationFailedException {
776 return generateInitialMetricCamerasFromEssentialMatrix(
777 fundamentalMatrix, leftIntrinsic, rightIntrinsic, leftPoints,
778 rightPoints, correctorType, leftCamera, rightCamera, null,
779 null);
780 }
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817 public static int generateInitialMetricCamerasFromEssentialMatrix(
818 final FundamentalMatrix fundamentalMatrix,
819 final PinholeCameraIntrinsicParameters leftIntrinsic,
820 final PinholeCameraIntrinsicParameters rightIntrinsic,
821 final List<Point2D> leftPoints, final List<Point2D> rightPoints,
822 final PinholeCamera leftCamera, final PinholeCamera rightCamera,
823 final List<Point3D> triangulatedPoints, final BitSet validTriangulatedPoints)
824 throws InitialCamerasEstimationFailedException {
825
826 return generateInitialMetricCamerasFromEssentialMatrix(
827 fundamentalMatrix, leftIntrinsic, rightIntrinsic, leftPoints,
828 rightPoints, Corrector.DEFAULT_TYPE, leftCamera, rightCamera,
829 triangulatedPoints, validTriangulatedPoints);
830 }
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870 public static int generateInitialMetricCamerasFromEssentialMatrix(
871 final FundamentalMatrix fundamentalMatrix,
872 final PinholeCameraIntrinsicParameters leftIntrinsic,
873 final PinholeCameraIntrinsicParameters rightIntrinsic,
874 final List<Point2D> leftPoints, final List<Point2D> rightPoints,
875 final CorrectorType correctorType, final PinholeCamera leftCamera,
876 final PinholeCamera rightCamera, final List<Point3D> triangulatedPoints,
877 final BitSet validTriangulatedPoints)
878 throws InitialCamerasEstimationFailedException {
879
880 if (leftPoints.size() != rightPoints.size()) {
881 throw new IllegalArgumentException(
882 "left and right points must have the same size");
883 }
884
885 final List<Point2D> correctedLeftPoints;
886 final List<Point2D> correctedRightPoints;
887 final Rotation3D rotation1;
888 final Rotation3D rotation2;
889 final Point2D translation1;
890 final Point2D translation2;
891 try {
892 final var essential = new EssentialMatrix(fundamentalMatrix, leftIntrinsic, rightIntrinsic);
893
894 essential.computePossibleRotationAndTranslations();
895
896 rotation1 = essential.getFirstPossibleRotation();
897 translation1 = essential.getFirstPossibleTranslation();
898
899 rotation2 = essential.getSecondPossibleRotation();
900 translation2 = essential.getSecondPossibleTranslation();
901
902 if (correctorType != null) {
903
904 final var corrector = Corrector.create(leftPoints, rightPoints, fundamentalMatrix, correctorType);
905 corrector.correct();
906
907 correctedLeftPoints = corrector.getLeftCorrectedPoints();
908 correctedRightPoints = corrector.getRightCorrectedPoints();
909 } else {
910
911 correctedLeftPoints = leftPoints;
912 correctedRightPoints = rightPoints;
913 }
914 } catch (final Exception e) {
915 throw new InitialCamerasEstimationFailedException(e);
916 }
917
918 if (triangulatedPoints != null) {
919 triangulatedPoints.clear();
920 }
921 if (validTriangulatedPoints != null) {
922 validTriangulatedPoints.clear();
923 }
924 int numValidTriangulatedPoints;
925
926 final var numPoints = correctedLeftPoints.size();
927 var skip = false;
928
929
930
931 try {
932 numValidTriangulatedPoints = computeCamerasAndTriangulation(rotation1, translation1,
933 leftIntrinsic, rightIntrinsic, correctedLeftPoints, correctedRightPoints, leftCamera, rightCamera,
934 triangulatedPoints, validTriangulatedPoints);
935 } catch (final Exception e) {
936 numValidTriangulatedPoints = 0;
937 }
938
939 if (numValidTriangulatedPoints >= numPoints) {
940
941
942 skip = true;
943 }
944
945 final var attemptLeftCamera = new PinholeCamera();
946 final var attemptRightCamera = new PinholeCamera();
947 List<Point3D> attemptTriangulatedPoints = null;
948 if (triangulatedPoints != null) {
949 attemptTriangulatedPoints = new ArrayList<>();
950 }
951 BitSet attemptValidTriangulatedPoints = null;
952 if (validTriangulatedPoints != null) {
953 attemptValidTriangulatedPoints = new BitSet(numPoints);
954 }
955 int attemptNumValidTriangulatedPoints;
956
957 if (!skip) {
958
959
960 try {
961 attemptNumValidTriangulatedPoints = computeCamerasAndTriangulation(rotation1, translation2,
962 leftIntrinsic, rightIntrinsic, correctedLeftPoints, correctedRightPoints, attemptLeftCamera,
963 attemptRightCamera, attemptTriangulatedPoints, attemptValidTriangulatedPoints);
964 } catch (final Exception e) {
965 attemptNumValidTriangulatedPoints = 0;
966 }
967
968 if (attemptNumValidTriangulatedPoints >= numPoints) {
969
970
971 skip = true;
972 }
973
974 if (attemptNumValidTriangulatedPoints > numValidTriangulatedPoints) {
975
976
977
978 updateBestSolutionData(leftCamera, rightCamera, triangulatedPoints, validTriangulatedPoints,
979 attemptLeftCamera, attemptRightCamera, attemptTriangulatedPoints,
980 attemptValidTriangulatedPoints);
981 numValidTriangulatedPoints = attemptNumValidTriangulatedPoints;
982 }
983 }
984
985 if (!skip) {
986
987
988 try {
989 attemptNumValidTriangulatedPoints = computeCamerasAndTriangulation(rotation2, translation1,
990 leftIntrinsic, rightIntrinsic, correctedLeftPoints, correctedRightPoints, attemptLeftCamera,
991 attemptRightCamera, attemptTriangulatedPoints, attemptValidTriangulatedPoints);
992 } catch (final Exception e) {
993 attemptNumValidTriangulatedPoints = 0;
994 }
995
996 if (attemptNumValidTriangulatedPoints >= numPoints) {
997
998
999 skip = true;
1000 }
1001
1002 if (attemptNumValidTriangulatedPoints > numValidTriangulatedPoints) {
1003
1004
1005
1006 updateBestSolutionData(leftCamera, rightCamera, triangulatedPoints, validTriangulatedPoints,
1007 attemptLeftCamera, attemptRightCamera, attemptTriangulatedPoints,
1008 attemptValidTriangulatedPoints);
1009 numValidTriangulatedPoints = attemptNumValidTriangulatedPoints;
1010 }
1011 }
1012
1013 if (!skip) {
1014
1015
1016 try {
1017 attemptNumValidTriangulatedPoints = computeCamerasAndTriangulation(rotation2, translation2,
1018 leftIntrinsic, rightIntrinsic, correctedLeftPoints, correctedRightPoints, attemptLeftCamera,
1019 attemptRightCamera, attemptTriangulatedPoints, attemptValidTriangulatedPoints);
1020 } catch (final Exception e) {
1021 attemptNumValidTriangulatedPoints = 0;
1022 }
1023
1024 if (attemptNumValidTriangulatedPoints > numValidTriangulatedPoints) {
1025
1026
1027
1028 updateBestSolutionData(leftCamera, rightCamera, triangulatedPoints, validTriangulatedPoints,
1029 attemptLeftCamera, attemptRightCamera, attemptTriangulatedPoints,
1030 attemptValidTriangulatedPoints);
1031 numValidTriangulatedPoints = attemptNumValidTriangulatedPoints;
1032 }
1033 }
1034
1035 if (numValidTriangulatedPoints == 0) {
1036 throw new InitialCamerasEstimationFailedException("no valid points found");
1037 }
1038
1039 return numValidTriangulatedPoints;
1040 }
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052 private void internalSetLeftAndRightPoints(final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
1053 if (leftPoints == null || rightPoints == null || leftPoints.size() != rightPoints.size()) {
1054 throw new IllegalArgumentException();
1055 }
1056 this.leftPoints = leftPoints;
1057 this.rightPoints = rightPoints;
1058 }
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082 private static void updateBestSolutionData(
1083 final PinholeCamera leftCamera,
1084 final PinholeCamera rightCamera,
1085 final List<Point3D> triangulatedPoints,
1086 final BitSet validTriangulatedPoints,
1087 final PinholeCamera attemptLeftCamera,
1088 final PinholeCamera attemptRightCamera,
1089 final List<Point3D> attemptTriangulatedPoints,
1090 final BitSet attemptValidTriangulatedPoints)
1091 throws InitialCamerasEstimationFailedException {
1092
1093 try {
1094 leftCamera.setInternalMatrix(attemptLeftCamera.getInternalMatrix());
1095 rightCamera.setInternalMatrix(attemptRightCamera.getInternalMatrix());
1096 if (triangulatedPoints != null && attemptTriangulatedPoints != null) {
1097 triangulatedPoints.clear();
1098 triangulatedPoints.addAll(attemptTriangulatedPoints);
1099 }
1100 if (validTriangulatedPoints != null && attemptValidTriangulatedPoints != null) {
1101 validTriangulatedPoints.clear();
1102 validTriangulatedPoints.or(attemptValidTriangulatedPoints);
1103 }
1104 } catch (final WrongSizeException e) {
1105 throw new InitialCamerasEstimationFailedException(e);
1106 }
1107 }
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146 private static int computeCamerasAndTriangulation(
1147 final Rotation3D rotation,
1148 final Point2D translation,
1149 final PinholeCameraIntrinsicParameters leftIntrinsic,
1150 final PinholeCameraIntrinsicParameters rightIntrinsic,
1151 final List<Point2D> leftPoints,
1152 final List<Point2D> rightPoints,
1153 final PinholeCamera estimatedLeftCamera,
1154 final PinholeCamera estimatedRightCamera,
1155 final List<Point3D> triangulatedPoints,
1156 final BitSet validTriangulatedPoints) throws WrongSizeException, CameraException, LockedException,
1157 NotReadyException, Point3DTriangulationException {
1158
1159 if (triangulatedPoints != null) {
1160 triangulatedPoints.clear();
1161 }
1162 if (validTriangulatedPoints != null) {
1163 validTriangulatedPoints.clear();
1164 }
1165 var numValidTriangulatedPoints = 0;
1166
1167 final var leftIntrinsicMatrix = leftIntrinsic.getInternalMatrix();
1168 final var rightIntrinsicMatrix = rightIntrinsic.getInternalMatrix();
1169
1170 final var rotationMatrix = rotation.asInhomogeneousMatrix();
1171
1172
1173
1174
1175 final var tmp = Matrix.identity(PinholeCamera.PINHOLE_CAMERA_MATRIX_ROWS,
1176 PinholeCamera.PINHOLE_CAMERA_MATRIX_COLS);
1177
1178
1179 leftIntrinsicMatrix.multiply(tmp);
1180
1181
1182 estimatedLeftCamera.setInternalMatrix(leftIntrinsicMatrix);
1183 estimatedLeftCamera.normalize();
1184 estimatedLeftCamera.fixCameraSign();
1185
1186
1187
1188
1189 tmp.setSubmatrix(0, 0, 2, 2, rotationMatrix);
1190
1191
1192 translation.normalize();
1193 tmp.setElementAt(0, 3, translation.getHomX());
1194 tmp.setElementAt(1, 3, translation.getHomY());
1195 tmp.setElementAt(2, 3, translation.getHomW());
1196
1197
1198 rightIntrinsicMatrix.multiply(tmp);
1199
1200
1201 estimatedRightCamera.setInternalMatrix(rightIntrinsicMatrix);
1202 estimatedRightCamera.normalize();
1203 estimatedRightCamera.fixCameraSign();
1204
1205
1206 final var triangulator = SinglePoint3DTriangulator.create();
1207
1208 final var numPoints = leftPoints.size();
1209 Point2D leftPoint;
1210 Point2D rightPoint;
1211 final var points = new ArrayList<Point2D>();
1212 final var cameras = new ArrayList<PinholeCamera>();
1213 Point3D triangulatedPoint;
1214 boolean frontLeft;
1215 boolean frontRight;
1216 for (var i = 0; i < numPoints; i++) {
1217 leftPoint = leftPoints.get(i);
1218 rightPoint = rightPoints.get(i);
1219
1220 points.clear();
1221 points.add(leftPoint);
1222 points.add(rightPoint);
1223
1224 cameras.clear();
1225 cameras.add(estimatedLeftCamera);
1226 cameras.add(estimatedRightCamera);
1227
1228 triangulator.setPointsAndCameras(points, cameras);
1229 triangulatedPoint = triangulator.triangulate();
1230 if (triangulatedPoints != null) {
1231 triangulatedPoints.add(triangulatedPoint);
1232 }
1233
1234
1235 frontLeft = estimatedLeftCamera.isPointInFrontOfCamera(triangulatedPoint);
1236 frontRight = estimatedRightCamera.isPointInFrontOfCamera(triangulatedPoint);
1237
1238 if (frontLeft && frontRight) {
1239
1240 if (validTriangulatedPoints != null) {
1241 validTriangulatedPoints.set(i);
1242 }
1243 numValidTriangulatedPoints++;
1244 } else {
1245
1246 if (validTriangulatedPoints != null) {
1247 validTriangulatedPoints.clear(i);
1248 }
1249 }
1250 }
1251
1252 return numValidTriangulatedPoints;
1253 }
1254 }