/* * Software License Agreement (BSD License) * * Point Cloud Library (PCL) - www.pointclouds.org * Copyright (c) 2010-2011, Willow Garage, Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the copyright holder(s) nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $Id$ */ #pragma once #include #include namespace pcl { /** Principal Component analysis (PCA) class.\n * Principal components are extracted by singular values decomposition on the * covariance matrix of the centered input cloud. Available data after pca computation * are:\n * - The Mean of the input data\n * - The Eigenvectors: Ordered set of vectors representing the resultant principal components and the eigenspace cartesian basis (right-handed coordinate system).\n * - The Eigenvalues: Eigenvectors correspondent loadings ordered in descending order.\n\n * Other methods allow projection in the eigenspace, reconstruction from eigenspace and * update of the eigenspace with a new datum (according Matej Artec, Matjaz Jogan and * Ales Leonardis: "Incremental PCA for On-line Visual Learning and Recognition"). * * \author Nizar Sallem * \ingroup common */ template class PCA : public pcl::PCLBase { public: using Base = pcl::PCLBase; using PointCloud = typename Base::PointCloud; using PointCloudPtr = typename Base::PointCloudPtr; using PointCloudConstPtr = typename Base::PointCloudConstPtr; using PointIndicesPtr = typename Base::PointIndicesPtr; using PointIndicesConstPtr = typename Base::PointIndicesConstPtr; using Base::input_; using Base::indices_; using Base::initCompute; using Base::setInputCloud; /** Updating method flag */ enum FLAG { /** keep the new basis vectors if possible */ increase, /** preserve subspace dimension */ preserve }; /** \brief Default Constructor * \param basis_only flag to compute only the PCA basis */ PCA (bool basis_only = false) : Base () , basis_only_ (basis_only) {} /** Copy Constructor * \param[in] pca PCA object */ PCA (PCA const & pca) : Base (pca) , compute_done_ (pca.compute_done_) , basis_only_ (pca.basis_only_) , eigenvectors_ (pca.eigenvectors_) , coefficients_ (pca.coefficients_) , mean_ (pca.mean_) , eigenvalues_ (pca.eigenvalues_) {} /** Assignment operator * \param[in] pca PCA object */ inline PCA& operator= (PCA const & pca) { eigenvectors_ = pca.eigenvectors_; coefficients_ = pca.coefficients_; eigenvalues_ = pca.eigenvalues_; mean_ = pca.mean_; return (*this); } /** \brief Provide a pointer to the input dataset * \param cloud the const boost shared pointer to a PointCloud message */ inline void setInputCloud (const PointCloudConstPtr &cloud) override { Base::setInputCloud (cloud); compute_done_ = false; } /** \brief Provide a pointer to the vector of indices that represents the input data. * \param[in] indices a pointer to the indices that represent the input data. */ void setIndices (const IndicesPtr &indices) override { Base::setIndices (indices); compute_done_ = false; } /** \brief Provide a pointer to the vector of indices that represents the input data. * \param[in] indices a pointer to the indices that represent the input data. */ void setIndices (const IndicesConstPtr &indices) override { Base::setIndices (indices); compute_done_ = false; } /** \brief Provide a pointer to the vector of indices that represents the input data. * \param[in] indices a pointer to the indices that represent the input data. */ void setIndices (const PointIndicesConstPtr &indices) override { Base::setIndices (indices); compute_done_ = false; } /** \brief Set the indices for the points laying within an interest region of * the point cloud. * \note you shouldn't call this method on unorganized point clouds! * \param[in] row_start the offset on rows * \param[in] col_start the offset on columns * \param[in] nb_rows the number of rows to be considered row_start included * \param[in] nb_cols the number of columns to be considered col_start included */ void setIndices (std::size_t row_start, std::size_t col_start, std::size_t nb_rows, std::size_t nb_cols) override { Base::setIndices (row_start, col_start, nb_rows, nb_cols); compute_done_ = false; } /** \brief Mean accessor * \throw InitFailedException */ inline Eigen::Vector4f& getMean () { if (!compute_done_) initCompute (); if (!compute_done_) PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::getMean] PCA initCompute failed"); return (mean_); } /** Eigen Vectors accessor * \return Column ordered eigenvectors, representing the eigenspace cartesian basis (right-handed coordinate system). * \throw InitFailedException */ inline Eigen::Matrix3f& getEigenVectors () { if (!compute_done_) initCompute (); if (!compute_done_) PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::getEigenVectors] PCA initCompute failed"); return (eigenvectors_); } /** Eigen Values accessor * \throw InitFailedException */ inline Eigen::Vector3f& getEigenValues () { if (!compute_done_) initCompute (); if (!compute_done_) PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::getEigenVectors] PCA getEigenValues failed"); return (eigenvalues_); } /** Coefficients accessor * \throw InitFailedException */ inline Eigen::MatrixXf& getCoefficients () { if (!compute_done_) initCompute (); if (!compute_done_) PCL_THROW_EXCEPTION (InitFailedException, "[pcl::PCA::getEigenVectors] PCA getCoefficients failed"); return (coefficients_); } /** update PCA with a new point * \param[in] input input point * \param[in] flag update flag * \throw InitFailedException */ inline void update (const PointT& input, FLAG flag = preserve); /** Project point on the eigenspace. * \param[in] input point from original dataset * \param[out] projection the point in eigen vectors space * \throw InitFailedException */ inline void project (const PointT& input, PointT& projection); /** Project cloud on the eigenspace. * \param[in] input cloud from original dataset * \param[out] projection the cloud in eigen vectors space * \throw InitFailedException */ inline void project (const PointCloud& input, PointCloud& projection); /** Reconstruct point from its projection * \param[in] projection point from eigenvector space * \param[out] input reconstructed point * \throw InitFailedException */ inline void reconstruct (const PointT& projection, PointT& input); /** Reconstruct cloud from its projection * \param[in] projection cloud from eigenvector space * \param[out] input reconstructed cloud * \throw InitFailedException */ inline void reconstruct (const PointCloud& projection, PointCloud& input); private: inline bool initCompute (); bool compute_done_{false}; bool basis_only_; Eigen::Matrix3f eigenvectors_; Eigen::MatrixXf coefficients_; Eigen::Vector4f mean_; Eigen::Vector3f eigenvalues_; }; // class PCA } // namespace pcl #include