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.DualAbsoluteQuadricEstimator;
19  import com.irurueta.ar.calibration.estimators.LMSEDualAbsoluteQuadricEstimator;
20  import com.irurueta.ar.epipolar.FundamentalMatrix;
21  import com.irurueta.geometry.PinholeCamera;
22  import com.irurueta.geometry.estimators.LockedException;
23  import com.irurueta.geometry.estimators.NotReadyException;
24  
25  import java.util.ArrayList;
26  
27  /**
28   * Estimates an initial pair of cameras in the metric stratum (up to an
29   * arbitrary scale) using a given fundamental matrix and assuming zero skewness
30   * and principal point at the origin for the intrinsic parameters of estimated
31   * cameras.
32   * Aspect ratio can be configured but by default it is assumed to be 1.0.
33   */
34  public class DualAbsoluteQuadricInitialCamerasEstimator extends InitialCamerasEstimator {
35  
36      /**
37       * Aspect ratio of intrinsic parameters of cameras.
38       * Typically, this value is 1.0 if vertical coordinates increase upwards,
39       * or -1.0 if it is the opposite.
40       */
41      private double aspectRatio = DualAbsoluteQuadricEstimator.DEFAULT_FOCAL_DISTANCE_ASPECT_RATIO;
42  
43      /**
44       * Constructor.
45       */
46      public DualAbsoluteQuadricInitialCamerasEstimator() {
47          super();
48      }
49  
50      /**
51       * Constructor.
52       *
53       * @param fundamentalMatrix fundamental matrix relating two views.
54       */
55      public DualAbsoluteQuadricInitialCamerasEstimator(final FundamentalMatrix fundamentalMatrix) {
56          super(fundamentalMatrix);
57      }
58  
59      /**
60       * Constructor.
61       *
62       * @param listener listener to handle events raised by this instance.
63       */
64      public DualAbsoluteQuadricInitialCamerasEstimator(final InitialCamerasEstimatorListener listener) {
65          super(listener);
66      }
67  
68      /**
69       * Constructor.
70       *
71       * @param fundamentalMatrix fundamental matrix relating two views.
72       * @param listener          listener to handle events raised by this instance.
73       */
74      public DualAbsoluteQuadricInitialCamerasEstimator(
75              final FundamentalMatrix fundamentalMatrix, final InitialCamerasEstimatorListener listener) {
76          super(fundamentalMatrix, listener);
77      }
78  
79      /**
80       * Returns method used by this estimator.
81       *
82       * @return method used by this estimator.
83       */
84      @Override
85      public InitialCamerasEstimatorMethod getMethod() {
86          return InitialCamerasEstimatorMethod.DUAL_ABSOLUTE_QUADRIC;
87      }
88  
89      /**
90       * Indicates if estimator is ready.
91       *
92       * @return true if estimator is ready, false otherwise.
93       */
94      @Override
95      public boolean isReady() {
96          return fundamentalMatrix != null;
97      }
98  
99      /**
100      * Estimates cameras.
101      *
102      * @throws LockedException                         if estimator is locked.
103      * @throws NotReadyException                       if estimator is not ready.
104      * @throws InitialCamerasEstimationFailedException if estimation of cameras
105      *                                                 fails for some reason, typically due to numerical
106      *                                                 instabilities.
107      */
108     @Override
109     public void estimate() throws LockedException, NotReadyException, InitialCamerasEstimationFailedException {
110         if (isLocked()) {
111             throw new LockedException();
112         }
113 
114         if (!isReady()) {
115             throw new NotReadyException();
116         }
117 
118         try {
119             locked = true;
120 
121             if (listener != null) {
122                 listener.onStart(this);
123             }
124 
125             if (estimatedLeftCamera == null) {
126                 estimatedLeftCamera = new PinholeCamera();
127             }
128             if (estimatedRightCamera == null) {
129                 estimatedRightCamera = new PinholeCamera();
130             }
131 
132             generateInitialMetricCamerasUsingDAQ(fundamentalMatrix, aspectRatio, estimatedLeftCamera,
133                     estimatedRightCamera);
134 
135             if (listener != null) {
136                 listener.onFinish(this, estimatedLeftCamera, estimatedRightCamera);
137             }
138         } catch (final InitialCamerasEstimationFailedException e) {
139             if (listener != null) {
140                 listener.onFail(this, e);
141             }
142             throw e;
143         } finally {
144             locked = false;
145         }
146     }
147 
148     /**
149      * Gets aspect ratio of intrinsic parameters of cameras.
150      * Typically, this value is 1.0 if vertical coordinates increase upwards,
151      * or -1.0 if it is the opposite.
152      *
153      * @return aspect ratio of intrinsic parameters of cameras.
154      */
155     public double getAspectRatio() {
156         return aspectRatio;
157     }
158 
159     /**
160      * Sets aspect ratio of intrinsic parameters of cameras.
161      * Typically, this value is 1.0 if vertical coordinates increase upwards,
162      * or -1.0 if it is the opposite.
163      *
164      * @param aspectRatio aspect ratio of intrinsic parameters of cameras.
165      * @throws LockedException if estimator is locked.
166      */
167     public void setAspectRatio(final double aspectRatio) throws LockedException {
168         if (isLocked()) {
169             throw new LockedException();
170         }
171         this.aspectRatio = aspectRatio;
172     }
173 
174     /**
175      * Generates initial cameras in metric stratum (with arbitrary scale) using
176      * provided fundamental matrix by means of estimation of the Dual Absolute
177      * Quadric and the required projective to metric transformation.
178      *
179      * @param fundamentalMatrix input fundamental matrix to estimate cameras.
180      * @param leftCamera        instance where left camera will be stored.
181      * @param rightCamera       instance where right camera will be stored.
182      * @throws InitialCamerasEstimationFailedException if estimation fails.
183      */
184     public static void generateInitialMetricCamerasUsingDAQ(
185             final FundamentalMatrix fundamentalMatrix,
186             final PinholeCamera leftCamera,
187             final PinholeCamera rightCamera)
188             throws InitialCamerasEstimationFailedException {
189         generateInitialMetricCamerasUsingDAQ(fundamentalMatrix,
190                 DualAbsoluteQuadricEstimator.DEFAULT_FOCAL_DISTANCE_ASPECT_RATIO, leftCamera, rightCamera);
191     }
192 
193     /**
194      * Generates initial cameras in metric stratum (with arbitrary scale) using
195      * provided fundamental matrix by means of estimation of the Dual Absolute
196      * Quadric and the required projective to metric transformation.
197      *
198      * @param fundamentalMatrix input fundamental matrix to estimate cameras.
199      * @param aspectRatio       aspect ratio of intrinsic parameters of cameras.
200      *                          Typically, this value is 1.0 if vertical coordinates increase upwards or
201      *                          -1.0 if it is the opposite.
202      * @param leftCamera        instance where left camera will be stored.
203      * @param rightCamera       instance where right camera will be stored.
204      * @throws InitialCamerasEstimationFailedException if estimation fails.
205      */
206     public static void generateInitialMetricCamerasUsingDAQ(
207             final FundamentalMatrix fundamentalMatrix,
208             final double aspectRatio,
209             final PinholeCamera leftCamera,
210             final PinholeCamera rightCamera)
211             throws InitialCamerasEstimationFailedException {
212 
213         try {
214             // generate arbitrary projective cameras
215             fundamentalMatrix.generateCamerasInArbitraryProjectiveSpace(leftCamera, rightCamera);
216 
217             final var cameras = new ArrayList<PinholeCamera>();
218             cameras.add(leftCamera);
219             cameras.add(rightCamera);
220 
221             // estimate dual absolute quadric
222             final var daqEstimator = new LMSEDualAbsoluteQuadricEstimator(cameras);
223             daqEstimator.setLMSESolutionAllowed(false);
224             daqEstimator.setZeroSkewness(true);
225             daqEstimator.setPrincipalPointAtOrigin(true);
226             daqEstimator.setFocalDistanceAspectRatioKnown(true);
227             daqEstimator.setFocalDistanceAspectRatio(aspectRatio);
228             daqEstimator.setSingularityEnforced(true);
229 
230             final var daq = daqEstimator.estimate();
231             final var transformation = daq.getMetricToProjectiveTransformation();
232             // inverse transformation to upgrade cameras from projective to
233             // metric stratum
234             transformation.inverse();
235 
236             // transform cameras
237             transformation.transform(leftCamera);
238             transformation.transform(rightCamera);
239         } catch (final Exception e) {
240             throw new InitialCamerasEstimationFailedException(e);
241         }
242     }
243 }