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.epipolar.FundamentalMatrix;
19  import com.irurueta.geometry.PinholeCamera;
20  import com.irurueta.geometry.estimators.LockedException;
21  import com.irurueta.geometry.estimators.NotReadyException;
22  
23  /**
24   * Estimates initial cameras to initialize geometry in a metric stratum.
25   * This class uses provided fundamental matrix in order to obtain a pair of
26   * cameras and upgrade such cameras into a metric stratum.
27   * This class assumes that principal point of intrinsic camera parameters are
28   * located at the origin of coordinates, and also that skewness of such
29   * intrinsic parameters is zero.
30   * This class can upgrade cameras to a metric stratum by either estimating the
31   * Dual Absolute Quadric and its corresponding projective to metric
32   * transformation, or by solving the Kruppa equations to estimate the Dual
33   * Image of Absolute Conic to determine intrinsic parameters and then compute
34   * the essential matrix and use 2D point matches to triangulate them and find
35   * the initial cameras.
36   */
37  @SuppressWarnings("DuplicatedCode")
38  public abstract class InitialCamerasEstimator {
39  
40      /**
41       * Default method.
42       */
43      public static final InitialCamerasEstimatorMethod DEFAULT_METHOD =
44              InitialCamerasEstimatorMethod.DUAL_ABSOLUTE_QUADRIC;
45  
46      /**
47       * Fundamental matrix relating two views whose cameras need to be estimated.
48       */
49      protected FundamentalMatrix fundamentalMatrix;
50  
51      /**
52       * Indicates if this estimator is locked or not.
53       */
54      protected boolean locked;
55  
56      /**
57       * Estimated camera for left view.
58       */
59      protected PinholeCamera estimatedLeftCamera;
60  
61      /**
62       * Estimated camera for right view.
63       */
64      protected PinholeCamera estimatedRightCamera;
65  
66      /**
67       * Listener to handle events raised by this instance.
68       */
69      protected InitialCamerasEstimatorListener listener;
70  
71      /**
72       * Constructor.
73       */
74      protected InitialCamerasEstimator() {
75      }
76  
77      /**
78       * Constructor.
79       *
80       * @param fundamentalMatrix fundamental matrix relating two views.
81       */
82      protected InitialCamerasEstimator(final FundamentalMatrix fundamentalMatrix) {
83          this.fundamentalMatrix = fundamentalMatrix;
84      }
85  
86      /**
87       * Constructor.
88       *
89       * @param listener listener to handle events raised by this instance.
90       */
91      protected InitialCamerasEstimator(final InitialCamerasEstimatorListener listener) {
92          this.listener = listener;
93      }
94  
95      /**
96       * Constructor.
97       *
98       * @param fundamentalMatrix fundamental matrix relating two views.
99       * @param listener          listener to handle events raised by this instance.
100      */
101     protected InitialCamerasEstimator(final FundamentalMatrix fundamentalMatrix,
102                                       final InitialCamerasEstimatorListener listener) {
103         this.fundamentalMatrix = fundamentalMatrix;
104         this.listener = listener;
105     }
106 
107     /**
108      * Gets fundamental matrix relating two views whose cameras need to be
109      * estimated.
110      *
111      * @return fundamental matrix relating two views.
112      */
113     public FundamentalMatrix getFundamentalMatrix() {
114         return fundamentalMatrix;
115     }
116 
117     /**
118      * Sets fundamental matrix relating two views whose cameras need to be
119      * estimated.
120      *
121      * @param fundamentalMatrix fundamental matrix relating two views.
122      * @throws LockedException if estimator is locked.
123      */
124     public void setFundamentalMatrix(final FundamentalMatrix fundamentalMatrix) throws LockedException {
125         if (isLocked()) {
126             throw new LockedException();
127         }
128         this.fundamentalMatrix = fundamentalMatrix;
129     }
130 
131     /**
132      * Gets listener to handle events raised by this instance.
133      *
134      * @return listener to handle events raised by this instance.
135      */
136     public InitialCamerasEstimatorListener getListener() {
137         return listener;
138     }
139 
140     /**
141      * Sets listener to handle events raised by this instance.
142      *
143      * @param listener listener to handle events raised by this instance.
144      */
145     public void setListener(final InitialCamerasEstimatorListener listener) {
146         this.listener = listener;
147     }
148 
149     /**
150      * Indicates if this estimator is locked or not.
151      *
152      * @return true if this estimator is locked, false otherwise.
153      */
154     public boolean isLocked() {
155         return locked;
156     }
157 
158     /**
159      * Gets estimated camera for left view.
160      *
161      * @return estimated camera for left view.
162      */
163     public PinholeCamera getEstimatedLeftCamera() {
164         return estimatedLeftCamera;
165     }
166 
167     /**
168      * Gets estimated camera for right view.
169      *
170      * @return estimated camera for right view.
171      */
172     public PinholeCamera getEstimatedRightCamera() {
173         return estimatedRightCamera;
174     }
175 
176     /**
177      * Returns method used by this estimator.
178      *
179      * @return method used by this estimator.
180      */
181     public abstract InitialCamerasEstimatorMethod getMethod();
182 
183     /**
184      * Indicates if estimator is ready.
185      *
186      * @return true if estimator is ready, false otherwise.
187      */
188     public abstract boolean isReady();
189 
190     /**
191      * Estimates cameras.
192      *
193      * @throws LockedException                         if estimator is locked.
194      * @throws NotReadyException                       if estimator is not ready.
195      * @throws InitialCamerasEstimationFailedException if estimation of cameras
196      *                                                 fails for some reason, typically due to numerical
197      *                                                 instabilities.
198      */
199     public abstract void estimate() throws LockedException, NotReadyException, InitialCamerasEstimationFailedException;
200 
201     /**
202      * Creates an instance of an initial cameras estimator using provided
203      * method.
204      *
205      * @param method method to estimate initial cameras.
206      * @return an estimator.
207      */
208     public static InitialCamerasEstimator create(final InitialCamerasEstimatorMethod method) {
209         return switch (method) {
210             case ESSENTIAL_MATRIX -> new EssentialMatrixInitialCamerasEstimator();
211             case DUAL_IMAGE_OF_ABSOLUTE_CONIC -> new DualImageOfAbsoluteConicInitialCamerasEstimator();
212             default -> new DualAbsoluteQuadricInitialCamerasEstimator();
213         };
214     }
215 
216     /**
217      * Creates an instance of an initial cameras estimator using provided
218      * fundamental matrix and provided method.
219      *
220      * @param fundamentalMatrix fundamental matrix relating two views.
221      * @param method            method to estimate initial cameras.
222      * @return an estimator.
223      */
224     public static InitialCamerasEstimator create(
225             final FundamentalMatrix fundamentalMatrix, final InitialCamerasEstimatorMethod method) {
226         return switch (method) {
227             case ESSENTIAL_MATRIX -> new EssentialMatrixInitialCamerasEstimator(fundamentalMatrix);
228             case DUAL_IMAGE_OF_ABSOLUTE_CONIC -> new DualImageOfAbsoluteConicInitialCamerasEstimator(fundamentalMatrix);
229             default -> new DualAbsoluteQuadricInitialCamerasEstimator(fundamentalMatrix);
230         };
231     }
232 
233     /**
234      * Creates an instance of an initial cameras estimator using provided
235      * listener and method.
236      *
237      * @param listener listener to handle events.
238      * @param method   method to estimate initial cameras.
239      * @return an estimator.
240      */
241     public static InitialCamerasEstimator create(
242             final InitialCamerasEstimatorListener listener, final InitialCamerasEstimatorMethod method) {
243         return switch (method) {
244             case ESSENTIAL_MATRIX -> new EssentialMatrixInitialCamerasEstimator(listener);
245             case DUAL_IMAGE_OF_ABSOLUTE_CONIC -> new DualImageOfAbsoluteConicInitialCamerasEstimator(listener);
246             default -> new DualAbsoluteQuadricInitialCamerasEstimator(listener);
247         };
248     }
249 
250     /**
251      * Creates an instance of an initial cameras estimator using provided
252      * fundamental matrix, listener and method.
253      *
254      * @param fundamentalMatrix fundamental matrix relating two views.
255      * @param listener          listener to handle events.
256      * @param method            method to estimate initial cameras.
257      * @return an estimator.
258      */
259     public static InitialCamerasEstimator create(
260             final FundamentalMatrix fundamentalMatrix,
261             final InitialCamerasEstimatorListener listener,
262             final InitialCamerasEstimatorMethod method) {
263         return switch (method) {
264             case ESSENTIAL_MATRIX -> new EssentialMatrixInitialCamerasEstimator(fundamentalMatrix, listener);
265             case DUAL_IMAGE_OF_ABSOLUTE_CONIC -> new DualImageOfAbsoluteConicInitialCamerasEstimator(
266                     fundamentalMatrix, listener);
267             default -> new DualAbsoluteQuadricInitialCamerasEstimator(fundamentalMatrix, listener);
268         };
269     }
270 
271     /**
272      * Creates an instance of an initial cameras estimator using provided
273      * method.
274      *
275      * @return an estimator.
276      */
277     public static InitialCamerasEstimator create() {
278         return create(DEFAULT_METHOD);
279     }
280 
281     /**
282      * Creates an instance of an initial cameras estimator using provided
283      * fundamental matrix and provided method.
284      *
285      * @param fundamentalMatrix fundamental matrix relating two views.
286      * @return an estimator.
287      */
288     public static InitialCamerasEstimator create(final FundamentalMatrix fundamentalMatrix) {
289         return create(fundamentalMatrix, DEFAULT_METHOD);
290     }
291 
292     /**
293      * Creates an instance of an initial cameras estimator using provided
294      * listener and method.
295      *
296      * @param listener listener to handle events.
297      * @return an estimator.
298      */
299     public static InitialCamerasEstimator create(final InitialCamerasEstimatorListener listener) {
300         return create(listener, DEFAULT_METHOD);
301     }
302 
303     /**
304      * Creates an instance of an initial cameras estimator using provided
305      * fundamental matrix, listener and method.
306      *
307      * @param fundamentalMatrix fundamental matrix relating two views.
308      * @param listener          listener to handle events.
309      * @return an estimator.
310      */
311     public static InitialCamerasEstimator create(
312             final FundamentalMatrix fundamentalMatrix, final InitialCamerasEstimatorListener listener) {
313         return create(fundamentalMatrix, listener, DEFAULT_METHOD);
314     }
315 }