View Javadoc
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.ar.calibration.estimators.KruppaDualImageOfAbsoluteConicEstimator;
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.geometry.PinholeCamera;
23  import com.irurueta.geometry.Point2D;
24  import com.irurueta.geometry.Point3D;
25  import com.irurueta.geometry.estimators.LockedException;
26  import com.irurueta.geometry.estimators.NotReadyException;
27  
28  import java.util.ArrayList;
29  import java.util.BitSet;
30  import java.util.List;
31  
32  /**
33   * Estimates an initial pair of cameras in the metric stratum (up to an
34   * arbitrary scale) using a given fundamental matrix to obtain the Dual Image
35   * of Absolute Conic by solving Kruppa equations to obtain the Essential matrix,
36   * so that once it is computed it can be used to determine best pair of camera
37   * poses and translations by triangulating a set of matched points and checking
38   * that their triangulation lies in front of cameras.
39   */
40  public class DualImageOfAbsoluteConicInitialCamerasEstimator extends InitialCamerasEstimator {
41  
42      /**
43       * Indicates whether matched 2D points must be triangulated by default.
44       */
45      public static final boolean DEFAULT_TRIANGULATE_POINTS = false;
46  
47      /**
48       * Indicates whether triangulated points must be marked as valid (i.e. when
49       * they lie in front of both of the estimated cameras) or not.
50       */
51      public static final boolean DEFAULT_MARK_VALID_TRIANGULATED_POINTS = false;
52  
53      /**
54       * Aspect ratio of intrinsic parameters of cameras.
55       * Typically, this value is 1.0 if vertical coordinates increase upwards,
56       * or -1.0 if it is the opposite.
57       */
58      private double aspectRatio = KruppaDualImageOfAbsoluteConicEstimator.DEFAULT_FOCAL_DISTANCE_ASPECT_RATIO;
59  
60      /**
61       * Horizontal coordinate of principal point. This value should be the
62       * coordinates of the center of an image assuming that the coordinates start
63       * on the top-left or bottom-left corner. Using a value close to zero
64       * will produce inaccurate results.
65       */
66      private double principalPointX;
67  
68      /**
69       * Vertical coordinate of principal point. This value should be the
70       * coordinates of the center of an image assuming that the coordinates start
71       * on the top-left or bottom-left corner. Using a value close to zero will
72       * produce inaccurate results.
73       */
74      private double principalPointY;
75  
76      /**
77       * Matched 2D points on left view.
78       */
79      private List<Point2D> leftPoints;
80  
81      /**
82       * Matched 2D points on right view.
83       */
84      private List<Point2D> rightPoints;
85  
86      /**
87       * Type of corrector to use to triangulate matched points or null if no
88       * corrector needs to be used.
89       */
90      private CorrectorType correctorType = Corrector.DEFAULT_TYPE;
91  
92      /**
93       * Indicates whether matched 2D points need to be triangulated.
94       */
95      private boolean triangulatePoints = DEFAULT_TRIANGULATE_POINTS;
96  
97      /**
98       * Marks which of the triangulated points are marked as valid (lie in front
99       * of both of the estimated cameras) and which ones aren't.
100      */
101     private boolean markValidTriangulatedPoints = DEFAULT_MARK_VALID_TRIANGULATED_POINTS;
102 
103     /**
104      * Contains triangulated points.
105      */
106     private List<Point3D> triangulatedPoints;
107 
108     /**
109      * Contains booleans indicating whether triangulated points are valid (i.e.
110      * lie in front of both estimated cameras) or not.
111      */
112     private BitSet validTriangulatedPoints;
113 
114     /**
115      * Constructor.
116      */
117     public DualImageOfAbsoluteConicInitialCamerasEstimator() {
118         super();
119     }
120 
121     /**
122      * Constructor.
123      *
124      * @param fundamentalMatrix fundamental matrix relating two views.
125      */
126     public DualImageOfAbsoluteConicInitialCamerasEstimator(final FundamentalMatrix fundamentalMatrix) {
127         super(fundamentalMatrix);
128     }
129 
130     /**
131      * Constructor.
132      *
133      * @param leftPoints  matched 2D points on left view.
134      * @param rightPoints matched 2D points on right view.
135      * @throws IllegalArgumentException if provided lists don't have the same
136      *                                  size.
137      */
138     public DualImageOfAbsoluteConicInitialCamerasEstimator(
139             final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
140         super();
141         internalSetLeftAndRightPoints(leftPoints, rightPoints);
142     }
143 
144     /**
145      * Constructor.
146      *
147      * @param fundamentalMatrix fundamental matrix relating two views.
148      * @param leftPoints        matched 2D points on left view.
149      * @param rightPoints       matched 2D points on right view.
150      * @throws IllegalArgumentException if provided lists don't have the same
151      *                                  size.
152      */
153     public DualImageOfAbsoluteConicInitialCamerasEstimator(
154             final FundamentalMatrix fundamentalMatrix, final List<Point2D> leftPoints,
155             final List<Point2D> rightPoints) {
156         super(fundamentalMatrix);
157         internalSetLeftAndRightPoints(leftPoints, rightPoints);
158     }
159 
160     /**
161      * Constructor.
162      *
163      * @param listener listener to handle events raised by this instance.
164      */
165     public DualImageOfAbsoluteConicInitialCamerasEstimator(final InitialCamerasEstimatorListener listener) {
166         super(listener);
167     }
168 
169     /**
170      * Constructor.
171      *
172      * @param fundamentalMatrix fundamental matrix relating two views.
173      * @param listener          listener to handle events raised by this instance.
174      */
175     public DualImageOfAbsoluteConicInitialCamerasEstimator(
176             final FundamentalMatrix fundamentalMatrix, final InitialCamerasEstimatorListener listener) {
177         super(fundamentalMatrix, listener);
178     }
179 
180     /**
181      * Constructor.
182      *
183      * @param leftPoints  matched 2D points on left view.
184      * @param rightPoints matched 2D points on right view.
185      * @param listener    listener to handle events raised by this instance.
186      * @throws IllegalArgumentException if provided lists don't have the same
187      *                                  size.
188      */
189     public DualImageOfAbsoluteConicInitialCamerasEstimator(
190             final List<Point2D> leftPoints, final List<Point2D> rightPoints,
191             final InitialCamerasEstimatorListener listener) {
192         super(listener);
193         internalSetLeftAndRightPoints(leftPoints, rightPoints);
194     }
195 
196     /**
197      * Constructor.
198      *
199      * @param fundamentalMatrix fundamental matrix relating two views.
200      * @param leftPoints        matched 2D points on left view.
201      * @param rightPoints       matched 2D points on right view.
202      * @param listener          listener to handle events raised by this instance.
203      * @throws IllegalArgumentException if provided lists don't have the same
204      *                                  size.
205      */
206     public DualImageOfAbsoluteConicInitialCamerasEstimator(
207             final FundamentalMatrix fundamentalMatrix,
208             final List<Point2D> leftPoints,
209             final List<Point2D> rightPoints,
210             final InitialCamerasEstimatorListener listener) {
211         super(fundamentalMatrix, listener);
212         internalSetLeftAndRightPoints(leftPoints, rightPoints);
213     }
214 
215     /**
216      * Returns method used by this estimator.
217      *
218      * @return method used by this estimator.
219      */
220     @Override
221     public InitialCamerasEstimatorMethod getMethod() {
222         return InitialCamerasEstimatorMethod.DUAL_IMAGE_OF_ABSOLUTE_CONIC;
223     }
224 
225     /**
226      * Indicates if estimator is ready.
227      *
228      * @return true if estimator is ready, false otherwise.
229      */
230     @Override
231     public boolean isReady() {
232         return fundamentalMatrix != null && leftPoints != null && rightPoints != null
233                 && leftPoints.size() == rightPoints.size();
234     }
235 
236     /**
237      * Estimates cameras.
238      *
239      * @throws LockedException                         if estimator is locked.
240      * @throws NotReadyException                       if estimator is not ready.
241      * @throws InitialCamerasEstimationFailedException if estimation of cameras
242      *                                                 fails for some reason, typically due to numerical
243      *                                                 instabilities.
244      */
245     @SuppressWarnings("DuplicatedCode")
246     @Override
247     public void estimate() throws LockedException, NotReadyException, InitialCamerasEstimationFailedException {
248         if (isLocked()) {
249             throw new LockedException();
250         }
251 
252         if (!isReady()) {
253             throw new NotReadyException();
254         }
255 
256         try {
257             locked = true;
258 
259             if (listener != null) {
260                 listener.onStart(this);
261             }
262 
263             if (triangulatePoints) {
264                 triangulatedPoints = new ArrayList<>();
265             } else {
266                 triangulatedPoints = null;
267             }
268 
269             final var nPoints = leftPoints.size();
270             if (markValidTriangulatedPoints) {
271                 validTriangulatedPoints = new BitSet(nPoints);
272             } else {
273                 validTriangulatedPoints = null;
274             }
275 
276             if (estimatedLeftCamera == null) {
277                 estimatedLeftCamera = new PinholeCamera();
278             }
279             if (estimatedRightCamera == null) {
280                 estimatedRightCamera = new PinholeCamera();
281             }
282 
283             generateInitialMetricCamerasUsingDIAC(fundamentalMatrix, principalPointX, principalPointY, aspectRatio,
284                     leftPoints, rightPoints, correctorType, estimatedLeftCamera, estimatedRightCamera,
285                     triangulatedPoints, validTriangulatedPoints);
286 
287             if (listener != null) {
288                 listener.onFinish(this, estimatedLeftCamera, estimatedRightCamera);
289             }
290         } catch (final InitialCamerasEstimationFailedException e) {
291             if (listener != null) {
292                 listener.onFail(this, e);
293             }
294             throw e;
295         } finally {
296             locked = false;
297         }
298     }
299 
300     /**
301      * Gets aspect ratio of intrinsic parameters of cameras.
302      * Typically, this value is 1.0 if vertical coordinates increase upwards,
303      * or -1.0 if it is the opposite.
304      *
305      * @return aspect ratio of intrinsic parameters of cameras.
306      */
307     public double getAspectRatio() {
308         return aspectRatio;
309     }
310 
311     /**
312      * Sets aspect ratio of intrinsic parameters of cameras.
313      * Typically, this value is 1.0 if vertical coordinates increase upwards,
314      * or -1.0 if it is the opposite.
315      *
316      * @param aspectRatio aspect ratio of intrinsic parameters of cameras.
317      * @throws LockedException if estimator is locked.
318      */
319     public void setAspectRatio(final double aspectRatio) throws LockedException {
320         if (isLocked()) {
321             throw new LockedException();
322         }
323         this.aspectRatio = aspectRatio;
324     }
325 
326     /**
327      * Gets horizontal coordinate of principal point. This value should be the
328      * coordinates of the center of an image assuming that the coordinates start
329      * on the top-left or bottom-left corner. Using a value close to zero
330      * will produce inaccurate results.
331      *
332      * @return horizontal coordinate of principal point.
333      */
334     public double getPrincipalPointX() {
335         return principalPointX;
336     }
337 
338     /**
339      * Sets horizontal coordinate of principal point. This value should be the
340      * coordinates of the center of an image assuming that the coordinates start
341      * on the top-left or bottom-left corner. Using a value close to zero
342      * will produce inaccurate results.
343      *
344      * @param principalPointX horizontal coordinate of principal point.
345      * @throws LockedException if estimator is locked.
346      */
347     public void setPrincipalPointX(final double principalPointX) throws LockedException {
348         if (isLocked()) {
349             throw new LockedException();
350         }
351         this.principalPointX = principalPointX;
352     }
353 
354     /**
355      * Gets vertical coordinate of principal point. This value should be the
356      * coordinates of the center of an image assuming that the coordinates start
357      * on the top-left or bottom-left corner. Using a value close to zero will
358      * produce inaccurate results.
359      *
360      * @return vertical coordinate of principal point.
361      */
362     public double getPrincipalPointY() {
363         return principalPointY;
364     }
365 
366     /**
367      * Sets vertical coordinate of principal point. This value should be the
368      * coordinates of the center of an image assuming that the coordinates start
369      * on the top-left or bottom-left corner. Using a value close to zero will
370      * produce inaccurate results.
371      *
372      * @param principalPointY vertical coordinate of principal point.
373      * @throws LockedException if estimator is locked.
374      */
375     public void setPrincipalPointY(final double principalPointY) throws LockedException {
376         if (isLocked()) {
377             throw new LockedException();
378         }
379         this.principalPointY = principalPointY;
380     }
381 
382     /**
383      * Sets horizontal and vertical coordinates of principal point. This value
384      * should be the coordinates of the center of an image assuming that the
385      * coordinates start on the top-left or bottom-left corner. Using a value
386      * close to zero will produce inaccurate results.
387      *
388      * @param principalPointX horizontal coordinate of principal point.
389      * @param principalPointY vertical coordinate of principal point.
390      * @throws LockedException if estimator is locked.
391      */
392     public void setPrincipalPoint(final double principalPointX, final double principalPointY) throws LockedException {
393         if (isLocked()) {
394             throw new LockedException();
395         }
396         this.principalPointX = principalPointX;
397         this.principalPointY = principalPointY;
398     }
399 
400     /**
401      * Gets matched 2D points on left view.
402      *
403      * @return matched 2D points on left view.
404      */
405     public List<Point2D> getLeftPoints() {
406         return leftPoints;
407     }
408 
409     /**
410      * Sets matched 2D points on left view.
411      *
412      * @param leftPoints matched 2D points on left view.
413      * @throws LockedException if estimator is locked.
414      */
415     public void setLeftPoints(final List<Point2D> leftPoints) throws LockedException {
416         if (isLocked()) {
417             throw new LockedException();
418         }
419         this.leftPoints = leftPoints;
420     }
421 
422     /**
423      * Gets matched 2D points on right view.
424      *
425      * @return matched 2D points on right view.
426      */
427     public List<Point2D> getRightPoints() {
428         return rightPoints;
429     }
430 
431     /**
432      * Sets matched 2D points on right view.
433      *
434      * @param rightPoints matched 2D points on right view.
435      * @throws LockedException if estimator is locked.
436      */
437     public void setRightPoints(final List<Point2D> rightPoints) throws LockedException {
438         if (isLocked()) {
439             throw new LockedException();
440         }
441         this.rightPoints = rightPoints;
442     }
443 
444     /**
445      * Sets matched 2D points on left and right views.
446      *
447      * @param leftPoints  matched 2D points on left view.
448      * @param rightPoints matched 2D points on right view.
449      * @throws LockedException          if estimator is locked.
450      * @throws IllegalArgumentException if provided lists don't have the same
451      *                                  size.
452      */
453     public void setLeftAndRightPoints(final List<Point2D> leftPoints, final List<Point2D> rightPoints)
454             throws LockedException {
455         if (isLocked()) {
456             throw new LockedException();
457         }
458         internalSetLeftAndRightPoints(leftPoints, rightPoints);
459     }
460 
461     /**
462      * Gets type of corrector to use to triangulate matched points or null if
463      * no corrector needs to be used.
464      *
465      * @return type of corrector to use.
466      */
467     public CorrectorType getCorrectorType() {
468         return correctorType;
469     }
470 
471     /**
472      * Sets type of corrector to use to triangulate matched points or null if
473      * no corrector needs to be used.
474      *
475      * @param correctorType type of corrector to use.
476      * @throws LockedException if estimator is locked.
477      */
478     public void setCorrectorType(final CorrectorType correctorType) throws LockedException {
479         if (isLocked()) {
480             throw new LockedException();
481         }
482         this.correctorType = correctorType;
483     }
484 
485     /**
486      * Indicates whether matched 2D points need to be triangulated or not.
487      *
488      * @return true if 2D points need to be triangulated, false otherwise.
489      */
490     public boolean arePointsTriangulated() {
491         return triangulatePoints;
492     }
493 
494     /**
495      * Specifies whether matched 2D points need to be triangulated or not.
496      *
497      * @param triangulatePoints true if 2D points need to be triangulated, false
498      *                          otherwise.
499      * @throws LockedException if estimator is locked.
500      */
501     public void setPointsTriangulated(final boolean triangulatePoints) throws LockedException {
502         if (isLocked()) {
503             throw new LockedException();
504         }
505         this.triangulatePoints = triangulatePoints;
506     }
507 
508     /**
509      * Indicates which triangulated points are marked as valid (lie in front
510      * of both of the estimated cameras) and which ones aren't.
511      *
512      * @return true to mark valid and invalid triangulated points, false
513      * otherwise.
514      */
515     public boolean areValidTriangulatedPointsMarked() {
516         return markValidTriangulatedPoints;
517     }
518 
519     /**
520      * Specifies whether triangulated points are marked as valid (lie in front
521      * of both of the estimated cameras) and which ones aren't.
522      *
523      * @param markValidTriangulatedPoints true to mark valid and invalid
524      *                                    triangulated points, false otherwise.
525      * @throws LockedException if estimator is locked.
526      */
527     public void setValidTriangulatedPointsMarked(final boolean markValidTriangulatedPoints) throws LockedException {
528         if (isLocked()) {
529             throw new LockedException();
530         }
531         this.markValidTriangulatedPoints = markValidTriangulatedPoints;
532     }
533 
534     /**
535      * Gets triangulated points, if available.
536      *
537      * @return triangulated points or null.
538      */
539     public List<Point3D> getTriangulatedPoints() {
540         return triangulatedPoints;
541     }
542 
543     /**
544      * Gets bitset indicating which of the triangulated points are valid and
545      * which ones aren't.
546      *
547      * @return bitset indicating validity of triangulated points or null if not
548      * available.
549      */
550     public BitSet getValidTriangulatedPoints() {
551         return validTriangulatedPoints;
552     }
553 
554     /**
555      * Generates a pair of metric cameras (up to an arbitrary space) by
556      * estimating the intrinsic parameters of the views by solving the Kruppa
557      * equations to obtain the Dual Image of Absolute Conic (DIAC).
558      * The estimated intrinsic parameters can later be used to find the
559      * essential matrix (assuming that both views have the same intrinsic
560      * parameters), and the essential matrix along with provided matched 2D
561      * points can be used to determine the best pair of camera pose and
562      * translation that yields the largest number of triangulated points laying
563      * in front of both of the estimated cameras.
564      * This method uses default corrector type, does not keep triangulated
565      * points or valid triangulated points, and uses default aspect ratio (1.0).
566      *
567      * @param fundamentalMatrix fundamental matrix relating both left and right
568      *                          views.
569      * @param principalPointX   horizontal coordinate of principal point. This
570      *                          value should be the coordinates of the center of an image assuming that
571      *                          the coordinates start on the top-left or bottom-left corner. Using a
572      *                          value close to zero will produce inaccurate results.
573      * @param principalPointY   vertical coordinate of principal point. This
574      *                          value should be the coordinates of the center of an image assuming that
575      *                          the coordinates start on the top-left or bottom-left corner. Using a
576      *                          value close to zero will produce inaccurate results.
577      * @param leftPoints        points on left view matched with points on right view,
578      *                          so they can be triangulated using estimated cameras. Both lists of points
579      *                          must have the same size.
580      * @param rightPoints       points on right view matched with points on left view,
581      *                          so they can be triangulated using estimated cameras. Both lists of points
582      *                          must have the same size.
583      * @param leftCamera        instance where estimated left camera will be stored.
584      * @param rightCamera       instance where estimated right camera will be stored.
585      * @return number of valid triangulated points which lie in front of the two
586      * estimated cameras.
587      * @throws InitialCamerasEstimationFailedException if estimation of cameras
588      *                                                 fails for some reason, typically due to numerical
589      *                                                 instabilities.
590      * @throws IllegalArgumentException                if provided lists of left and right
591      *                                                 points don't have the same size.
592      */
593     public static int generateInitialMetricCamerasUsingDIAC(
594             final FundamentalMatrix fundamentalMatrix, final double principalPointX,
595             final double principalPointY, final List<Point2D> leftPoints,
596             final List<Point2D> rightPoints, final PinholeCamera leftCamera,
597             final PinholeCamera rightCamera) throws InitialCamerasEstimationFailedException {
598 
599         return generateInitialMetricCamerasUsingDIAC(fundamentalMatrix, principalPointX, principalPointY,
600                 leftPoints, rightPoints, Corrector.DEFAULT_TYPE, leftCamera, rightCamera);
601     }
602 
603     /**
604      * Generates a pair of metric cameras (up to an arbitrary space) by
605      * estimating the intrinsic parameters of the views by solving the Kruppa
606      * equations to obtain the Dual Image of Absolute Conic (DIAC).
607      * The estimated intrinsic parameters can later be used to find the
608      * essential matrix (assuming that both views have the same intrinsic
609      * parameters), and the essential matrix along with provided matched 2D
610      * points can be used to determine the best pair of camera pose and
611      * translation that yields the largest number of triangulated points laying
612      * in front of both of the estimated cameras.
613      * This method does not keep triangulated points or valid triangulated
614      * points and uses default aspect ratio (1.0).
615      *
616      * @param fundamentalMatrix fundamental matrix relating both left and right
617      *                          views.
618      * @param principalPointX   horizontal coordinate of principal point. This
619      *                          value should be the coordinates of the center of an image assuming that
620      *                          the coordinates start on the top-left or bottom-left corner. Using a
621      *                          value close to zero will produce inaccurate results.
622      * @param principalPointY   vertical coordinate of principal point. This
623      *                          value should be the coordinates of the center of an image assuming that
624      *                          the coordinates start on the top-left or bottom-left corner. Using a
625      *                          value close to zero will produce inaccurate results.
626      * @param leftPoints        points on left view matched with points on right view,
627      *                          so they can be triangulated using estimated cameras. Both lists of points
628      *                          must have the same size.
629      * @param rightPoints       points on right view matched with points on left view,
630      *                          so they can be triangulated using estimated cameras. Both lists of points
631      *                          must have the same size.
632      * @param correctorType     corrector type to be used to correct 2D points, so
633      *                          they follow the epipolar geometry defined by provided fundamental matrix
634      *                          so that error on triangulated points is reduced. If null, no corrector
635      *                          will be used.
636      * @param leftCamera        instance where estimated left camera will be stored.
637      * @param rightCamera       instance where estimated right camera will be stored.
638      * @return number of valid triangulated points which lie in front of the two
639      * estimated cameras.
640      * @throws InitialCamerasEstimationFailedException if estimation of
641      *                                                 cameras fails for some reason, typically due to
642      *                                                 numerical instabilities.
643      * @throws IllegalArgumentException                if provided lists of left and right
644      *                                                 points don't have the same size.
645      */
646     public static int generateInitialMetricCamerasUsingDIAC(
647             final FundamentalMatrix fundamentalMatrix, final double principalPointX,
648             final double principalPointY, final List<Point2D> leftPoints,
649             final List<Point2D> rightPoints, final CorrectorType correctorType,
650             final PinholeCamera leftCamera, final PinholeCamera rightCamera)
651             throws InitialCamerasEstimationFailedException {
652 
653         return generateInitialMetricCamerasUsingDIAC(fundamentalMatrix, principalPointX, principalPointY,
654                 leftPoints, rightPoints, correctorType, leftCamera, rightCamera, null,
655                 null);
656     }
657 
658     /**
659      * Generates a pair of metric cameras (up to an arbitrary space) by
660      * estimating the intrinsic parameters of the views by solving the Kruppa
661      * equations to obtain the Dual Image of Absolute Conic (DIAC).
662      * The estimated intrinsic parameters can later be used to find the
663      * essential matrix (assuming that both views have the same intrinsic
664      * parameters), and the essential matrix along with provided matched 2D
665      * points can be used to determine the best pair of camera pose and
666      * translation that yields the largest number of triangulated points laying
667      * in front of both of the estimated cameras.
668      * This method uses default corrector type and default aspect ratio (1.0).
669      *
670      * @param fundamentalMatrix       fundamental matrix relating both left and right
671      *                                views.
672      * @param principalPointX         horizontal coordinate of principal point. This
673      *                                value should be the coordinates of the center of an image assuming
674      *                                that the coordinates start on the top-left or bottom-left corner.
675      *                                Using a value close to zero will produce inaccurate results.
676      * @param principalPointY         vertical coordinate of principal point. This
677      *                                value should be the coordinates of the center of an image assuming
678      *                                that the coordinates start on the top-left or bottom-left corner.
679      *                                Using a value close to zero will produce inaccurate results.
680      * @param leftPoints              points on left view matched with points on right view,
681      *                                so they can be triangulated using estimated cameras. Both lists of
682      *                                points must have the same size.
683      * @param rightPoints             points on right view matched with points on left view,
684      *                                so they can be triangulated using estimated cameras. Both lists of
685      *                                points must have the same size.
686      * @param leftCamera              instance where estimated left camera will be stored.
687      * @param rightCamera             instance where estimated right camera will be stored.
688      * @param triangulatedPoints      instance where triangulated 3D points will be
689      *                                stored or null if triangulated points don't need to be kept.
690      * @param validTriangulatedPoints instance which indicates which
691      *                                triangulated 3D points are considered valid because they lie in
692      *                                front of both cameras or null if such data doesn't need to be kept.
693      * @return number of valid triangulated points which lie in front of the two
694      * estimated cameras.
695      * @throws InitialCamerasEstimationFailedException if estimation of cameras
696      *                                                 fails for some reason, typically due to numerical
697      *                                                 instabilities.
698      * @throws IllegalArgumentException                if provided lists of left and right
699      *                                                 points don't have the same size.
700      */
701     public static int generateInitialMetricCamerasUsingDIAC(
702             final FundamentalMatrix fundamentalMatrix, final double principalPointX,
703             final double principalPointY, final List<Point2D> leftPoints,
704             final List<Point2D> rightPoints, final PinholeCamera leftCamera,
705             final PinholeCamera rightCamera, final List<Point3D> triangulatedPoints,
706             final BitSet validTriangulatedPoints)
707             throws InitialCamerasEstimationFailedException {
708 
709         return generateInitialMetricCamerasUsingDIAC(fundamentalMatrix, principalPointX, principalPointY,
710                 leftPoints, rightPoints, Corrector.DEFAULT_TYPE, leftCamera, rightCamera, triangulatedPoints,
711                 validTriangulatedPoints);
712     }
713 
714     /**
715      * Generates a pair of metric cameras (up to an arbitrary space) by
716      * estimating the intrinsic parameters of the views by solving the Kruppa
717      * equations to obtain the Dual Image of Absolute Conic (DIAC).
718      * The estimated intrinsic parameters can later be used to find the
719      * essential matrix (assuming that both views have the same intrinsic
720      * parameters), and the essential matrix along with provided matched 2D
721      * points can be used to determine the best pair of camera pose and
722      * translation that yields the largest number of triangulated points laying
723      * in front of both of the estimated cameras.
724      * This method uses default aspect ratio (1.0).
725      *
726      * @param fundamentalMatrix       fundamental matrix relating both left and right
727      *                                views.
728      * @param principalPointX         horizontal coordinate of principal point. This
729      *                                value should be the coordinates of the center of an image assuming
730      *                                that the coordinates start on the top-left or bottom-left corner.
731      *                                Using a value close to zero will produce inaccurate results.
732      * @param principalPointY         vertical coordinate of principal point. This
733      *                                value should be the coordinates of the center of an image assuming
734      *                                that the coordinates start on the top-left or bottom-left corner.
735      *                                Using a value close to zero will produce inaccurate results.
736      * @param leftPoints              points on left view matched with points on right view,
737      *                                so they can be triangulated using estimated cameras. Both lists of
738      *                                points must have the same size.
739      * @param rightPoints             points on right view matched with points on left view,
740      *                                so they can be triangulated using estimated cameras. Both lists of
741      *                                points must have the same size.
742      * @param correctorType           corrector type to be used to correct 2D points, so
743      *                                they follow the epipolar geometry defined by provided fundamental
744      *                                matrix so that error on triangulated points is reduced. If null, no
745      *                                corrector will be used.
746      * @param leftCamera              instance where estimated left camera will be stored.
747      * @param rightCamera             instance where estimated right camera will be stored.
748      * @param triangulatedPoints      instance where triangulated 3D points will be
749      *                                stored or null if triangulated points don't need to be kept.
750      * @param validTriangulatedPoints instance which indicates which
751      *                                triangulated 3D points are considered valid because they lie in
752      *                                front of both cameras or null if such data doesn't need to be kept.
753      * @return number of valid triangulated points which lie in front of the two
754      * estimated cameras.
755      * @throws InitialCamerasEstimationFailedException if estimation of cameras
756      *                                                 fails for some reason, typically due to numerical
757      *                                                 instabilities.
758      * @throws IllegalArgumentException                if provided lists of left and right
759      *                                                 points don't have the same size.
760      */
761     public static int generateInitialMetricCamerasUsingDIAC(
762             final FundamentalMatrix fundamentalMatrix, final double principalPointX,
763             final double principalPointY, final List<Point2D> leftPoints,
764             final List<Point2D> rightPoints, final CorrectorType correctorType,
765             final PinholeCamera leftCamera, final PinholeCamera rightCamera,
766             final List<Point3D> triangulatedPoints, final BitSet validTriangulatedPoints)
767             throws InitialCamerasEstimationFailedException {
768 
769         return generateInitialMetricCamerasUsingDIAC(fundamentalMatrix,
770                 principalPointX, principalPointY,
771                 KruppaDualImageOfAbsoluteConicEstimator.DEFAULT_FOCAL_DISTANCE_ASPECT_RATIO, leftPoints, rightPoints,
772                 correctorType, leftCamera, rightCamera, triangulatedPoints, validTriangulatedPoints);
773     }
774 
775     /**
776      * Generates a pair of metric cameras (up to an arbitrary space) by
777      * estimating the intrinsic parameters of the views by solving the Kruppa
778      * equations to obtain the Dual Image of Absolute Conic (DIAC).
779      * The estimated intrinsic parameters can later be used to find the
780      * essential matrix (assuming that both views have the same intrinsic
781      * parameters), and the essential matrix along with provided matched 2D
782      * points can be used to determine the best pair of camera pose and
783      * translation that yields the largest number of triangulated points laying
784      * in front of both of the estimated cameras.
785      * This method uses default corrector type and does not keep triangulated
786      * points or valid triangulated points.
787      *
788      * @param fundamentalMatrix fundamental matrix relating both left and right
789      *                          views.
790      * @param principalPointX   horizontal coordinate of principal point. This
791      *                          value should be the coordinates of the center of an image assuming that
792      *                          the coordinates start on the top-left or bottom-left corner. Using a
793      *                          value close to zero will produce inaccurate results.
794      * @param principalPointY   vertical coordinate of principal point. This
795      *                          value should be the coordinates of the center of an image assuming that
796      *                          the coordinates start on the top-left or bottom-left corner. Using a
797      *                          value close to zero will produce inaccurate results.
798      * @param aspectRatio       aspect ratio for estimated intrinsic parameters. This
799      *                          is typically 1.0 if vertical coordinates increase upwards or -1.0 if it
800      *                          is the opposite.
801      * @param leftPoints        points on left view matched with points on right view,
802      *                          so they can be triangulated using estimated cameras. Both lists of points
803      *                          must have the same size.
804      * @param rightPoints       points on right view matched with points on left view,
805      *                          so they can be triangulated using estimated cameras. Both lists of points
806      *                          must have the same size.
807      * @param leftCamera        instance where estimated left camera will be stored.
808      * @param rightCamera       instance where estimated right camera will be stored.
809      * @return number of valid triangulated points which lie in front of the two
810      * estimated cameras.
811      * @throws InitialCamerasEstimationFailedException if estimation of cameras
812      *                                                 fails for some reason, typically due to numerical
813      *                                                 instabilities.
814      * @throws IllegalArgumentException                if provided lists of left and right
815      *                                                 points don't have the same size.
816      */
817     public static int generateInitialMetricCamerasUsingDIAC(
818             final FundamentalMatrix fundamentalMatrix, final double principalPointX,
819             final double principalPointY, final double aspectRatio,
820             final List<Point2D> leftPoints, final List<Point2D> rightPoints,
821             final PinholeCamera leftCamera, final PinholeCamera rightCamera)
822             throws InitialCamerasEstimationFailedException {
823 
824         return generateInitialMetricCamerasUsingDIAC(fundamentalMatrix, principalPointX, principalPointY, aspectRatio,
825                 leftPoints, rightPoints, Corrector.DEFAULT_TYPE, leftCamera, rightCamera);
826     }
827 
828     /**
829      * Generates a pair of metric cameras (up to an arbitrary space) by
830      * estimating the intrinsic parameters of the views by solving the Kruppa
831      * equations to obtain the Dual Image of Absolute Conic (DIAC).
832      * The estimated intrinsic parameters can later be used to find the
833      * essential matrix (assuming that both views have the same intrinsic
834      * parameters), and the essential matrix along with provided matched 2D
835      * points can be used to determine the best pair of camera pose and
836      * translation that yields the largest number of triangulated points laying
837      * in front of both of the estimated cameras.
838      * This method does not keep triangulated points or valid triangulated
839      * points.
840      *
841      * @param fundamentalMatrix fundamental matrix relating both left and right
842      *                          views.
843      * @param principalPointX   horizontal coordinate of principal point. This
844      *                          value should be the coordinates of the center of an image assuming that
845      *                          the coordinates start on the top-left or bottom-left corner. Using a
846      *                          value close to zero will produce inaccurate results.
847      * @param principalPointY   vertical coordinate of principal point. This
848      *                          value should be the coordinates of the center of an image assuming that
849      *                          the coordinates start on the top-left or bottom-left corner. Using a
850      *                          value close to zero will produce inaccurate results.
851      * @param aspectRatio       aspect ratio for estimated intrinsic parameters. This
852      *                          is typically 1.0 if vertical coordinates increase upwards or -1.0 if it
853      *                          is the opposite.
854      * @param leftPoints        points on left view matched with points on right view,
855      *                          so they can be triangulated using estimated cameras. Both lists of points
856      *                          must have the same size.
857      * @param rightPoints       points on right view matched with points on left view,
858      *                          so they can be triangulated using estimated cameras. Both lists of points
859      *                          must have the same size.
860      * @param correctorType     corrector type to be used to correct 2D points, so
861      *                          they follow the epipolar geometry defined by provided fundamental matrix
862      *                          so that error on triangulated points is reduced. If null, no corrector
863      *                          will be used.
864      * @param leftCamera        instance where estimated left camera will be stored.
865      * @param rightCamera       instance where estimated right camera will be stored.
866      * @return number of valid triangulated points which lie in front of the two
867      * estimated cameras.
868      * @throws InitialCamerasEstimationFailedException if estimation of
869      *                                                 cameras fails for some reason, typically due to
870      *                                                 numerical instabilities.
871      * @throws IllegalArgumentException                if provided lists of left and right
872      *                                                 points don't have the same size.
873      */
874     public static int generateInitialMetricCamerasUsingDIAC(
875             final FundamentalMatrix fundamentalMatrix, final double principalPointX,
876             final double principalPointY, final double aspectRatio,
877             final List<Point2D> leftPoints, final List<Point2D> rightPoints,
878             final CorrectorType correctorType, final PinholeCamera leftCamera,
879             final PinholeCamera rightCamera) throws InitialCamerasEstimationFailedException {
880 
881         return generateInitialMetricCamerasUsingDIAC(fundamentalMatrix, principalPointX, principalPointY, aspectRatio,
882                 leftPoints, rightPoints, correctorType, leftCamera, rightCamera, null,
883                 null);
884     }
885 
886     /**
887      * Generates a pair of metric cameras (up to an arbitrary space) by
888      * estimating the intrinsic parameters of the views by solving the Kruppa
889      * equations to obtain the Dual Image of Absolute Conic (DIAC).
890      * The estimated intrinsic parameters can later be used to find the
891      * essential matrix (assuming that both views have the same intrinsic
892      * parameters), and the essential matrix along with provided matched 2D
893      * points can be used to determine the best pair of camera pose and
894      * translation that yields the largest number of triangulated points laying
895      * in front of both of the estimated cameras.
896      * This method uses default corrector type.
897      *
898      * @param fundamentalMatrix       fundamental matrix relating both left and right
899      *                                views.
900      * @param principalPointX         horizontal coordinate of principal point. This
901      *                                value should be the coordinates of the center of an image assuming
902      *                                that the coordinates start on the top-left or bottom-left corner.
903      *                                Using a value close to zero will produce inaccurate results.
904      * @param principalPointY         vertical coordinate of principal point. This
905      *                                value should be the coordinates of the center of an image assuming
906      *                                that the coordinates start on the top-left or bottom-left corner.
907      *                                Using a value close to zero will produce inaccurate results.
908      * @param aspectRatio             aspect ratio for estimated intrinsic parameters. This
909      *                                is typically 1.0 if vertical coordinates increase upwards or -1.0 if
910      *                                it is the opposite.
911      * @param leftPoints              points on left view matched with points on right view,
912      *                                so they can be triangulated using estimated cameras. Both lists of
913      *                                points must have the same size.
914      * @param rightPoints             points on right view matched with points on left view,
915      *                                so they can be triangulated using estimated cameras. Both lists of
916      *                                points must have the same size.
917      * @param leftCamera              instance where estimated left camera will be stored.
918      * @param rightCamera             instance where estimated right camera will be stored.
919      * @param triangulatedPoints      instance where triangulated 3D points will be
920      *                                stored or null if triangulated points don't need to be kept.
921      * @param validTriangulatedPoints instance which indicates which
922      *                                triangulated 3D points are considered valid because they lie in
923      *                                front of both cameras or null if such data doesn't need to be kept.
924      * @return number of valid triangulated points which lie in front of the two
925      * estimated cameras.
926      * @throws InitialCamerasEstimationFailedException if estimation of cameras
927      *                                                 fails for some reason, typically due to numerical
928      *                                                 instabilities.
929      * @throws IllegalArgumentException                if provided lists of left and right
930      *                                                 points don't have the same size.
931      */
932     public static int generateInitialMetricCamerasUsingDIAC(
933             final FundamentalMatrix fundamentalMatrix, final double principalPointX,
934             final double principalPointY, final double aspectRatio,
935             final List<Point2D> leftPoints, final List<Point2D> rightPoints,
936             final PinholeCamera leftCamera, final PinholeCamera rightCamera,
937             final List<Point3D> triangulatedPoints, final BitSet validTriangulatedPoints)
938             throws InitialCamerasEstimationFailedException {
939 
940         return generateInitialMetricCamerasUsingDIAC(fundamentalMatrix, principalPointX, principalPointY, aspectRatio,
941                 leftPoints, rightPoints, Corrector.DEFAULT_TYPE, leftCamera, rightCamera, triangulatedPoints,
942                 validTriangulatedPoints);
943     }
944 
945     /**
946      * Generates a pair of metric cameras (up to an arbitrary space) by
947      * estimating the intrinsic parameters of the views by solving the Kruppa
948      * equations to obtain the Dual Image of Absolute Conic (DIAC).
949      * The estimated intrinsic parameters can later be used to find the
950      * essential matrix (assuming that both views have the same intrinsic
951      * parameters), and the essential matrix along with provided matched 2D
952      * points can be used to determine the best pair of camera pose and
953      * translation that yields the largest number of triangulated points laying
954      * in front of both of the estimated cameras.
955      *
956      * @param fundamentalMatrix       fundamental matrix relating both left and right
957      *                                views.
958      * @param principalPointX         horizontal coordinate of principal point. This
959      *                                value should be the coordinates of the center of an image assuming
960      *                                that the coordinates start on the top-left or bottom-left corner.
961      *                                Using a value close to zero will produce inaccurate results.
962      * @param principalPointY         vertical coordinate of principal point. This
963      *                                value should be the coordinates of the center of an image assuming
964      *                                that the coordinates start on the top-left or bottom-left corner.
965      *                                Using a value close to zero will produce inaccurate results.
966      * @param aspectRatio             aspect ratio for estimated intrinsic parameters. This
967      *                                is typically 1.0 if vertical coordinates increase upwards or -1.0 if
968      *                                it is the opposite.
969      * @param leftPoints              points on left view matched with points on right view,
970      *                                so they can be triangulated using estimated cameras. Both lists of
971      *                                points must have the same size.
972      * @param rightPoints             points on right view matched with points on left view,
973      *                                so they can be triangulated using estimated cameras. Both lists of
974      *                                points must have the same size.
975      * @param correctorType           corrector type to be used to correct 2D points, so
976      *                                they follow the epipolar geometry defined by provided fundamental
977      *                                matrix so that error on triangulated points is reduced. If null, no
978      *                                corrector will be used.
979      * @param leftCamera              instance where estimated left camera will be stored.
980      * @param rightCamera             instance where estimated right camera will be stored.
981      * @param triangulatedPoints      instance where triangulated 3D points will be
982      *                                stored or null if triangulated points don't need to be kept.
983      * @param validTriangulatedPoints instance which indicates which
984      *                                triangulated 3D points are considered valid because they lie in
985      *                                front of both cameras or null if such data doesn't need to be kept.
986      * @return number of valid triangulated points which lie in front of the two
987      * estimated cameras.
988      * @throws InitialCamerasEstimationFailedException if estimation of cameras
989      *                                                 fails for some reason, typically due to numerical
990      *                                                 instabilities.
991      * @throws IllegalArgumentException                if provided lists of left and right
992      *                                                 points don't have the same size.
993      */
994     public static int generateInitialMetricCamerasUsingDIAC(
995             final FundamentalMatrix fundamentalMatrix, final double principalPointX,
996             final double principalPointY, final double aspectRatio,
997             final List<Point2D> leftPoints, final List<Point2D> rightPoints,
998             final CorrectorType correctorType, final PinholeCamera leftCamera,
999             final PinholeCamera rightCamera, final List<Point3D> triangulatedPoints,
1000             final BitSet validTriangulatedPoints) throws InitialCamerasEstimationFailedException {
1001 
1002         try {
1003             final KruppaDualImageOfAbsoluteConicEstimator diacEstimator = new KruppaDualImageOfAbsoluteConicEstimator(
1004                     fundamentalMatrix);
1005             diacEstimator.setPrincipalPointX(principalPointX);
1006             diacEstimator.setPrincipalPointY(principalPointY);
1007             diacEstimator.setFocalDistanceAspectRatioKnown(true);
1008             diacEstimator.setFocalDistanceAspectRatio(aspectRatio);
1009 
1010             final var diac = diacEstimator.estimate();
1011 
1012             final var intrinsic = diac.getIntrinsicParameters();
1013 
1014             return EssentialMatrixInitialCamerasEstimator.generateInitialMetricCamerasFromEssentialMatrix(
1015                     fundamentalMatrix, intrinsic, intrinsic, leftPoints, rightPoints, correctorType, leftCamera,
1016                     rightCamera, triangulatedPoints, validTriangulatedPoints);
1017 
1018         } catch (final InitialCamerasEstimationFailedException e) {
1019             throw e;
1020         } catch (final Exception e) {
1021             throw new InitialCamerasEstimationFailedException(e);
1022         }
1023     }
1024 
1025     /**
1026      * Internal method to set matched 2D points on left and right views.
1027      * This method does not check whether the estimator is locked or not, only
1028      * ensures that provided lists have the same size.
1029      *
1030      * @param leftPoints  matched 2D points on left view.
1031      * @param rightPoints matched 2D points on right view.
1032      * @throws IllegalArgumentException if provided lists don't have the same
1033      *                                  size.
1034      */
1035     private void internalSetLeftAndRightPoints(final List<Point2D> leftPoints, final List<Point2D> rightPoints) {
1036         if (leftPoints == null || rightPoints == null || leftPoints.size() != rightPoints.size()) {
1037             throw new IllegalArgumentException();
1038         }
1039         this.leftPoints = leftPoints;
1040         this.rightPoints = rightPoints;
1041     }
1042 }