/*
* Copyright (c) 2011-2016, Peter Abeles. All Rights Reserved.
*
* This file is part of BoofCV (http://boofcv.org).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package boofcv.alg.geo.bundle;
import georegression.geometry.ConvertRotation3D_F64;
import georegression.struct.point.Point3D_F64;
import georegression.struct.point.Vector3D_F64;
import georegression.struct.se.Se3_F64;
import georegression.struct.so.Rodrigues_F64;
import org.ddogleg.fitting.modelset.ModelCodec;
import org.ejml.data.DenseMatrix64F;
import org.ejml.factory.DecompositionFactory;
import org.ejml.interfaces.decomposition.SingularValueDecomposition;
import org.ejml.ops.CommonOps;
/**
* Parametrization for Bundle Adjustment with known calibration where the
* rotation matrix is encoded using {@link Rodrigues_F64} coordinates.
*
* @author Peter Abeles
*/
public class CalibPoseAndPointRodriguesCodec
implements ModelCodec
{
// number of camera views
int numViews;
// number of points in world coordinates
int numPoints;
// number of views with unknown extrinsic parameters
int numViewsUnknown;
// indicates if a view is known or not
boolean knownView[];
// storage
Rodrigues_F64 rotation = new Rodrigues_F64();
DenseMatrix64F R = new DenseMatrix64F(3,3);
// used to make sure the rotation matrix is in SO(3)
SingularValueDecomposition svd = DecompositionFactory.svd(3, 3, true, true, false);
/**
* Specify the number of views and points it can expected
*/
public void configure( int numViews , int numPoints , int numViewsUnknown , boolean []knownView) {
if( numViews < knownView.length )
throw new IllegalArgumentException("Number of views is less than knownView length");
this.numViews = numViews;
this.numPoints = numPoints;
this.numViewsUnknown = numViewsUnknown;
this.knownView = knownView;
}
@Override
public void decode(double[] input, CalibratedPoseAndPoint outputModel) {
int paramIndex = 0;
// first decode the transformation
for( int i = 0; i < numViews; i++ ) {
// don't decode if it is already known
if( knownView[i] )
continue;
Se3_F64 se = outputModel.getWorldToCamera(i);
rotation.setParamVector(input[paramIndex++], input[paramIndex++], input[paramIndex++]);
ConvertRotation3D_F64.rodriguesToMatrix(rotation,se.getR());
Vector3D_F64 T = se.getT();
T.x = input[paramIndex++];
T.y = input[paramIndex++];
T.z = input[paramIndex++];
}
// now decode the points
for( int i = 0; i < numPoints; i++ ) {
Point3D_F64 p = outputModel.getPoint(i);
p.x = input[paramIndex++];
p.y = input[paramIndex++];
p.z = input[paramIndex++];
}
}
@Override
public void encode(CalibratedPoseAndPoint model, double[] param) {
int paramIndex = 0;
// first decode the transformation
for( int i = 0; i < numViews; i++ ) {
// don't encode if it is already known
if( knownView[i] )
continue;
Se3_F64 se = model.getWorldToCamera(i);
// force the "rotation matrix" to be an exact rotation matrix
// otherwise Rodrigues will have issues with the noise
if( !svd.decompose(se.getR()) )
throw new RuntimeException("SVD failed");
DenseMatrix64F U = svd.getU(null,false);
DenseMatrix64F V = svd.getV(null,false);
CommonOps.multTransB(U,V,R);
// extract Rodrigues coordinates
ConvertRotation3D_F64.matrixToRodrigues(R,rotation);
param[paramIndex++] = rotation.unitAxisRotation.x*rotation.theta;
param[paramIndex++] = rotation.unitAxisRotation.y*rotation.theta;
param[paramIndex++] = rotation.unitAxisRotation.z*rotation.theta;
Vector3D_F64 T = se.getT();
param[paramIndex++] = T.x;
param[paramIndex++] = T.y;
param[paramIndex++] = T.z;
}
for( int i = 0; i < numPoints; i++ ) {
Point3D_F64 p = model.getPoint(i);
param[paramIndex++] = p.x;
param[paramIndex++] = p.y;
param[paramIndex++] = p.z;
}
}
@Override
public int getParamLength() {
return numViewsUnknown*6 + numPoints*3;
}
}
Ads help maintain this website.