00001
00002
00003
00004
00005
00006
00007
00008 #include "articulation_models/models/pca_gp_model.h"
00009 #include "articulation_models/utils.h"
00010
00011 using namespace std;
00012 using namespace articulation_msgs;
00013
00014 #include "Eigen/Core"
00015 #include <Eigen/SVD>
00016
00017 using namespace Eigen;
00018
00019 USING_PART_OF_NAMESPACE_EIGEN
00020
00021 #include <iomanip>
00022 #define VEC(a) setprecision(5)<<fixed<<a.x()<<" "<<a.y()<<" "<<a.z()<<" "<<a.w()<<" l="<<a.length()
00023 #define VEC2(a) "t=["<<VEC(a.getOrigin())<<"] r=[]"<<VEC(a.getRotation())<<"]"
00024 #define PRINT(a) cout << #a <<"=" << VEC(a)<<endl;
00025 #define PRINT2(a) cout << #a <<"=" << VEC2(a)<<endl;
00026
00027 #include <boost/format.hpp>
00028 using namespace boost;
00029
00030 namespace articulation_models {
00031
00032 PCAGPModel::PCAGPModel() {
00033 complexity = 0;
00034
00035 downsample = 20;
00036
00037
00038 CovFuncND initialCovFunc;
00039 double initialSigmaNoise;
00040 vector<double> params = vector<double>(2);
00041 params[0] = -0.5;
00042 params[1] = 0.0;
00043 initialCovFunc.setHyperparameter(params);
00044 initialSigmaNoise = -5;
00045
00046 for(size_t i=0;i<7;i++) {
00047 gp.push_back( new gaussian_process::SingleGP(initialCovFunc,initialSigmaNoise) );
00048 }
00049
00050 initialized = false;
00051 outlier_ratio = 0.0;
00052
00053 }
00054
00055 PCAGPModel::~PCAGPModel() {
00056 for(size_t i=0;i<gp.size();i++) {
00057 delete gp[i];
00058 }
00059 gp.clear();
00060 }
00061
00062
00063 void PCAGPModel::readParamsFromModel() {
00064 GenericModel::readParamsFromModel();
00065 getParam("downsample",downsample);
00066 getParam("rigid_position",rigid_position);
00067 getParam("prismatic_dir",prismatic_dir);
00068 double training_samples_float=0.00;
00069 getParam("training_samples",training_samples_float);
00070 training_samples = (int)training_samples_float;
00071 complexity = 3 + 6*training_samples;
00072
00073 checkInitialized();
00074 }
00075
00076 void PCAGPModel::writeParamsToModel() {
00077 GenericModel::writeParamsToModel();
00078 setParam("downsample",downsample,ParamMsg::PARAM);
00079 setParam("rigid_position",rigid_position,ParamMsg::PARAM);
00080 setParam("prismatic_dir",prismatic_dir,ParamMsg::PARAM);
00081 setParam("training_samples",training_samples,ParamMsg::PARAM);
00082 }
00083
00084 btTransform PCAGPModel::pose(size_t index) {
00085 btTransform pose;
00086 getParam(str(format("pose[%d]")%index),pose);
00087 return pose;
00088 }
00089
00090 void PCAGPModel::storeData(bool inliersOnly) {
00091
00092 bool resample = false;
00093 size_t n = model.track.pose.size();
00094
00095 vector<double> inliers_cum(n,0);
00096 double sum = 0;
00097 for(size_t i=0;i<n;i++) {
00098 if(inliersOnly)
00099 sum += 1 - model.track.channels[channelOutlier].values[i];
00100 else
00101 sum += 1;
00102 inliers_cum[i] = sum;
00103 }
00104
00105
00106 training_samples = (int)sum;
00107 if(downsample>0 && n>downsample) {
00108 training_samples = downsample;
00109 resample = true;
00110 }
00111 complexity = 1 + getDOFs() + 6*training_samples;
00112
00113 for(size_t i=0;i<training_samples;i++) {
00114 double choice = i / (double)training_samples;
00115 size_t j=0;
00116 for(j=0;j<n;j++) {
00117 if(inliers_cum[j]/sum>choice) break;
00118 }
00119
00120 setParam(str(format("pose[%d]")%i),poseToTransform(model.track.pose[j]),ParamMsg::PARAM);
00121 }
00122
00123 }
00124
00125 bool PCAGPModel::fitModel() {
00126 if(getSamples()<3) return true;
00127
00128
00129
00130
00131
00132 storeData(false);
00133 outlier_ratio = 0.0;
00134 buildGPs();
00135 getLogLikelihood(true);
00146
00147
00148
00149 return true;
00150 }
00151
00152 void PCAGPModel::buildGPs() {
00153 if(training_samples<3) return;
00154
00155
00156 btVector3 sum_p(0,0,0);
00157 for (size_t j = 0; j < training_samples; j++) {
00158 sum_p = sum_p + pose(j).getOrigin();
00159 }
00160 rigid_position = sum_p / training_samples;
00161
00162
00163 MatrixXf X_trans(training_samples, 3);
00164 for (size_t j = 0; j < training_samples; j++) {
00165 btVector3 diff = pose(j).getOrigin() - rigid_position;
00166 X_trans(j, 0) = diff.x();
00167 X_trans(j, 1) = diff.y();
00168 X_trans(j, 2) = diff.z();
00169 }
00170
00171 VectorXf b(training_samples);
00172 VectorXf x(3);
00173 b = VectorXf::Zero(training_samples);
00174 SVD<MatrixXf> svdOfA(X_trans);
00175 svdOfA.solve(b, &x);
00176
00177 const Eigen::MatrixXf U = svdOfA.matrixU();
00178 const Eigen::MatrixXf V = svdOfA.matrixV();
00179 const Eigen::VectorXf S = svdOfA.singularValues();
00180
00181 Eigen::MatrixXf Y_trans = U * S.asDiagonal();
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 prismatic_dir= btVector3(V(0, 0), V(1, 0), V(2, 0));
00200
00201
00202 if(!check_values(rigid_position)) {
00203 cerr <<"rigid_position has NaNs"<<endl;
00204 return ;
00205 }
00206 if(!check_values(prismatic_dir)) {
00207 cerr <<"prismatic_dir has NaNs"<<endl;
00208 return ;
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223 TVector<TDoubleVector> input(training_samples);
00224 TVector<double> output[7];
00225 for(size_t j=0;j<7;j++) {
00226 output[j] = TDoubleVector(training_samples);
00227 }
00228
00229 for(size_t i=0;i<training_samples;i++) {
00230 input[i] = TDoubleVector(1);
00231
00232 geometry_msgs::Pose p = transformToPose(pose(i));
00233 input[i][0] = predictConfiguration( p )[0];
00234 output[0][i] = p.position.x;
00235 output[1][i] = p.position.y;
00236 output[2][i] = p.position.z;
00237 output[3][i] = p.orientation.w;
00238 output[4][i] = p.orientation.x;
00239 output[5][i] = p.orientation.y;
00240 output[6][i] = p.orientation.z;
00241 }
00242
00243 for(size_t j=0;j<7;j++) {
00244
00245 gp[j]->SetData(input,output[j]);
00246
00247 }
00248
00249
00250
00251 }
00252
00253 V_Configuration PCAGPModel::predictConfiguration(geometry_msgs::Pose pose) {
00254 btVector3 diff = (positionToVector(pose.position) - rigid_position);
00255
00256
00257
00258 V_Configuration q( 1 );
00259 q(0) = diff.dot(prismatic_dir);
00260
00261 return q;
00262 }
00263
00264 geometry_msgs::Pose PCAGPModel::predictPose(V_Configuration q) {
00265 geometry_msgs::Pose result;
00266 double mean_x=0,var_x=0;
00267 double mean_y=0,var_y=0;
00268 double mean_z=0,var_z=0;
00269 double mean_rw=0,var_rw=0;
00270 double mean_rx=0,var_rx=0;
00271 double mean_ry=0,var_ry=0;
00272 double mean_rz=0,var_rz=0;
00273 TDoubleVector inp(1);
00274 inp(0) = q[0];
00275 gp[0]->Evaluate( inp, mean_x, var_x );
00276 gp[1]->Evaluate( inp, mean_y, var_y );
00277 gp[2]->Evaluate( inp, mean_z, var_z );
00278 gp[3]->Evaluate( inp, mean_rw, var_rw );
00279 gp[4]->Evaluate( inp, mean_rx, var_rx );
00280 gp[5]->Evaluate( inp, mean_ry, var_ry );
00281 gp[6]->Evaluate( inp, mean_rz, var_rz );
00282
00283 btQuaternion pred_rot(mean_rx,mean_ry,mean_rz,mean_rw);
00284 btVector3 pred_pos(mean_x,mean_y,mean_z);
00285 pred_rot.normalize();
00286 btTransform pred_pose(pred_rot,pred_pos);
00287 result = transformToPose(pred_pose);
00288
00289
00290
00291
00292 return result;
00293 }
00294
00295 void PCAGPModel::checkInitialized() {
00296 if(!initialized) {
00297 buildGPs();
00298 initialized = true;
00299 }
00300 }
00301
00302 void PCAGPModel::projectPoseToConfiguration() {
00303 checkInitialized();
00304 GenericModel::projectPoseToConfiguration();
00305 }
00306
00307 void PCAGPModel::projectConfigurationToPose() {
00308 checkInitialized();
00309 GenericModel::projectConfigurationToPose();
00310 }
00311
00312 void PCAGPModel::projectConfigurationToJacobian() {
00313 checkInitialized();
00314 GenericModel::projectConfigurationToJacobian();
00315 }
00316
00317 bool PCAGPModel::evaluateModel() {
00318 checkInitialized();
00319 return GenericModel::evaluateModel();
00320 }
00321
00322 bool PCAGPModel::normalizeParameters() {
00323 if(model.track.pose.size()>2) {
00324 rigid_position = rigid_position + predictConfiguration(model.track.pose.front())[0] * prismatic_dir;
00325 if(predictConfiguration(model.track.pose.back())[0]<0)
00326 prismatic_dir *= -1;
00327 }
00328 return true;
00329 }
00330 }