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 }