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