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 }