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 }