View Javadoc
1   /*
2    * Copyright (C) 2015 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.calibration;
17  
18  import com.irurueta.algebra.AlgebraException;
19  import com.irurueta.algebra.CholeskyDecomposer;
20  import com.irurueta.algebra.Matrix;
21  import com.irurueta.algebra.WrongSizeException;
22  import com.irurueta.geometry.Conic;
23  import com.irurueta.geometry.ConicNotAvailableException;
24  import com.irurueta.geometry.DualConic;
25  import com.irurueta.geometry.DualQuadric;
26  import com.irurueta.geometry.InvalidPinholeCameraIntrinsicParametersException;
27  import com.irurueta.geometry.NonSymmetricMatrixException;
28  import com.irurueta.geometry.PinholeCamera;
29  import com.irurueta.geometry.PinholeCameraIntrinsicParameters;
30  
31  import java.io.Serializable;
32  
33  /**
34   * The dual image of the absolute conic (DIAC), is the projection of the
35   * dual absolute quadric using a given pinhole camera.
36   * In an ideal metric stratum, the dual absolute quadric is equal to the
37   * identity matrix, except for the bottom-right element, which is zero. In those
38   * cases the dual image of the absolute conic only depends on the pinhole camera
39   * intrinsic parameters, and for that reason the DIAC is typically used for
40   * camera calibration purposes.
41   */
42  public class DualImageOfAbsoluteConic extends DualConic implements Serializable {
43  
44      /**
45       * Constructor.
46       * When working on a metric stratum, the DIAC is directly related by the
47       * pinhole camera intrinsic parameters as C^-1=K*K'
48       *
49       * @param k pinhole camera intrinsic parameters.
50       */
51      public DualImageOfAbsoluteConic(final PinholeCameraIntrinsicParameters k) {
52          super();
53          setFromPinholeCameraIntrinsicParameters(k);
54      }
55  
56      /**
57       * Constructor.
58       * When not working on a metric stratum, the DIAC can be obtained as the
59       * projection of provided dual absolute quadric using provided camera
60       *
61       * @param camera              a pinhole camera.
62       * @param dualAbsoluteQuadric the dual absolute quadric.
63       */
64      public DualImageOfAbsoluteConic(final PinholeCamera camera, final DualQuadric dualAbsoluteQuadric) {
65          super();
66          setFromCameraAndDualAbsoluteQuadric(camera, dualAbsoluteQuadric);
67      }
68  
69      /**
70       * Constructor of this class. This constructor accepts every parameter
71       * describing a dual conic (parameters a, b, c, d, e, f).
72       *
73       * @param a Parameter A of the conic.
74       * @param b Parameter B of the conic.
75       * @param c Parameter C of the conic.
76       * @param d Parameter D of the conic.
77       * @param e Parameter E of the conic.
78       * @param f Parameter F of the conic.
79       */
80      public DualImageOfAbsoluteConic(
81              final double a, final double b, final double c, final double d, final double e, final double f) {
82          super(a, b, c, d, e, f);
83      }
84  
85      /**
86       * This method sets the matrix used to describe a dual conic.
87       * This matrix must be 3x3 and symmetric.
88       *
89       * @param m 3x3 Matrix describing the conic.
90       * @throws IllegalArgumentException    Raised when the size of the matrix is
91       *                                     not 3x3.
92       * @throws NonSymmetricMatrixException Raised when the conic matrix is not
93       *                                     symmetric.
94       */
95      public DualImageOfAbsoluteConic(final Matrix m) throws NonSymmetricMatrixException {
96          super(m);
97      }
98  
99      /**
100      * Constructor without arguments.
101      */
102     protected DualImageOfAbsoluteConic() {
103         super();
104     }
105 
106     /**
107      * Computes the conic corresponding to this dual conic.
108      *
109      * @return A new conic instance of this dual conic.
110      * @throws ConicNotAvailableException Raised if the rank of the dual conic
111      *                                    matrix is not complete due to wrong parameters or numerical
112      *                                    instability.
113      */
114     @Override
115     public Conic getConic() throws ConicNotAvailableException {
116         final var c = new ImageOfAbsoluteConic();
117         conic(c);
118         return c;
119     }
120 
121 
122     /**
123      * Sets DIAC parameters from pinhole camera intrinsic parameters when we
124      * are working in a metric stratum, which is equal to C^-1=K*K'.
125      *
126      * @param k pinhole camera intrinsic parameters.
127      */
128     public final void setFromPinholeCameraIntrinsicParameters(final PinholeCameraIntrinsicParameters k) {
129         final var kMatrix = k.getInternalMatrix();
130         try {
131             setParameters(kMatrix.multiplyAndReturnNew(kMatrix.transposeAndReturnNew()));
132         } catch (final WrongSizeException | NonSymmetricMatrixException ignore) {
133             // never happens
134         }
135     }
136 
137     /**
138      * Sets DIAC parameters by projecting provided dual absolute quadric using
139      * provided pinhole camera. This method can be used when not working in a
140      * metric stratum. The projection is equal to C^-1=P*Q^-1*P'.
141      *
142      * @param camera              a pinhole camera.
143      * @param dualAbsoluteQuadric the dual absolute quadric.
144      */
145     public final void setFromCameraAndDualAbsoluteQuadric(final PinholeCamera camera,
146                                                           final DualQuadric dualAbsoluteQuadric) {
147         camera.project(dualAbsoluteQuadric, this);
148     }
149 
150     /**
151      * Assuming that we are working in a metric stratum this method obtains the
152      * internal parameters of a pinhole camera by means of Cholesky
153      * decomposition.
154      * To avoid numerical instabilities it is preferred to obtain the
155      * ImageOfAbsoluteConic corresponding to this instance (using #getConic()
156      * method), and from there using
157      * ImageOfAbsoluteConic#getIntrinsicParameters() method, since it is more
158      * reliable than using cholesky decomposition.
159      *
160      * @return the internal parameters of a pinhole camera.
161      * @throws InvalidPinholeCameraIntrinsicParametersException if pinhole
162      *                                                          camera intrinsic parameters cannot be
163      *                                                          obtained from this conic instance.
164      */
165     public PinholeCameraIntrinsicParameters getIntrinsicParameters()
166             throws InvalidPinholeCameraIntrinsicParametersException {
167         try {
168             normalize();
169             // the DIAC is a dual conic, and hence it is symmetric, hence:
170             // C^-1=K*K'=(K*K')'=(C^-1)'
171             // C=(K*K')^-1 = K'^-1*K^-1 = (K^-1)'*(K^-1), where K^-1 is still
172             // upper triangular
173             final var m = asMatrix();
174             final var invM = com.irurueta.algebra.Utils.inverse(m);
175             final var decomposer = new CholeskyDecomposer(invM);
176             decomposer.decompose();
177             final var inverseInternalParamsMatrix = decomposer.getR();
178             final var internalParamsMatrix = com.irurueta.algebra.Utils.inverse(inverseInternalParamsMatrix);
179             return new PinholeCameraIntrinsicParameters(internalParamsMatrix);
180         } catch (final AlgebraException e) {
181             throw new InvalidPinholeCameraIntrinsicParametersException(e);
182         }
183     }
184 }