00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "ErrorMinimizersImpl.h"
00037 #include "PointMatcherPrivate.h"
00038 #include "Functions.h"
00039
00040 #include "Eigen/SVD"
00041 #include <iostream>
00042
00043 using namespace Eigen;
00044 using namespace std;
00045 using namespace PointMatcherSupport;
00046
00047
00048 template<typename T>
00049 typename PointMatcher<T>::TransformationParameters ErrorMinimizersImpl<T>::IdentityErrorMinimizer::compute(
00050 const DataPoints& filteredReading,
00051 const DataPoints& filteredReference,
00052 const OutlierWeights& outlierWeights,
00053 const Matches& matches)
00054 {
00055 return TransformationParameters::Identity(filteredReading.features.rows(), filteredReading.features.rows());
00056 }
00057
00058 template struct ErrorMinimizersImpl<float>::IdentityErrorMinimizer;
00059 template struct ErrorMinimizersImpl<double>::IdentityErrorMinimizer;
00060
00061
00062
00063 template<typename T>
00064 typename PointMatcher<T>::TransformationParameters ErrorMinimizersImpl<T>::PointToPointErrorMinimizer::compute(
00065 const DataPoints& filteredReading,
00066 const DataPoints& filteredReference,
00067 const OutlierWeights& outlierWeights,
00068 const Matches& matches)
00069 {
00070 typedef typename Matches::Ids Ids;
00071
00072 assert(matches.ids.rows() > 0);
00073
00074 typename ErrorMinimizer::ErrorElements& mPts = this->getMatchedPoints(filteredReading, filteredReference, matches, outlierWeights);
00075
00076
00077 const int dimCount(mPts.reading.features.rows());
00078 const int ptsCount(mPts.reading.features.cols());
00079
00080
00081 const Vector meanReading = mPts.reading.features.rowwise().sum() / ptsCount;
00082 const Vector meanReference = mPts.reference.features.rowwise().sum() / ptsCount;
00083
00084
00085 mPts.reading.features.colwise() -= meanReading;
00086 mPts.reference.features.colwise() -= meanReference;
00087
00088
00089 const Matrix m(mPts.reference.features.topRows(dimCount-1) * mPts.reading.features.topRows(dimCount-1).transpose());
00090 const JacobiSVD<Matrix> svd(m, ComputeThinU | ComputeThinV);
00091 const Matrix rotMatrix(svd.matrixU() * svd.matrixV().transpose());
00092 const Vector trVector(meanReference.head(dimCount-1)- rotMatrix * meanReading.head(dimCount-1));
00093
00094 Matrix result(Matrix::Identity(dimCount, dimCount));
00095 result.corner(TopLeft, dimCount-1, dimCount-1) = rotMatrix;
00096 result.corner(TopRight, dimCount-1, 1) = trVector;
00097
00098 return result;
00099 }
00100
00101 template<typename T>
00102 T ErrorMinimizersImpl<T>::PointToPointErrorMinimizer::getOverlap() const
00103 {
00104
00105
00106
00107 const int nbPoints = this->lastErrorElements.reading.features.cols();
00108 if(nbPoints == 0)
00109 {
00110 throw std::runtime_error("Error, last error element empty. Error minimizer needs to be called at least once before using this method.");
00111 }
00112
00113 if (!this->lastErrorElements.reading.descriptorExists("simpleSensorNoise"))
00114 {
00115 LOG_INFO_STREAM("PointToPointErrorMinimizer - warning, no sensor noise found. Using best estimate given outlier rejection instead.");
00116 return this->weightedPointUsedRatio;
00117 }
00118
00119 const BOOST_AUTO(noises, this->lastErrorElements.reading.getDescriptorViewByName("simpleSensorNoise"));
00120
00121 const Vector dists = (this->lastErrorElements.reading.features - this->lastErrorElements.reference.features).colwise().norm();
00122 const T mean = dists.sum()/nbPoints;
00123
00124 int count = 0;
00125 for(int i=0; i < nbPoints; i++)
00126 {
00127 if(dists(i) < (mean + noises(0,i)))
00128 {
00129 count++;
00130 }
00131 }
00132
00133 return (T)count/(T)nbPoints;
00134 }
00135
00136 template struct ErrorMinimizersImpl<float>::PointToPointErrorMinimizer;
00137 template struct ErrorMinimizersImpl<double>::PointToPointErrorMinimizer;
00138
00139
00140
00141 template<typename T>
00142 ErrorMinimizersImpl<T>::PointToPlaneErrorMinimizer::PointToPlaneErrorMinimizer(const Parameters& params):
00143 ErrorMinimizer("PointToPlaneErrorMinimizer", PointToPlaneErrorMinimizer::availableParameters(), params),
00144 force2D(Parametrizable::get<T>("force2D"))
00145 {
00146 }
00147
00148
00149 template<typename T>
00150 typename PointMatcher<T>::TransformationParameters ErrorMinimizersImpl<T>::PointToPlaneErrorMinimizer::compute(
00151 const DataPoints& filteredReading,
00152 const DataPoints& filteredReference,
00153 const OutlierWeights& outlierWeights,
00154 const Matches& matches)
00155 {
00156 typedef typename PointMatcher<T>::ConvergenceError ConvergenceError;
00157 typedef typename Matches::Ids Ids;
00158
00159 assert(matches.ids.rows() > 0);
00160
00161
00162 typename ErrorMinimizer::ErrorElements& mPts = this->getMatchedPoints(filteredReading, filteredReference, matches, outlierWeights);
00163
00164 const int dim = mPts.reading.features.rows();
00165 const int nbPts = mPts.reading.features.cols();
00166
00167
00168 int forcedDim = dim - 1;
00169 if(force2D && dim == 4)
00170 {
00171 mPts.reading.features.conservativeResize(3, Eigen::NoChange);
00172 mPts.reading.features.row(2) = Matrix::Ones(1, nbPts);
00173 mPts.reference.features.conservativeResize(3, Eigen::NoChange);
00174 mPts.reference.features.row(2) = Matrix::Ones(1, nbPts);
00175 forcedDim = dim - 2;
00176 }
00177
00178
00179 const BOOST_AUTO(normalRef, mPts.reference.getDescriptorViewByName("normals").topRows(forcedDim));
00180
00181
00182 assert(normalRef.rows() > 0);
00183
00184
00185 const Matrix cross = this->crossProduct(mPts.reading.features, normalRef);
00186
00187
00188
00189 Matrix wF(normalRef.rows()+ cross.rows(), normalRef.cols());
00190 Matrix F(normalRef.rows()+ cross.rows(), normalRef.cols());
00191
00192 for(int i=0; i < cross.rows(); i++)
00193 {
00194 wF.row(i) = mPts.weights.cwise() * cross.row(i);
00195 F.row(i) = cross.row(i);
00196 }
00197 for(int i=0; i < normalRef.rows(); i++)
00198 {
00199 wF.row(i + cross.rows()) = normalRef.row(i);
00200 F.row(i + cross.rows()) = normalRef.row(i);
00201 }
00202
00203
00204 const Matrix A = wF * F.transpose();
00205 if (A.fullPivHouseholderQr().rank() != A.rows())
00206 {
00207
00208
00209 }
00210
00211 const Matrix deltas = mPts.reading.features - mPts.reference.features;
00212
00213
00214 Matrix dotProd = Matrix::Zero(1, normalRef.cols());
00215
00216 for(int i=0; i<normalRef.rows(); i++)
00217 {
00218 dotProd += (deltas.row(i).cwise() * normalRef.row(i));
00219 }
00220
00221
00222 const Vector b = -(wF * dotProd.transpose());
00223
00224
00225 Vector x(A.rows());
00226 A.llt().solve(b, &x);
00227
00228
00229 Matrix mOut;
00230 if(dim == 4 && !force2D)
00231 {
00232 Eigen::Transform<T, 3, Eigen::Affine> transform;
00233
00234 transform = Eigen::AngleAxis<T>(x(0), Eigen::Matrix<T,1,3>::UnitX())
00235 * Eigen::AngleAxis<T>(x(1), Eigen::Matrix<T,1,3>::UnitY())
00236 * Eigen::AngleAxis<T>(x(2), Eigen::Matrix<T,1,3>::UnitZ());
00237
00238
00239
00240
00241
00242 transform.translation() = x.segment(3, 3);
00243 mOut = transform.matrix();
00244 }
00245 else
00246 {
00247 Eigen::Transform<T, 2, Eigen::Affine> transform;
00248 transform = Eigen::Rotation2D<T> (x(0));
00249 transform.translation() = x.segment(1, 2);
00250
00251 if(force2D)
00252 {
00253 mOut = Matrix::Identity(dim, dim);
00254 mOut.corner(TopLeft, 2, 2) = transform.matrix().corner(TopLeft, 2, 2);
00255 mOut.corner(TopRight, 2, 1) = transform.matrix().corner(TopRight, 2, 1);
00256 }
00257 else
00258 {
00259 mOut = transform.matrix();
00260 }
00261 }
00262 return mOut;
00263 }
00264
00265 template<typename T>
00266 T ErrorMinimizersImpl<T>::PointToPlaneErrorMinimizer::getOverlap() const
00267 {
00268 const int nbPoints = this->lastErrorElements.reading.features.cols();
00269 const int dim = this->lastErrorElements.reading.features.rows();
00270 if(nbPoints == 0)
00271 {
00272 throw std::runtime_error("Error, last error element empty. Error minimizer needs to be called at least once before using this method.");
00273 }
00274
00275 if (!this->lastErrorElements.reading.descriptorExists("simpleSensorNoise") ||
00276 !this->lastErrorElements.reading.descriptorExists("normals"))
00277 {
00278 LOG_INFO_STREAM("PointToPlaneErrorMinimizer - warning, no sensor noise or normals found. Using best estimate given outlier rejection instead.");
00279 return this->weightedPointUsedRatio;
00280 }
00281
00282 const BOOST_AUTO(noises, this->lastErrorElements.reading.getDescriptorViewByName("simpleSensorNoise"));
00283 const BOOST_AUTO(normals, this->lastErrorElements.reading.getDescriptorViewByName("normals"));
00284 int count = 0;
00285 for(int i=0; i < nbPoints; i++)
00286 {
00287 if(this->lastErrorElements.matches.dists(0, i) != numeric_limits<T>::infinity())
00288 {
00289 const Vector d = this->lastErrorElements.reading.features.col(i) - this->lastErrorElements.reference.features.col(i);
00290 const Vector n = normals.col(i);
00291 const T projectionDist = d.head(dim-1).dot(n.normalized());
00292 if(anyabs(projectionDist) < noises(0,i))
00293 count++;
00294 }
00295 }
00296
00297 return (T)count/(T)nbPoints;
00298 }
00299
00300 template struct ErrorMinimizersImpl<float>::PointToPlaneErrorMinimizer;
00301 template struct ErrorMinimizersImpl<double>::PointToPlaneErrorMinimizer;
00302
00303
00304
00305
00306 template<typename T>
00307 ErrorMinimizersImpl<T>::PointToPointWithCovErrorMinimizer::PointToPointWithCovErrorMinimizer(const Parameters& params):
00308 ErrorMinimizer("PointToPointWithCovErrorMinimizer", PointToPointWithCovErrorMinimizer::availableParameters(), params),
00309 sensorStdDev(Parametrizable::get<T>("sensorStdDev"))
00310 {
00311 }
00312
00313 template<typename T>
00314 typename PointMatcher<T>::TransformationParameters ErrorMinimizersImpl<T>::PointToPointWithCovErrorMinimizer::compute(
00315 const DataPoints& filteredReading,
00316 const DataPoints& filteredReference,
00317 const OutlierWeights& outlierWeights,
00318 const Matches& matches)
00319 {
00320 typedef typename Matches::Ids Ids;
00321
00322 assert(matches.ids.rows() > 0);
00323
00324 typename ErrorMinimizer::ErrorElements& mPts = this->getMatchedPoints(filteredReading, filteredReference, matches, outlierWeights);
00325
00326
00327 const int dimCount(mPts.reading.features.rows());
00328 const int ptsCount(mPts.reading.features.cols());
00329
00330
00331 const Vector meanReading = mPts.reading.features.rowwise().sum() / ptsCount;
00332 const Vector meanReference = mPts.reference.features.rowwise().sum() / ptsCount;
00333
00334
00335 mPts.reading.features.colwise() -= meanReading;
00336 mPts.reference.features.colwise() -= meanReference;
00337
00338
00339 const Matrix m(mPts.reference.features.topRows(dimCount-1) * mPts.reading.features.topRows(dimCount-1).transpose());
00340 const JacobiSVD<Matrix> svd(m, ComputeThinU | ComputeThinV);
00341 const Matrix rotMatrix(svd.matrixU() * svd.matrixV().transpose());
00342 const Vector trVector(meanReference.head(dimCount-1)- rotMatrix * meanReading.head(dimCount-1));
00343
00344 Matrix result(Matrix::Identity(dimCount, dimCount));
00345 result.corner(TopLeft, dimCount-1, dimCount-1) = rotMatrix;
00346 result.corner(TopRight, dimCount-1, 1) = trVector;
00347
00348 this->covMatrix = this->estimateCovariance(filteredReading, filteredReference, matches, outlierWeights, result);
00349
00350 return result;
00351 }
00352
00353 template<typename T>
00354 typename ErrorMinimizersImpl<T>::Matrix
00355 ErrorMinimizersImpl<T>::PointToPointWithCovErrorMinimizer::estimateCovariance(const DataPoints& reading, const DataPoints& reference, const Matches& matches, const OutlierWeights& outlierWeights, const TransformationParameters& transformation)
00356 {
00357 int max_nbr_point = outlierWeights.cols();
00358
00359 Matrix covariance(Matrix::Zero(6,6));
00360 Matrix J_hessian(Matrix::Zero(6,6));
00361 Matrix d2J_dReadingdX(Matrix::Zero(6, max_nbr_point));
00362 Matrix d2J_dReferencedX(Matrix::Zero(6, max_nbr_point));
00363
00364 Vector reading_point(Vector::Zero(3));
00365 Vector reference_point(Vector::Zero(3));
00366 Vector normal(3);
00367 Vector reading_direction(Vector::Zero(3));
00368 Vector reference_direction(Vector::Zero(3));
00369
00370 normal << 1.0, 1.0, 1.0;
00371
00372 T beta = -asin(transformation(2,0));
00373 T alpha = atan2(transformation(2,1), transformation(2,2));
00374 T gamma = atan2(transformation(1,0)/cos(beta), transformation(0,0)/cos(beta));
00375 T t_x = transformation(0,3);
00376 T t_y = transformation(1,3);
00377 T t_z = transformation(2,3);
00378
00379 Vector tmp_vector_6(Vector::Zero(6));
00380
00381 int valid_points_count = 0;
00382
00383 for(int i = 0; i < max_nbr_point; ++i)
00384 {
00385 if (outlierWeights(0,i) > 0.0)
00386 {
00387 reading_point = reading.features.block(0,i,3,1);
00388 int reference_idx = matches.ids(0,i);
00389 reference_point = reference.features.block(0,reference_idx,3,1);
00390
00391 T reading_range = reading_point.norm();
00392 reading_direction = reading_point / reading_range;
00393 T reference_range = reference_point.norm();
00394 reference_direction = reference_point / reference_range;
00395
00396 T n_alpha = normal(2)*reading_direction(1) - normal(1)*reading_direction(2);
00397 T n_beta = normal(0)*reading_direction(2) - normal(2)*reading_direction(0);
00398 T n_gamma = normal(1)*reading_direction(0) - normal(0)*reading_direction(1);
00399
00400 T E = normal(0)*(reading_point(0) - gamma*reading_point(1) + beta*reading_point(2) + t_x - reference_point(0));
00401 E += normal(1)*(gamma*reading_point(0) + reading_point(1) - alpha*reading_point(2) + t_y - reference_point(1));
00402 E += normal(2)*(-beta*reading_point(0) + alpha*reading_point(1) + reading_point(2) + t_z - reference_point(2));
00403
00404 T N_reading = normal(0)*(reading_direction(0) - gamma*reading_direction(1) + beta*reading_direction(2));
00405 N_reading += normal(1)*(gamma*reading_direction(0) + reading_direction(1) - alpha*reading_direction(2));
00406 N_reading += normal(2)*(-beta*reading_direction(0) + alpha*reading_direction(1) + reading_direction(2));
00407
00408 T N_reference = -(normal(0)*reference_direction(0) + normal(1)*reference_direction(1) + normal(2)*reference_direction(2));
00409
00410
00411 tmp_vector_6 << normal(0), normal(1), normal(2), reading_range * n_alpha, reading_range * n_beta, reading_range * n_gamma;
00412
00413 J_hessian += tmp_vector_6 * tmp_vector_6.transpose();
00414
00415 tmp_vector_6 << normal(0) * N_reading, normal(1) * N_reading, normal(2) * N_reading, n_alpha * (E + reading_range * N_reading), n_beta * (E + reading_range * N_reading), n_gamma * (E + reading_range * N_reading);
00416
00417 d2J_dReadingdX.block(0,valid_points_count,6,1) = tmp_vector_6;
00418
00419 tmp_vector_6 << normal(0) * N_reference, normal(1) * N_reference, normal(2) * N_reference, reference_range * n_alpha * N_reference, reference_range * n_beta * N_reference, reference_range * n_gamma * N_reference;
00420
00421 d2J_dReferencedX.block(0,valid_points_count,6,1) = tmp_vector_6;
00422
00423 valid_points_count++;
00424 }
00425 }
00426
00427 Matrix d2J_dZdX(Matrix::Zero(6, 2 * valid_points_count));
00428 d2J_dZdX.block(0,0,6,valid_points_count) = d2J_dReadingdX.block(0,0,6,valid_points_count);
00429 d2J_dZdX.block(0,valid_points_count,6,valid_points_count) = d2J_dReferencedX.block(0,0,6,valid_points_count);
00430
00431 Matrix inv_J_hessian = J_hessian.inverse();
00432
00433 covariance = d2J_dZdX * d2J_dZdX.transpose();
00434 covariance = inv_J_hessian * covariance * inv_J_hessian;
00435
00436 return (sensorStdDev * sensorStdDev) * covariance;
00437 }
00438
00439 template<typename T>
00440 T ErrorMinimizersImpl<T>::PointToPointWithCovErrorMinimizer::getOverlap() const
00441 {
00442 const int nbPoints = this->lastErrorElements.reading.features.cols();
00443 if(nbPoints == 0)
00444 {
00445 throw std::runtime_error("Error, last error element empty. Error minimizer needs to be called at least once before using this method.");
00446 }
00447
00448 if (!this->lastErrorElements.reading.descriptorExists("simpleSensorNoise"))
00449 {
00450 LOG_INFO_STREAM("PointToPointErrorMinimizer - warning, no sensor noise found. Using best estimate given outlier rejection instead.");
00451 return this->weightedPointUsedRatio;
00452 }
00453
00454 const BOOST_AUTO(noises, this->lastErrorElements.reading.getDescriptorViewByName("simpleSensorNoise"));
00455 int count = 0;
00456 for(int i=0; i < nbPoints; i++)
00457 {
00458 const T dist = (this->lastErrorElements.reading.features.col(i) - this->lastErrorElements.reference.features.col(i)).norm();
00459 if(dist < noises(0,i))
00460 count++;
00461
00462 }
00463
00464 return (T)count/(T)nbPoints;
00465 }
00466
00467 template<typename T>
00468 typename ErrorMinimizersImpl<T>::Matrix ErrorMinimizersImpl<T>::PointToPointWithCovErrorMinimizer::getCovariance() const
00469 {
00470 return covMatrix;
00471 }
00472
00473 template struct ErrorMinimizersImpl<float>::PointToPointWithCovErrorMinimizer;
00474 template struct ErrorMinimizersImpl<double>::PointToPointWithCovErrorMinimizer;
00475
00476
00477
00478 template<typename T>
00479 ErrorMinimizersImpl<T>::PointToPlaneWithCovErrorMinimizer::PointToPlaneWithCovErrorMinimizer(const Parameters& params):
00480 ErrorMinimizer("PointToPlaneWithCovErrorMinimizer", PointToPlaneWithCovErrorMinimizer::availableParameters(), params),
00481 force2D(Parametrizable::get<T>("force2D")),
00482 sensorStdDev(Parametrizable::get<T>("sensorStdDev"))
00483 {
00484 }
00485
00486
00487 template<typename T>
00488 typename PointMatcher<T>::TransformationParameters ErrorMinimizersImpl<T>::PointToPlaneWithCovErrorMinimizer::compute(
00489 const DataPoints& filteredReading,
00490 const DataPoints& filteredReference,
00491 const OutlierWeights& outlierWeights,
00492 const Matches& matches)
00493 {
00494 typedef typename PointMatcher<T>::ConvergenceError ConvergenceError;
00495 typedef typename Matches::Ids Ids;
00496
00497 assert(matches.ids.rows() > 0);
00498
00499
00500 typename ErrorMinimizer::ErrorElements& mPts = this->getMatchedPoints(filteredReading, filteredReference, matches, outlierWeights);
00501
00502 const int dim = mPts.reading.features.rows();
00503 const int nbPts = mPts.reading.features.cols();
00504
00505
00506 int forcedDim = dim - 1;
00507 if(force2D && dim == 4)
00508 {
00509 mPts.reading.features.conservativeResize(3, Eigen::NoChange);
00510 mPts.reading.features.row(2) = Matrix::Ones(1, nbPts);
00511 mPts.reference.features.conservativeResize(3, Eigen::NoChange);
00512 mPts.reference.features.row(2) = Matrix::Ones(1, nbPts);
00513 forcedDim = dim - 2;
00514 }
00515
00516
00517 const BOOST_AUTO(normalRef, mPts.reference.getDescriptorViewByName("normals").topRows(forcedDim));
00518
00519
00520 assert(normalRef.rows() > 0);
00521
00522
00523 const Matrix cross = this->crossProduct(mPts.reading.features, normalRef);
00524
00525
00526
00527 Matrix wF(normalRef.rows()+ cross.rows(), normalRef.cols());
00528 Matrix F(normalRef.rows()+ cross.rows(), normalRef.cols());
00529
00530 for(int i=0; i < cross.rows(); i++)
00531 {
00532 wF.row(i) = mPts.weights.cwise() * cross.row(i);
00533 F.row(i) = cross.row(i);
00534 }
00535 for(int i=0; i < normalRef.rows(); i++)
00536 {
00537 wF.row(i + cross.rows()) = normalRef.row(i);
00538 F.row(i + cross.rows()) = normalRef.row(i);
00539 }
00540
00541
00542 const Matrix A = wF * F.transpose();
00543 if (A.fullPivHouseholderQr().rank() != A.rows())
00544 {
00545
00546
00547 }
00548
00549 const Matrix deltas = mPts.reading.features - mPts.reference.features;
00550
00551
00552 Matrix dotProd = Matrix::Zero(1, normalRef.cols());
00553
00554 for(int i=0; i<normalRef.rows(); i++)
00555 {
00556 dotProd += (deltas.row(i).cwise() * normalRef.row(i));
00557 }
00558
00559
00560 const Vector b = -(wF * dotProd.transpose());
00561
00562
00563 Vector x(A.rows());
00564 A.llt().solve(b, &x);
00565
00566
00567 Matrix mOut;
00568 if(dim == 4 && !force2D)
00569 {
00570 Eigen::Transform<T, 3, Eigen::Affine> transform;
00571
00572 transform = Eigen::AngleAxis<T>(x(0), Eigen::Matrix<T,1,3>::UnitX())
00573 * Eigen::AngleAxis<T>(x(1), Eigen::Matrix<T,1,3>::UnitY())
00574 * Eigen::AngleAxis<T>(x(2), Eigen::Matrix<T,1,3>::UnitZ());
00575
00576
00577
00578
00579
00580 transform.translation() = x.segment(3, 3);
00581 mOut = transform.matrix();
00582 }
00583 else
00584 {
00585 Eigen::Transform<T, 2, Eigen::Affine> transform;
00586 transform = Eigen::Rotation2D<T> (x(0));
00587 transform.translation() = x.segment(1, 2);
00588
00589 if(force2D)
00590 {
00591 mOut = Matrix::Identity(dim, dim);
00592 mOut.corner(TopLeft, 2, 2) = transform.matrix().corner(TopLeft, 2, 2);
00593 mOut.corner(TopRight, 2, 1) = transform.matrix().corner(TopRight, 2, 1);
00594 }
00595 else
00596 {
00597 mOut = transform.matrix();
00598 }
00599 }
00600
00601 this->covMatrix = this->estimateCovariance(filteredReading, filteredReference, matches, outlierWeights, mOut);
00602
00603 return mOut;
00604 }
00605
00606 template<typename T>
00607 typename ErrorMinimizersImpl<T>::Matrix
00608 ErrorMinimizersImpl<T>::PointToPlaneWithCovErrorMinimizer::estimateCovariance(const DataPoints& reading, const DataPoints& reference, const Matches& matches, const OutlierWeights& outlierWeights, const TransformationParameters& transformation)
00609 {
00610 int max_nbr_point = outlierWeights.cols();
00611
00612 Matrix covariance(Matrix::Zero(6,6));
00613 Matrix J_hessian(Matrix::Zero(6,6));
00614 Matrix d2J_dReadingdX(Matrix::Zero(6, max_nbr_point));
00615 Matrix d2J_dReferencedX(Matrix::Zero(6, max_nbr_point));
00616
00617 Vector reading_point(Vector::Zero(3));
00618 Vector reference_point(Vector::Zero(3));
00619 Vector normal(3);
00620 Vector reading_direction(Vector::Zero(3));
00621 Vector reference_direction(Vector::Zero(3));
00622
00623 Matrix normals = reference.getDescriptorViewByName("normals");
00624
00625 if (normals.rows() < 3)
00626 return Matrix::Zero(6,6);
00627
00628 T beta = -asin(transformation(2,0));
00629 T alpha = atan2(transformation(2,1), transformation(2,2));
00630 T gamma = atan2(transformation(1,0)/cos(beta), transformation(0,0)/cos(beta));
00631 T t_x = transformation(0,3);
00632 T t_y = transformation(1,3);
00633 T t_z = transformation(2,3);
00634
00635 Vector tmp_vector_6(Vector::Zero(6));
00636
00637 int valid_points_count = 0;
00638
00639 for(int i = 0; i < max_nbr_point; ++i)
00640 {
00641 if (outlierWeights(0,i) > 0.0)
00642 {
00643 reading_point = reading.features.block(0,i,3,1);
00644 int reference_idx = matches.ids(0,i);
00645 reference_point = reference.features.block(0,reference_idx,3,1);
00646
00647 normal = normals.block(0,reference_idx,3,1);
00648
00649 T reading_range = reading_point.norm();
00650 reading_direction = reading_point / reading_range;
00651 T reference_range = reference_point.norm();
00652 reference_direction = reference_point / reference_range;
00653
00654 T n_alpha = normal(2)*reading_direction(1) - normal(1)*reading_direction(2);
00655 T n_beta = normal(0)*reading_direction(2) - normal(2)*reading_direction(0);
00656 T n_gamma = normal(1)*reading_direction(0) - normal(0)*reading_direction(1);
00657
00658 T E = normal(0)*(reading_point(0) - gamma*reading_point(1) + beta*reading_point(2) + t_x - reference_point(0));
00659 E += normal(1)*(gamma*reading_point(0) + reading_point(1) - alpha*reading_point(2) + t_y - reference_point(1));
00660 E += normal(2)*(-beta*reading_point(0) + alpha*reading_point(1) + reading_point(2) + t_z - reference_point(2));
00661
00662 T N_reading = normal(0)*(reading_direction(0) - gamma*reading_direction(1) + beta*reading_direction(2));
00663 N_reading += normal(1)*(gamma*reading_direction(0) + reading_direction(1) - alpha*reading_direction(2));
00664 N_reading += normal(2)*(-beta*reading_direction(0) + alpha*reading_direction(1) + reading_direction(2));
00665
00666 T N_reference = -(normal(0)*reference_direction(0) + normal(1)*reference_direction(1) + normal(2)*reference_direction(2));
00667
00668
00669 tmp_vector_6 << normal(0), normal(1), normal(2), reading_range * n_alpha, reading_range * n_beta, reading_range * n_gamma;
00670
00671 J_hessian += tmp_vector_6 * tmp_vector_6.transpose();
00672
00673 tmp_vector_6 << normal(0) * N_reading, normal(1) * N_reading, normal(2) * N_reading, n_alpha * (E + reading_range * N_reading), n_beta * (E + reading_range * N_reading), n_gamma * (E + reading_range * N_reading);
00674
00675 d2J_dReadingdX.block(0,valid_points_count,6,1) = tmp_vector_6;
00676
00677 tmp_vector_6 << normal(0) * N_reference, normal(1) * N_reference, normal(2) * N_reference, reference_range * n_alpha * N_reference, reference_range * n_beta * N_reference, reference_range * n_gamma * N_reference;
00678
00679 d2J_dReferencedX.block(0,valid_points_count,6,1) = tmp_vector_6;
00680
00681 valid_points_count++;
00682 }
00683 }
00684
00685 Matrix d2J_dZdX(Matrix::Zero(6, 2 * valid_points_count));
00686 d2J_dZdX.block(0,0,6,valid_points_count) = d2J_dReadingdX.block(0,0,6,valid_points_count);
00687 d2J_dZdX.block(0,valid_points_count,6,valid_points_count) = d2J_dReferencedX.block(0,0,6,valid_points_count);
00688
00689 Matrix inv_J_hessian = J_hessian.inverse();
00690
00691 covariance = d2J_dZdX * d2J_dZdX.transpose();
00692 covariance = inv_J_hessian * covariance * inv_J_hessian;
00693
00694 return (sensorStdDev * sensorStdDev) * covariance;
00695 }
00696
00697
00698
00699 template<typename T>
00700 T ErrorMinimizersImpl<T>::PointToPlaneWithCovErrorMinimizer::getOverlap() const
00701 {
00702 const int nbPoints = this->lastErrorElements.reading.features.cols();
00703 const int dim = this->lastErrorElements.reading.features.rows();
00704 if(nbPoints == 0)
00705 {
00706 throw std::runtime_error("Error, last error element empty. Error minimizer needs to be called at least once before using this method.");
00707 }
00708
00709 if (!this->lastErrorElements.reading.descriptorExists("simpleSensorNoise") ||
00710 !this->lastErrorElements.reading.descriptorExists("normals"))
00711 {
00712 LOG_INFO_STREAM("PointToPlaneErrorMinimizer - warning, no sensor noise or normals found. Using best estimate given outlier rejection instead.");
00713 return this->weightedPointUsedRatio;
00714 }
00715
00716 const BOOST_AUTO(noises, this->lastErrorElements.reading.getDescriptorViewByName("simpleSensorNoise"));
00717 const BOOST_AUTO(normals, this->lastErrorElements.reading.getDescriptorViewByName("normals"));
00718 int count = 0;
00719 for(int i=0; i < nbPoints; i++)
00720 {
00721 if(this->lastErrorElements.matches.dists(0, i) != numeric_limits<T>::infinity())
00722 {
00723 const Vector d = this->lastErrorElements.reading.features.col(i) - this->lastErrorElements.reference.features.col(i);
00724 const Vector n = normals.col(i);
00725 const T projectionDist = d.head(dim-1).dot(n.normalized());
00726 if(anyabs(projectionDist) < noises(0,i))
00727 count++;
00728 }
00729 }
00730
00731 return (T)count/(T)nbPoints;
00732 }
00733
00734 template<typename T>
00735 typename ErrorMinimizersImpl<T>::Matrix ErrorMinimizersImpl<T>::PointToPlaneWithCovErrorMinimizer::getCovariance() const
00736 {
00737 return covMatrix;
00738 }
00739
00740 template struct ErrorMinimizersImpl<float>::PointToPlaneWithCovErrorMinimizer;
00741 template struct ErrorMinimizersImpl<double>::PointToPlaneWithCovErrorMinimizer;
00742