├── CMakeLists.txt ├── src ├── icpPointToPoint.h ├── icpPointToPlane.h ├── icp.cpp ├── icp.h ├── demo.cpp ├── matrix.h ├── kdtree.h ├── icpPointToPoint.cpp ├── icpPointToPlane.cpp ├── kdtree.cpp └── matrix.cpp └── README.TXT /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # project 2 | cmake_minimum_required (VERSION 2.6) 3 | project (libicp) 4 | 5 | # directories 6 | set (LIBICP_SRC_DIR src) 7 | FIND_PATH(BOOST_DIR "boost") 8 | 9 | # include directory 10 | include_directories("${LIBICP_SRC_DIR}") 11 | include_directories("${BOOST_DIR}") 12 | 13 | #include directories for lasreaders 14 | 15 | include_directories("/LAStools/LASlib/inc") 16 | include_directories("/LAStools/LASzip/src") 17 | include_directories("/LAStools/LASlib/lib") 18 | 19 | 20 | # determine if OpenMP can/should be used 21 | option(USE_OPENMP "Enable OpenMP?" ON) # set to OFF to disable 22 | if(USE_OPENMP) 23 | FIND_PACKAGE(OpenMP) 24 | if(OPENMP_FOUND OR OpenMP_FOUND) 25 | message(STATUS "OpenMP flags = ${OpenMP_CXX_FLAGS}") 26 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 27 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 28 | else(OPENMP_FOUND OR OpenMP_FOUND) 29 | message(STATUS "OpenMP not supported") 30 | endif(OPENMP_FOUND OR OpenMP_FOUND) 31 | endif(USE_OPENMP) 32 | 33 | # sources 34 | FILE(GLOB LIBICP_SRC_FILES "src/*.cpp") 35 | 36 | # make release version 37 | set(CMAKE_BUILD_TYPE Release) 38 | 39 | # build demo program 40 | add_executable(icp ${LIBICP_SRC_FILES}) 41 | 42 | target_link_libraries(icp /LAStools/LASlib/lib/liblas.a) 43 | -------------------------------------------------------------------------------- /src/icpPointToPoint.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011. All rights reserved. 3 | Institute of Measurement and Control Systems 4 | Karlsruhe Institute of Technology, Germany 5 | 6 | Authors: Andreas Geiger 7 | 8 | libicp is free software; you can redistribute it and/or modify it under the 9 | terms of the GNU General Public License as published by the Free Software 10 | Foundation; either version 2 of the License, or any later version. 11 | 12 | libicp is distributed in the hope that it will be useful, but WITHOUT ANY 13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License along with 17 | libicp; if not, write to the Free Software Foundation, Inc., 51 Franklin 18 | Street, Fifth Floor, Boston, MA 02110-1301, USA 19 | */ 20 | 21 | #ifndef ICP_POINT_TO_POINT_H 22 | #define ICP_POINT_TO_POINT_H 23 | 24 | #include "icp.h" 25 | 26 | class IcpPointToPoint : public Icp { 27 | 28 | public: 29 | 30 | IcpPointToPoint (double *M,const int32_t M_num,const int32_t dim) : Icp(M,M_num,dim) {} 31 | virtual ~IcpPointToPoint () {} 32 | 33 | private: 34 | 35 | double fitStep (double *T,const int32_t T_num,Matrix &R,Matrix &t,const std::vector &active); 36 | std::vector getInliers (double *T,const int32_t T_num,const Matrix &R,const Matrix &t,const double indist); 37 | double getResidual(double *T,const int32_t T_num,const Matrix &R,const Matrix &t,const std::vector &active); 38 | }; 39 | 40 | #endif // ICP_POINT_TO_POINT_H 41 | -------------------------------------------------------------------------------- /src/icpPointToPlane.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011. All rights reserved. 3 | Institute of Measurement and Control Systems 4 | Karlsruhe Institute of Technology, Germany 5 | 6 | Authors: Andreas Geiger 7 | 8 | libicp is free software; you can redistribute it and/or modify it under the 9 | terms of the GNU General Public License as published by the Free Software 10 | Foundation; either version 2 of the License, or any later version. 11 | 12 | libicp is distributed in the hope that it will be useful, but WITHOUT ANY 13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License along with 17 | libicp; if not, write to the Free Software Foundation, Inc., 51 Franklin 18 | Street, Fifth Floor, Boston, MA 02110-1301, USA 19 | */ 20 | 21 | #ifndef ICP_POINT_TO_PLANE_H 22 | #define ICP_POINT_TO_PLANE_H 23 | 24 | #include "icp.h" 25 | 26 | class IcpPointToPlane : public Icp { 27 | 28 | public: 29 | 30 | IcpPointToPlane (double *M,const int32_t M_num,const int32_t dim,const int32_t num_neighbors=10,const double flatness=5.0) : Icp(M,M_num,dim) { 31 | M_normal = computeNormals(num_neighbors,flatness); 32 | } 33 | 34 | virtual ~IcpPointToPlane () { 35 | free(M_normal); 36 | } 37 | 38 | private: 39 | 40 | double fitStep (double *T,const int32_t T_num,Matrix &R,Matrix &t,const std::vector &active); 41 | std::vector getInliers (double *T,const int32_t T_num,const Matrix &R,const Matrix &t,const double indist); 42 | double getResidual(double *T,const int32_t T_num,const Matrix &R,const Matrix &t,const std::vector &active); 43 | // utility functions to compute normals from the model tree 44 | void computeNormal (const kdtree::KDTreeResultVector &neighbors,double *M_normal,const double flatness); 45 | double* computeNormals (const int32_t num_neighbors,const double flatness); 46 | 47 | // normals of model points 48 | double *M_normal; 49 | }; 50 | 51 | #endif // ICP_POINT_TO_PLANE_H 52 | -------------------------------------------------------------------------------- /src/icp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011. All rights reserved. 3 | Institute of Measurement and Control Systems 4 | Karlsruhe Institute of Technology, Germany 5 | 6 | Authors: Andreas Geiger 7 | 8 | libicp is free software; you can redistribute it and/or modify it under the 9 | terms of the GNU General Public License as published by the Free Software 10 | Foundation; either version 2 of the License, or any later version. 11 | 12 | libicp is distributed in the hope that it will be useful, but WITHOUT ANY 13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License along with 17 | libicp; if not, write to the Free Software Foundation, Inc., 51 Franklin 18 | Street, Fifth Floor, Boston, MA 02110-1301, USA 19 | */ 20 | 21 | #include "icp.h" 22 | using namespace std; 23 | 24 | Icp::Icp (double *M,const int32_t M_num,const int32_t dim) 25 | :m_dim(dim), m_max_iter(200), m_min_delta(1e-4) 26 | { 27 | 28 | // check for correct dimensionality 29 | if (dim!=2 && dim!=3) { 30 | cout << "ERROR: LIBICP works only for data of dimensionality 2 or 3" << endl; 31 | m_kd_tree = 0; 32 | return; 33 | } 34 | // check for minimum number of points 35 | if (M_num<5) { 36 | cout << "ERROR: LIBICP works only with at least 5 model points" << endl; 37 | m_kd_tree = 0; 38 | return; 39 | } 40 | 41 | // copy model points to M_data 42 | m_kd_data.resize(boost::extents[M_num][dim]); 43 | for (int32_t m=0; m active; 72 | if (indist<=0) { 73 | active.clear(); 74 | for (int32_t i=0; im_min_delta; iter++){ 98 | if(indist>0){ 99 | indist = std::max(indist*0.9,0.05); 100 | m_active = getInliers(T,T_num,R,t,indist); 101 | m_inlier_ratio = (double)m_active.size()/T_num; 102 | } 103 | delta=fitStep(T,T_num,R,t,m_active); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/icp.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011. All rights reserved. 3 | Institute of Measurement and Control Systems 4 | Karlsruhe Institute of Technology, Germany 5 | 6 | Authors: Andreas Geiger 7 | 8 | libicp is free software; you can redistribute it and/or modify it under the 9 | terms of the GNU General Public License as published by the Free Software 10 | Foundation; either version 2 of the License, or any later version. 11 | 12 | libicp is distributed in the hope that it will be useful, but WITHOUT ANY 13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License along with 17 | libicp; if not, write to the Free Software Foundation, Inc., 51 Franklin 18 | Street, Fifth Floor, Boston, MA 02110-1301, USA 19 | */ 20 | 21 | #ifndef ICP_H 22 | #define ICP_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "matrix.h" 31 | #include "kdtree.h" 32 | 33 | class Icp { 34 | 35 | public: 36 | 37 | // constructor 38 | // input: M ....... pointer to first model point 39 | // M_num ... number of model points 40 | // dim ... dimensionality of model points (2 or 3) 41 | Icp (double *M,const int32_t M_num,const int32_t dim); 42 | 43 | // deconstructor 44 | virtual ~Icp (); 45 | 46 | // set maximum number of iterations (1. stopping criterion) 47 | void setMaxIterations (int32_t val) { m_max_iter = val; } 48 | 49 | // set minimum delta of rot/trans parameters (2. stopping criterion) 50 | void setMinDeltaParam (double val) { m_min_delta = val; } 51 | 52 | double getInlierRatio(){ 53 | return m_inlier_ratio; 54 | } 55 | 56 | double getInlierCount(){ 57 | return m_active.size(); 58 | } 59 | 60 | // fit template to model yielding R,t (M = R*T + t) 61 | // input: T ....... pointer to first template point 62 | // T_num ... number of template points 63 | // R ....... initial rotation matrix 64 | // t ....... initial translation vector 65 | // indist .. inlier distance (if <=0: use all points) 66 | // output: R ....... final rotation matrix 67 | // t ....... final translation vector 68 | double fit(double *T,const int32_t T_num,Matrix &R,Matrix &t,double indist=-1); 69 | 70 | 71 | private: 72 | // iterative fitting 73 | void fitIterate(double *T,const int32_t T_num,Matrix &R,Matrix &t, double indist = -1); 74 | 75 | // inherited classes need to overwrite these functions 76 | virtual double fitStep(double *T,const int32_t T_num,Matrix &R,Matrix &t,const std::vector &active) = 0; 77 | virtual std::vector getInliers(double *T,const int32_t T_num,const Matrix &R,const Matrix &t,const double indist) = 0; 78 | 79 | virtual double getResidual(double *T,const int32_t T_num,const Matrix &R,const Matrix &t,const std::vector &active)=0; 80 | 81 | protected: 82 | 83 | // kd tree of model points 84 | kdtree::KDTree* m_kd_tree; 85 | kdtree::KDTreeArray m_kd_data; 86 | 87 | int32_t m_dim; // dimensionality of model + template data (2 or 3) 88 | int32_t m_max_iter; // max number of iterations 89 | double m_min_delta; // min parameter delta 90 | 91 | std::vector m_active; //inliers 92 | 93 | double m_inlier_ratio; // active.size()/ T_num 94 | double m_residual; // residual of icp 95 | Matrix m_covariance; // covariance of the result 96 | }; 97 | 98 | #endif // ICP_H 99 | -------------------------------------------------------------------------------- /src/demo.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011. All rights reserved. 3 | Institute of Measurement and Control Systems 4 | Karlsruhe Institute of Technology, Germany 5 | 6 | This file is part of libicp. 7 | Authors: Andreas Geiger 8 | Updated by Chelsea Scott 9 | 10 | libicp is free software; you can redistribute it and/or modify it under the 11 | terms of the GNU General Public License as published by the Free Software 12 | Foundation; either version 3 of the License, or any later version. 13 | 14 | libicp is distributed in the hope that it will be useful, but WITHOUT ANY 15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along with 19 | libicp; if not, write to the Free Software Foundation, Inc., 51 Franklin 20 | Street, Fifth Floor, Boston, MA 02110-1301, USA 21 | */ 22 | 23 | // Demo program showing how libicp can be used 24 | 25 | #include 26 | #include "icpPointToPlane.h" 27 | #include 28 | #include 29 | #include // std::ifstream 30 | #include // std::cout 31 | #include // printf/scanf family 32 | #include "lasreader.hpp" 33 | #include 34 | #include 35 | 36 | using namespace std; 37 | 38 | int main (int argc, char** argv) { 39 | 40 | if (argc != 3) { 41 | printf("enter 3 arguments only eg. icp input_filename output_filename\n"); 42 | return 0; 43 | } 44 | 45 | char* inputFileName = argv[1]; 46 | char* outputFileName = argv[2]; 47 | 48 | //output file is disp.txt 49 | //FILE* outfile = fopen("disp.txt","w"); 50 | FILE* outfile = fopen(outputFileName,"w"); 51 | 52 | //tiles.txt contains the coordinates of the core points 53 | //FILE* myfile = fopen("tiles.txt","r"); 54 | FILE* myfile = fopen(inputFileName,"r"); 55 | int x, y; 56 | 57 | //loop through tile.txt 58 | while (fscanf(myfile, "%d %d", &x,&y)==2){ 59 | 60 | // write name of compare and reference tile to read 61 | char compare_file[50]; 62 | char reference_file[50]; 63 | snprintf(compare_file, 50,"las_diff/compare_%d_%d.las",x,y); 64 | snprintf(reference_file,50,"las_diff/reference_%d_%d.las",x,y); 65 | 66 | //read the compare tile 67 | LASreadOpener lasreadopener; 68 | lasreadopener.set_file_name(compare_file); 69 | LASreader* lasreader=lasreadopener.open(); 70 | 71 | int npts = lasreader->npoints; 72 | double* M = (double*)malloc(npts*3*sizeof(double)); 73 | int numM = npts; 74 | 75 | LASpoint* p; 76 | int i=0; 77 | 78 | while (lasreader -> read_point()) { 79 | p = &lasreader->point; 80 | M[i] = p->get_x(); 81 | M[i+1] = p->get_y(); 82 | M[i+2] = p->get_z(); 83 | i += 3; 84 | } 85 | 86 | lasreader->close(); 87 | delete lasreader; 88 | 89 | //read the reference file 90 | LASreadOpener nreadopener; 91 | nreadopener.set_file_name(reference_file); 92 | LASreader* nreader = nreadopener.open(); 93 | npts=nreader->npoints; 94 | int numN = npts; 95 | 96 | double* N = (double*)malloc(npts*3*sizeof(double)); 97 | i=0; 98 | while (nreader->read_point()){ 99 | p= &nreader->point; 100 | N[i] = p-> get_x(); 101 | N[i+1] = p->get_y(); 102 | N[i+2] = p->get_z(); 103 | i += 3; 104 | } 105 | 106 | nreader->close(); 107 | delete nreader; 108 | 109 | // find the mean (x,y,z) of the compare dataset. 110 | double sum1=0; 111 | double sum2=0; 112 | double sum3=0; 113 | 114 | for (int k=0; k 50 && numM > 50) { 147 | IcpPointToPlane icp(N,numN,3); 148 | double residual = icp.fit(M,numM,R,t,-1); 149 | 150 | // write the output file 151 | fprintf(outfile, "%d %d %f %f %f %f %f %f %f %f %f %f %f %f\n",x,y, t.val[0][0], t.val[1][0], t.val[2][0], R.val[0][0], R.val[0][1], R.val[0][2], R.val[1][0], R.val[1][1], R.val[1][2], R.val[2][0], R.val[2][1], R.val[2][2] ); 152 | } 153 | // free memory 154 | free(M); 155 | free(N); 156 | } 157 | fclose(outfile); 158 | fclose(myfile); 159 | // success 160 | return 0; 161 | } 162 | -------------------------------------------------------------------------------- /README.TXT: -------------------------------------------------------------------------------- 1 | #################################################################################### 2 | # Copyright 2011. All rights reserved. # 3 | # Institute of Measurement and Control Systems # 4 | # Karlsruhe Institute of Technology, Germany # 5 | # # 6 | # This file is part of libicp. # 7 | # Authors: Andreas Geiger # 8 | # Please send any bugreports to geiger@kit.edu 9 | # LASReaders Update: Chelsea Scott - cpscott1@asu.edu 10 | # # 11 | # libicp is free software; you can redistribute it and/or modify it under the # 12 | # terms of the GNU General Public License as published by the Free Software # 13 | # Foundation; either version 3 of the License, or any later version. # 14 | # # 15 | # libicp is distributed in the hope that it will be useful, but WITHOUT ANY # 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A # 17 | # PARTICULAR PURPOSE. See the GNU General Public License for more details. # 18 | # # 19 | # You should have received a copy of the GNU General Public License along with # 20 | # libicp; if not, write to the Free Software Foundation, Inc., 51 Franklin # 21 | # Street, Fifth Floor, Boston, MA 02110-1301, USA # 22 | #################################################################################### 23 | 24 | +++++++++++++++++++++++++++++++++++ 25 | + INTRODUCTION + 26 | +++++++++++++++++++++++++++++++++++ 27 | 28 | Libicp (LIBrary for Iterative Closest Point fitting) is a cross-platfrom C++ 29 | library with MATLAB wrappers for fitting 2d or 3d point clouds with respect to 30 | each other. Currently it implements the SVD-based point-to-point algorithm as well 31 | as the linearized point-to-plane algorithm. It also supports outlier rejection 32 | and is accelerated by the use of kd trees as well as a coarse matching stage 33 | using only a subset of all points. 34 | 35 | If you distribute a software that uses libicp, you have to distribute it under GPL 36 | with the source code. 37 | 38 | +++++++++++++++++++++++++++++++++++ 39 | + COMPILING MATLAB WRAPPERS + 40 | +++++++++++++++++++++++++++++++++++ 41 | 42 | If you want to use libicp directly from MATLAB you can easily do this by using 43 | the MATLAB wrappers provided. They also include some demo files for testing your 44 | configuration. First, configure your MATLAB MEX C++ compiler, if it is not yet 45 | configured (mex -setup). Under Linux you might use g++, under Windows I compiled 46 | it successfully with the Microsoft Visual Studio Express 2008 compilers. 47 | 48 | 1) Change to the libicp/matlab directory 49 | 2) After running 'make.m' you should have a MEX file called 'icpMex' 50 | 3) Now try to run 'demo_2d.m' or 'demo_3d.m' 51 | 52 | +++++++++++++++++++++++++++++++++++ 53 | + BUILDING A C++ LIBRARY + 54 | +++++++++++++++++++++++++++++++++++ 55 | 56 | Prerequisites needed for compiling libicp using c++: 57 | - CMake (available at: http://www.cmake.org/) 58 | - Boost (available at: http://www.boost.org/) 59 | 60 | Note: 61 | 62 | Please make sure that the boost headers can be found! 63 | (Add /usr/local/include to your include path if you have 64 | installed them locally) 65 | 66 | Linux: 67 | 68 | 1) Move to libicp root directory 69 | 2) Type 'cmake .' 70 | 3) Type 'make' 71 | 4) Run './icp' (demo program) 72 | 73 | Windows: 74 | 75 | 1) Start CMake GUI 76 | 2) Set directories to libicp root directory 77 | 3) Run configure, configure and generate 78 | 4) Open the resulting Visual Studio solution with Visual Studio 79 | 5) Switch to 'Release' mode, build all and run the demo program 80 | 81 | For more information on CMake, have a look at the CMake documentation. 82 | 83 | For more information on the usage of the library, have a look into the MATLAB wrappers and 84 | into the documentation of the header file icp.h. 85 | 86 | Please send any feedback and bugreports to geiger@kit.edu 87 | Andreas Geiger 88 | 89 | The demo.cpp script was edited to conduct windowed ICP 3D differencing for this manuscript to Geosphere: 90 | 91 | Scott, C., Phan, M., Nandigam, V., Crosby, C., and Arrowsmith, J R., 2021, Measuring change at Earth’s surface: On-demand vertical and threedimensional topographic differencing implemented in OpenTopography: Geosphere, v. 17, no. 4, p. 1318–1332, https://doi.org/10.1130/GES02259.1 92 | 93 | Chelsea Scott: cpscott1@asu.edu(corresponding author) 94 | Minh Phan, Viswanath Nandigam, Christopher Crosby, Ramon Arrowsmith 95 | 96 | To set up to run this script: 97 | The following directory and txt file must be created. 98 | Create tiled point cloud files of the pre- and post- event data: 99 | 100 | For the compare (pre-event): 101 | las_diff/compare_x1_y1.las 102 | las_diff/compare_x2_y2.las 103 | ... 104 | 105 | For the reference (post-event): 106 | las_diff/ref_x1_y1.las 107 | las_diff/ref_x2_y2.las 108 | ... 109 | 110 | tiles.txt in the libicp-master directory 111 | tiles.txt 112 | x1 y1 113 | x2 y2 114 | ... 115 | 116 | This will output a disp.txt which has the results of the 3D differencing. 117 | -------------------------------------------------------------------------------- /src/matrix.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011. All rights reserved. 3 | Institute of Measurement and Control Systems 4 | Karlsruhe Institute of Technology, Germany 5 | 6 | Authors: Andreas Geiger 7 | 8 | matrix is free software; you can redistribute it and/or modify it under the 9 | terms of the GNU General Public License as published by the Free Software 10 | Foundation; either version 2 of the License, or any later version. 11 | 12 | matrix is distributed in the hope that it will be useful, but WITHOUT ANY 13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License along with 17 | matrix; if not, write to the Free Software Foundation, Inc., 51 Franklin 18 | Street, Fifth Floor, Boston, MA 02110-1301, USA 19 | */ 20 | 21 | #ifndef MATRIX_H 22 | #define MATRIX_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifndef _MSC_VER 31 | #include 32 | #else 33 | typedef signed __int8 int8_t; 34 | typedef signed __int16 int16_t; 35 | typedef signed __int32 int32_t; 36 | typedef signed __int64 int64_t; 37 | typedef unsigned __int8 uint8_t; 38 | typedef unsigned __int16 uint16_t; 39 | typedef unsigned __int32 uint32_t; 40 | typedef unsigned __int64 uint64_t; 41 | #endif 42 | 43 | #define endll endl << endl // double end line definition 44 | 45 | typedef double FLOAT; // double precision 46 | //typedef float FLOAT; // single precision 47 | 48 | class Matrix { 49 | 50 | public: 51 | 52 | // constructor / deconstructor 53 | Matrix (); // init empty 0x0 matrix 54 | Matrix (const int32_t m,const int32_t n); // init empty mxn matrix 55 | Matrix (const int32_t m,const int32_t n,const FLOAT* val_); // init mxn matrix with values from array 'val' 56 | Matrix (const Matrix &M); // creates deepcopy of M 57 | ~Matrix (); 58 | 59 | // assignment operator, copies contents of M 60 | Matrix& operator= (const Matrix &M); 61 | 62 | // copies submatrix of M into array 'val', default values copy whole row/column/matrix 63 | void getData(FLOAT* val_,int32_t i1=0,int32_t j1=0,int32_t i2=-1,int32_t j2=-1); 64 | 65 | // set or get submatrices of current matrix 66 | Matrix getMat(int32_t i1,int32_t j1,int32_t i2=-1,int32_t j2=-1); 67 | void setMat(const Matrix &M,const int32_t i,const int32_t j); 68 | 69 | // set sub-matrix to scalar (default 0), -1 as end replaces whole row/column/matrix 70 | void setVal(FLOAT s,int32_t i1=0,int32_t j1=0,int32_t i2=-1,int32_t j2=-1); 71 | 72 | // set (part of) diagonal to scalar, -1 as end replaces whole diagonal 73 | void setDiag(FLOAT s,int32_t i1=0,int32_t i2=-1); 74 | 75 | // clear matrix 76 | void zero(); 77 | 78 | // extract columns with given index 79 | Matrix extractCols (std::vector idx); 80 | 81 | // create identity matrix 82 | static Matrix eye (const int32_t m); 83 | void eye (); 84 | 85 | // create matrix with ones 86 | static Matrix ones(const int32_t m,const int32_t n); 87 | 88 | // create diagonal matrix with nx1 or 1xn matrix M as elements 89 | static Matrix diag(const Matrix &M); 90 | 91 | // returns the m-by-n matrix whose elements are taken column-wise from M 92 | static Matrix reshape(const Matrix &M,int32_t m,int32_t n); 93 | 94 | // create 3x3 rotation matrices (convention: http://en.wikipedia.org/wiki/Rotation_matrix) 95 | static Matrix rotMatX(const FLOAT &angle); 96 | static Matrix rotMatY(const FLOAT &angle); 97 | static Matrix rotMatZ(const FLOAT &angle); 98 | 99 | // simple arithmetic operations 100 | Matrix operator+ (const Matrix &M); // add matrix 101 | Matrix operator- (const Matrix &M); // subtract matrix 102 | Matrix operator* (const Matrix &M); // multiply with matrix 103 | Matrix operator* (const FLOAT &s); // multiply with scalar 104 | Matrix operator/ (const Matrix &M); // divide elementwise by matrix (or vector) 105 | Matrix operator/ (const FLOAT &s); // divide by scalar 106 | Matrix operator- (); // negative matrix 107 | Matrix operator~ (); // transpose 108 | FLOAT l2norm (); // euclidean norm (vectors) / frobenius norm (matrices) 109 | FLOAT mean (); // mean of all elements in matrix 110 | 111 | // complex arithmetic operations 112 | static Matrix cross (const Matrix &a, const Matrix &b); // cross product of two vectors 113 | static Matrix inv (const Matrix &M); // invert matrix M 114 | bool inv (); // invert this matrix 115 | FLOAT det (); // returns determinant of matrix 116 | bool solve (const Matrix &M,FLOAT eps=1e-20); // solve linear system M*x=B, replaces *this and M 117 | bool lu(int32_t *idx, FLOAT &d, FLOAT eps=1e-20); // replace *this by lower upper decomposition 118 | void svd(Matrix &U,Matrix &W,Matrix &V); // singular value decomposition *this = U*diag(W)*V^T 119 | 120 | // print matrix to stream 121 | friend std::ostream& operator<< (std::ostream& out,const Matrix& M); 122 | 123 | // direct data access 124 | FLOAT **val; 125 | int32_t m,n; 126 | 127 | private: 128 | 129 | void allocateMemory (const int32_t m_,const int32_t n_); 130 | void releaseMemory (); 131 | inline FLOAT pythag(FLOAT a,FLOAT b); 132 | 133 | }; 134 | 135 | #endif // MATRIX_H 136 | -------------------------------------------------------------------------------- /src/kdtree.h: -------------------------------------------------------------------------------- 1 | #ifndef __KDTREE_HPP 2 | #define __KDTREE_HPP 3 | 4 | // (c) Matthew B. Kennel, Institute for Nonlinear Science, UCSD (2004) 5 | // 6 | // Licensed under the Academic Free License version 1.1 found in file LICENSE 7 | // with additional provisions in that same file. 8 | // 9 | // Implement a kd tree for fast searching of points in a fixed data base 10 | // in k-dimensional Euclidean space. 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | namespace kdtree { 19 | 20 | typedef boost::multi_array KDTreeArray; 21 | typedef boost::const_multi_array_ref KDTreeROArray; 22 | 23 | typedef struct { 24 | float lower, upper; 25 | } interval; 26 | 27 | // let the compiler know that this is a names of classes. 28 | class KDTreeNode; 29 | class SearchRecord; 30 | 31 | struct KDTreeResult { 32 | public: 33 | float dis; // square distance 34 | int idx; // neighbor index 35 | }; 36 | 37 | class KDTreeResultVector : public std::vector { 38 | // inherit a std::vector 39 | // but, optionally maintain it in heap form as a priority 40 | // queue. 41 | public: 42 | 43 | // 44 | // add one new element to the list of results, and 45 | // keep it in heap order. To keep it in ordinary, as inserted, 46 | // order, then simply use push_back() as inherited 47 | // via std::vector<> 48 | 49 | void push_element_and_heapify(KDTreeResult&); 50 | float replace_maxpri_elt_return_new_maxpri(KDTreeResult&); 51 | 52 | float max_value(); 53 | // return the distance which has the maximum value of all on list, 54 | // assuming that ALL insertions were made by 55 | // push_element_and_heapify() 56 | }; 57 | 58 | class KDTree { 59 | public: 60 | const KDTreeArray& the_data; 61 | // "the_data" is a reference to the underlying multi_array of the 62 | // data to be included in the tree. 63 | // 64 | // NOTE: this structure does *NOT* own the storage underlying this. 65 | // Hence, it would be a very bad idea to change the underlying data 66 | // during use of the search facilities of this tree. 67 | // Also, the user must deallocate the memory underlying it. 68 | 69 | 70 | const int N; // number of data points 71 | int dim; 72 | bool sort_results; // sorting result? 73 | const bool rearrange; // are we rearranging? 74 | 75 | public: 76 | 77 | // constructor, has optional 'dim_in' feature, to use only 78 | // first 'dim_in' components for definition of nearest neighbors. 79 | KDTree(KDTreeArray& data_in, bool rearrange_in = true, int dim_in=-1); 80 | 81 | // destructor 82 | ~KDTree(); 83 | 84 | 85 | public: 86 | 87 | void n_nearest_brute_force(std::vector& qv, int nn, KDTreeResultVector& result); 88 | // search for n nearest to a given query vector 'qv' usin 89 | // exhaustive slow search. For debugging, usually. 90 | 91 | void n_nearest(std::vector& qv, int nn, KDTreeResultVector& result); 92 | // search for n nearest to a given query vector 'qv'. 93 | 94 | void n_nearest_around_point(int idxin, int correltime, int nn, 95 | KDTreeResultVector& result); 96 | // search for 'nn' nearest to point [idxin] of the input data, excluding 97 | // neighbors within correltime 98 | 99 | void r_nearest(std::vector& qv, float r2, KDTreeResultVector& result); 100 | // search for all neighbors in ball of size (square Euclidean distance) 101 | // r2. Return number of neighbors in 'result.size()', 102 | 103 | void r_nearest_around_point(int idxin, int correltime, float r2, 104 | KDTreeResultVector& result); 105 | // like 'r_nearest', but around existing point, with decorrelation 106 | // interval. 107 | 108 | int r_count(std::vector& qv, float r2); 109 | // count number of neighbors within square distance r2. 110 | 111 | int r_count_around_point(int idxin, int correltime, float r2); 112 | // like r_count, c 113 | 114 | friend class KDTreeNode; 115 | friend class SearchRecord; 116 | 117 | private: 118 | 119 | KDTreeNode* root; // the root pointer 120 | 121 | const KDTreeArray* data; 122 | // pointing either to the_data or an internal 123 | // rearranged data as necessary 124 | 125 | std::vector ind; 126 | // the index for the tree leaves. Data in a leaf with bounds [l,u] are 127 | // in 'the_data[ind[l],*] to the_data[ind[u],*] 128 | 129 | KDTreeArray rearranged_data; 130 | // if rearrange is true then this is the rearranged data storage. 131 | 132 | static const int bucketsize = 12; // global constant. 133 | 134 | private: 135 | void set_data(KDTreeArray& din); 136 | void build_tree(); // builds the tree. Used upon construction. 137 | KDTreeNode* build_tree_for_range(int l, int u, KDTreeNode* parent); 138 | void select_on_coordinate(int c, int k, int l, int u); 139 | int select_on_coordinate_value(int c, float alpha, int l, int u); 140 | void spread_in_coordinate(int c, int l, int u, interval& interv); 141 | }; 142 | 143 | class KDTreeNode { 144 | public: 145 | KDTreeNode(int dim); 146 | ~KDTreeNode(); 147 | 148 | private: 149 | // visible to self and KDTree. 150 | friend class KDTree; // allow kdtree to access private data 151 | 152 | int cut_dim; // dimension to cut; 153 | float cut_val, cut_val_left, cut_val_right; //cut value 154 | int l, u; // extents in index array for searching 155 | 156 | std::vector box; // [min,max] of the box enclosing all points 157 | 158 | KDTreeNode *left, *right; // pointers to left and right nodes. 159 | 160 | void search(SearchRecord& sr); 161 | // recursive innermost core routine for searching.. 162 | 163 | bool box_in_search_range(SearchRecord& sr); 164 | // return true if the bounding box for this node is within the 165 | // search range given by the searchvector and maximum ballsize in 'sr'. 166 | 167 | void check_query_in_bound(SearchRecord& sr); // debugging only 168 | 169 | // for processing final buckets. 170 | void process_terminal_node(SearchRecord& sr); 171 | void process_terminal_node_fixedball(SearchRecord& sr); 172 | }; 173 | 174 | } // namespace kdtree 175 | 176 | #endif 177 | -------------------------------------------------------------------------------- /src/icpPointToPoint.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011. All rights reserved. 3 | Institute of Measurement and Control Systems 4 | Karlsruhe Institute of Technology, Germany 5 | 6 | Authors: Andreas Geiger 7 | 8 | openMP support by Manolis Lourakis, Foundation for Research & Technology - Hellas, Heraklion, Greece 9 | 10 | libicp is free software; you can redistribute it and/or modify it under the 11 | terms of the GNU General Public License as published by the Free Software 12 | Foundation; either version 2 of the License, or any later version. 13 | 14 | libicp is distributed in the hope that it will be useful, but WITHOUT ANY 15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along with 19 | libicp; if not, write to the Free Software Foundation, Inc., 51 Franklin 20 | Street, Fifth Floor, Boston, MA 02110-1301, USA 21 | */ 22 | 23 | #ifdef _OPENMP 24 | #include 25 | #endif 26 | 27 | #include "icpPointToPoint.h" 28 | 29 | using namespace std; 30 | 31 | // Also see (3d part): "Least-Squares Fitting of Two 3-D Point Sets" (Arun, Huang and Blostein) 32 | double IcpPointToPoint::fitStep (double *T,const int32_t T_num,Matrix &R,Matrix &t,const std::vector &active) { 33 | 34 | int i; 35 | int nact = (int)active.size(); 36 | 37 | // init matrix for point correspondences 38 | Matrix p_m(nact,m_dim); // model 39 | Matrix p_t(nact,m_dim); // template 40 | 41 | // init mean 42 | Matrix mu_m(1,m_dim); 43 | Matrix mu_t(1,m_dim); 44 | 45 | // dimensionality 2 46 | if (m_dim==2) { 47 | 48 | // extract matrix and translation vector 49 | double r00 = R.val[0][0]; double r01 = R.val[0][1]; 50 | double r10 = R.val[1][0]; double r11 = R.val[1][1]; 51 | double t0 = t.val[0][0]; double t1 = t.val[1][0]; 52 | double mum0 = 0.0, mum1 = 0.0; 53 | double mut0 = 0.0, mut1 = 0.0; 54 | 55 | // establish correspondences 56 | #pragma omp parallel for private(i) default(none) shared(T,active,nact,p_m,p_t,r00,r01,r10,r11,t0,t1) reduction(+:mum0,mum1, mut0,mut1) // schedule (dynamic,2) 57 | for (i=0; i query(m_dim); 60 | kdtree::KDTreeResultVector result; 61 | 62 | // get index of active point 63 | int32_t idx = active[i]; 64 | 65 | // transform point according to R|t 66 | query[0] = (float)(r00*T[idx*2+0] + r01*T[idx*2+1] + t0); 67 | query[1] = (float)(r10*T[idx*2+0] + r11*T[idx*2+1] + t1); 68 | 69 | // search nearest neighbor 70 | m_kd_tree->n_nearest(query,1,result); 71 | 72 | // set model point 73 | p_m.val[i][0] = m_kd_tree->the_data[result[0].idx][0]; mum0 += p_m.val[i][0]; 74 | p_m.val[i][1] = m_kd_tree->the_data[result[0].idx][1]; mum1 += p_m.val[i][1]; 75 | 76 | // set template point 77 | p_t.val[i][0] = query[0]; mut0 += p_t.val[i][0]; 78 | p_t.val[i][1] = query[1]; mut1 += p_t.val[i][1]; 79 | } 80 | mu_m.val[0][0] = mum0; 81 | mu_m.val[0][1] = mum1; 82 | 83 | mu_t.val[0][0] = mut0; 84 | mu_t.val[0][1] = mut1; 85 | 86 | // dimensionality 3 87 | } else { 88 | 89 | // extract matrix and translation vector 90 | double r00 = R.val[0][0]; double r01 = R.val[0][1]; double r02 = R.val[0][2]; 91 | double r10 = R.val[1][0]; double r11 = R.val[1][1]; double r12 = R.val[1][2]; 92 | double r20 = R.val[2][0]; double r21 = R.val[2][1]; double r22 = R.val[2][2]; 93 | double t0 = t.val[0][0]; double t1 = t.val[1][0]; double t2 = t.val[2][0]; 94 | double mum0 = 0.0, mum1 = 0.0, mum2 = 0.0; 95 | double mut0 = 0.0, mut1 = 0.0, mut2 = 0.0; 96 | 97 | // establish correspondences 98 | #pragma omp parallel for private(i) default(none) shared(T,active,nact,p_m,p_t,r00,r01,r02,r10,r11,r12,r20,r21,r22,t0,t1,t2) reduction(+:mum0,mum1,mum2, mut0,mut1,mut2) // schedule (dynamic,2) 99 | for (i=0; i query(m_dim); 102 | kdtree::KDTreeResultVector result; 103 | 104 | // get index of active point 105 | int32_t idx = active[i]; 106 | 107 | // transform point according to R|t 108 | query[0] = (float)(r00*T[idx*3+0] + r01*T[idx*3+1] + r02*T[idx*3+2] + t0); 109 | query[1] = (float)(r10*T[idx*3+0] + r11*T[idx*3+1] + r12*T[idx*3+2] + t1); 110 | query[2] = (float)(r20*T[idx*3+0] + r21*T[idx*3+1] + r22*T[idx*3+2] + t2); 111 | 112 | // search nearest neighbor 113 | m_kd_tree->n_nearest(query,1,result); 114 | 115 | // set model point 116 | p_m.val[i][0] = m_kd_tree->the_data[result[0].idx][0]; mum0 += p_m.val[i][0]; 117 | p_m.val[i][1] = m_kd_tree->the_data[result[0].idx][1]; mum1 += p_m.val[i][1]; 118 | p_m.val[i][2] = m_kd_tree->the_data[result[0].idx][2]; mum2 += p_m.val[i][2]; 119 | 120 | // set template point 121 | p_t.val[i][0] = query[0]; mut0 += p_t.val[i][0]; 122 | p_t.val[i][1] = query[1]; mut1 += p_t.val[i][1]; 123 | p_t.val[i][2] = query[2]; mut2 += p_t.val[i][2]; 124 | } 125 | mu_m.val[0][0] = mum0; 126 | mu_m.val[0][1] = mum1; 127 | mu_m.val[0][2] = mum2; 128 | 129 | mu_t.val[0][0] = mut0; 130 | mu_t.val[0][1] = mut1; 131 | mu_t.val[0][2] = mut2; 132 | } 133 | 134 | // subtract mean 135 | mu_m = mu_m/(double)active.size(); 136 | mu_t = mu_t/(double)active.size(); 137 | Matrix q_m = p_m - Matrix::ones(active.size(),1)*mu_m; 138 | Matrix q_t = p_t - Matrix::ones(active.size(),1)*mu_t; 139 | 140 | // compute relative rotation matrix R and translation vector t 141 | Matrix H = ~q_t*q_m; 142 | Matrix U,W,V; 143 | H.svd(U,W,V); 144 | Matrix R_ = V*~U; 145 | 146 | // fix improper matrix problem 147 | if (R_.det()<0){ 148 | Matrix B = Matrix::eye(m_dim); 149 | B.val[m_dim-1][m_dim-1] = R_.det(); 150 | R_ = V*B*~U; 151 | } 152 | 153 | Matrix t_ = ~mu_m - R_*~mu_t; 154 | 155 | // compose: R|t = R_|t_ * R|t 156 | R = R_*R; 157 | t = R_*t+t_; 158 | 159 | // return max delta in parameters 160 | if (m_dim==2) return max((R_-Matrix::eye(2)).l2norm(),t_.l2norm()); 161 | else return max((R_-Matrix::eye(3)).l2norm(),t_.l2norm()); 162 | } 163 | 164 | std::vector IcpPointToPoint::getInliers (double *T,const int32_t T_num,const Matrix &R,const Matrix &t,const double indist) { 165 | 166 | // init inlier vector + query point + query result 167 | vector inliers; 168 | std::vector query(m_dim); 169 | kdtree::KDTreeResultVector neighbor; 170 | 171 | // dimensionality 2 172 | if (m_dim==2) { 173 | 174 | // extract matrix and translation vector 175 | double r00 = R.val[0][0]; double r01 = R.val[0][1]; 176 | double r10 = R.val[1][0]; double r11 = R.val[1][1]; 177 | double t0 = t.val[0][0]; double t1 = t.val[1][0]; 178 | 179 | // check for all points if they are inliers 180 | for (int32_t i=0; in_nearest(query,1,neighbor); 188 | 189 | // check if it is an inlier 190 | if (neighbor[0].disn_nearest(query,1,neighbor); 213 | 214 | // check if it is an inlier 215 | if (neighbor[0].dis &active ) 225 | { 226 | if(active.empty()) return 0; 227 | int nact = active.size(); 228 | double residual = 0; 229 | 230 | if (m_dim==2) { 231 | // extract matrix and translation vector 232 | double r00 = R.val[0][0]; double r01 = R.val[0][1]; 233 | double r10 = R.val[1][0]; double r11 = R.val[1][1]; 234 | double t0 = t.val[0][0]; double t1 = t.val[1][0]; 235 | for (int i=0; i query(m_dim); 238 | kdtree::KDTreeResultVector result; 239 | 240 | // get index of active point 241 | int32_t idx = active[i]; 242 | 243 | // transform point according to R|t 244 | query[0] = (float)(r00*T[idx*2+0] + r01*T[idx*2+1] + t0); 245 | query[1] = (float)(r10*T[idx*2+0] + r11*T[idx*2+1] + t1); 246 | 247 | // search nearest neighbor 248 | m_kd_tree->n_nearest(query,1,result); 249 | residual += result[0].dis; 250 | } 251 | // dimensionality 3 252 | } else { 253 | // extract matrix and translation vector 254 | double r00 = R.val[0][0]; double r01 = R.val[0][1]; double r02 = R.val[0][2]; 255 | double r10 = R.val[1][0]; double r11 = R.val[1][1]; double r12 = R.val[1][2]; 256 | double r20 = R.val[2][0]; double r21 = R.val[2][1]; double r22 = R.val[2][2]; 257 | double t0 = t.val[0][0]; double t1 = t.val[1][0]; double t2 = t.val[2][0]; 258 | for (int i=0; i query(m_dim); 261 | kdtree::KDTreeResultVector result; 262 | // get index of active point 263 | int32_t idx = active[i]; 264 | // transform point according to R|t 265 | query[0] = (float)(r00*T[idx*3+0] + r01*T[idx*3+1] + r02*T[idx*3+2] + t0); 266 | query[1] = (float)(r10*T[idx*3+0] + r11*T[idx*3+1] + r12*T[idx*3+2] + t1); 267 | query[2] = (float)(r20*T[idx*3+0] + r21*T[idx*3+1] + r22*T[idx*3+2] + t2); 268 | // search nearest neighbor 269 | m_kd_tree->n_nearest(query,1,result); 270 | residual += result[0].dis; 271 | } 272 | } 273 | residual /= nact; 274 | return residual; 275 | } 276 | -------------------------------------------------------------------------------- /src/icpPointToPlane.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2011. All rights reserved. 3 | Institute of Measurement and Control Systems 4 | Karlsruhe Institute of Technology, Germany 5 | 6 | Authors: Andreas Geiger 7 | 8 | openMP support by Manolis Lourakis, Foundation for Research & Technology - Hellas, Heraklion, Greece 9 | 10 | libicp is free software; you can redistribute it and/or modify it under the 11 | terms of the GNU General Public License as published by the Free Software 12 | Foundation; either version 2 of the License, or any later version. 13 | 14 | libicp is distributed in the hope that it will be useful, but WITHOUT ANY 15 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 16 | PARTICULAR PURPOSE. See the GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along with 19 | libicp; if not, write to the Free Software Foundation, Inc., 51 Franklin 20 | Street, Fifth Floor, Boston, MA 02110-1301, USA 21 | */ 22 | 23 | #ifdef _OPENMP 24 | #include 25 | #endif 26 | 27 | #include "icpPointToPlane.h" 28 | 29 | using namespace std; 30 | 31 | // Also see (3d part): "Linear Least-Squares Optimization for Point-to-Plane ICP Surface Registration" (Kok-Lim Low) 32 | double IcpPointToPlane::fitStep (double *T,const int32_t T_num,Matrix &R,Matrix &t,const std::vector &active) { 33 | 34 | int32_t i; 35 | int32_t nact = (int)active.size(); 36 | 37 | // init matrix for point32_t correspondences 38 | Matrix p_m(nact,m_dim); // model 39 | Matrix p_t(nact,m_dim); // template 40 | 41 | // dimensionality 2 42 | if (m_dim==2) { 43 | 44 | // extract matrix and translation vector 45 | double r00 = R.val[0][0]; double r01 = R.val[0][1]; 46 | double r10 = R.val[1][0]; double r11 = R.val[1][1]; 47 | double t0 = t.val[0][0]; double t1 = t.val[1][0]; 48 | 49 | // init A and b 50 | Matrix A(nact,3); 51 | Matrix b(nact,1); 52 | 53 | // establish correspondences 54 | #pragma omp parallel for private(i) default(none) shared(T,active,nact,p_m,p_t,A,b,r00,r01,r10,r11,t0,t1) // schedule (dynamic,2) 55 | for (i=0; i query(m_dim); 58 | kdtree::KDTreeResultVector result; 59 | 60 | // get index of active point 61 | int32_t idx = active[i]; 62 | 63 | // transform point according to R|t 64 | query[0] = (float)(r00*T[idx*2+0] + r01*T[idx*2+1] + t0); 65 | query[1] = (float)(r10*T[idx*2+0] + r11*T[idx*2+1] + t1); 66 | 67 | // search nearest neighbor 68 | m_kd_tree->n_nearest(query,1,result); 69 | 70 | // model point 71 | double dx = m_kd_tree->the_data[result[0].idx][0]; 72 | double dy = m_kd_tree->the_data[result[0].idx][1]; 73 | 74 | // model point normal 75 | double nx = M_normal[result[0].idx*2+0]; 76 | double ny = M_normal[result[0].idx*2+1]; 77 | 78 | // template point 79 | double sx = query[0]; 80 | double sy = query[1]; 81 | 82 | // setup least squares system 83 | A.val[i][0] = ny*sx-nx*sy; 84 | A.val[i][1] = nx; 85 | A.val[i][2] = ny; 86 | b.val[i][0] = nx*dx+ny*dy-nx*sx-ny*sy; 87 | } 88 | 89 | // linear least square matrices 90 | Matrix A_ = ~A*A; 91 | Matrix b_ = ~A*b; 92 | 93 | // solve linear system 94 | if (b_.solve(A_)) { 95 | 96 | // rotation matrix 97 | Matrix R_ = Matrix::eye(2); 98 | R_.val[0][1] = -b_.val[0][0]; 99 | R_.val[1][0] = +b_.val[0][0]; 100 | 101 | // orthonormalized rotation matrix 102 | Matrix U,W,V; 103 | R_.svd(U,W,V); 104 | R_ = U*~V; 105 | 106 | // fix improper matrix problem 107 | if (R_.det()<0){ 108 | Matrix B = Matrix::eye(m_dim); 109 | B.val[m_dim-1][m_dim-1] = R_.det(); 110 | R_ = V*B*~U; 111 | } 112 | 113 | // translation vector 114 | Matrix t_(2,1); 115 | t_.val[0][0] = b_.val[1][0]; 116 | t_.val[1][0] = b_.val[2][0]; 117 | 118 | // compose: R|t = R_|t_ * R|t 119 | R = R_*R; 120 | t = R_*t+t_; 121 | 122 | return max((R_-Matrix::eye(2)).l2norm(),t_.l2norm()); 123 | } 124 | 125 | // dimensionality 3 126 | } else { 127 | 128 | // extract matrix and translation vector 129 | double r00 = R.val[0][0]; double r01 = R.val[0][1]; double r02 = R.val[0][2]; 130 | double r10 = R.val[1][0]; double r11 = R.val[1][1]; double r12 = R.val[1][2]; 131 | double r20 = R.val[2][0]; double r21 = R.val[2][1]; double r22 = R.val[2][2]; 132 | double t0 = t.val[0][0]; double t1 = t.val[1][0]; double t2 = t.val[2][0]; 133 | 134 | // init A and b 135 | Matrix A(nact,6); 136 | Matrix b(nact,1); 137 | 138 | // establish correspondences 139 | #pragma omp parallel for private(i) default(none) shared(T,active,nact,p_m,p_t,A,b,r00,r01,r02,r10,r11,r12,r20,r21,r22,t0,t1,t2) // schedule (dynamic,2) 140 | for (i=0; i query(m_dim); 143 | kdtree::KDTreeResultVector result; 144 | 145 | // get index of active point 146 | int32_t idx = active[i]; 147 | 148 | // transform point according to R|t 149 | query[0] = (float)(r00*T[idx*3+0] + r01*T[idx*3+1] + r02*T[idx*3+2] + t0); 150 | query[1] = (float)(r10*T[idx*3+0] + r11*T[idx*3+1] + r12*T[idx*3+2] + t1); 151 | query[2] = (float)(r20*T[idx*3+0] + r21*T[idx*3+1] + r22*T[idx*3+2] + t2); 152 | 153 | // search nearest neighbor 154 | m_kd_tree->n_nearest(query,1,result); 155 | 156 | // model point 157 | double dx = m_kd_tree->the_data[result[0].idx][0]; 158 | double dy = m_kd_tree->the_data[result[0].idx][1]; 159 | double dz = m_kd_tree->the_data[result[0].idx][2]; 160 | 161 | // model point normal 162 | double nx = M_normal[result[0].idx*3+0]; 163 | double ny = M_normal[result[0].idx*3+1]; 164 | double nz = M_normal[result[0].idx*3+2]; 165 | 166 | // template point 167 | double sx = query[0]; 168 | double sy = query[1]; 169 | double sz = query[2]; 170 | 171 | // setup least squares system 172 | A.val[i][0] = nz*sy-ny*sz; 173 | A.val[i][1] = nx*sz-nz*sx; 174 | A.val[i][2] = ny*sx-nx*sy; 175 | A.val[i][3] = nx; 176 | A.val[i][4] = ny; 177 | A.val[i][5] = nz; 178 | b.val[i][0] = nx*dx+ny*dy+nz*dz-nx*sx-ny*sy-nz*sz; 179 | } 180 | 181 | // linear least square matrices 182 | Matrix A_ = ~A*A; 183 | Matrix b_ = ~A*b; 184 | 185 | // solve linear system 186 | if (b_.solve(A_)) { 187 | 188 | // rotation matrix 189 | Matrix R_ = Matrix::eye(3); 190 | R_.val[0][1] = -b_.val[2][0]; 191 | R_.val[1][0] = +b_.val[2][0]; 192 | R_.val[0][2] = +b_.val[1][0]; 193 | R_.val[2][0] = -b_.val[1][0]; 194 | R_.val[1][2] = -b_.val[0][0]; 195 | R_.val[2][1] = +b_.val[0][0]; 196 | 197 | // orthonormalized rotation matrix 198 | Matrix U,W,V; 199 | R_.svd(U,W,V); 200 | R_ = U*~V; 201 | 202 | // fix improper matrix problem 203 | if (R_.det()<0){ 204 | Matrix B = Matrix::eye(m_dim); 205 | B.val[m_dim-1][m_dim-1] = R_.det(); 206 | R_ = V*B*~U; 207 | } 208 | 209 | // translation vector 210 | Matrix t_(3,1); 211 | t_.val[0][0] = b_.val[3][0]; 212 | t_.val[1][0] = b_.val[4][0]; 213 | t_.val[2][0] = b_.val[5][0]; 214 | 215 | // compose: R|t = R_|t_ * R|t 216 | R = R_*R; 217 | t = R_*t+t_; 218 | return max((R_-Matrix::eye(3)).l2norm(),t_.l2norm()); 219 | } 220 | } 221 | 222 | // failure 223 | return 0; 224 | } 225 | 226 | std::vector IcpPointToPlane::getInliers (double *T,const int32_t T_num,const Matrix &R,const Matrix &t,const double indist) { 227 | 228 | // init inlier vector + query point + query result 229 | vector inliers; 230 | std::vector query(m_dim); 231 | kdtree::KDTreeResultVector neighbor; 232 | 233 | // dimensionality 2 234 | if (m_dim==2) { 235 | 236 | // extract matrix and translation vector 237 | double r00 = R.val[0][0]; double r01 = R.val[0][1]; 238 | double r10 = R.val[1][0]; double r11 = R.val[1][1]; 239 | double t0 = t.val[0][0]; double t1 = t.val[1][0]; 240 | 241 | // check for all points if they are inliers 242 | for (int32_t i=0; in_nearest(query,1,neighbor); 250 | 251 | // model point 252 | double dx = m_kd_tree->the_data[neighbor[0].idx][0]; 253 | double dy = m_kd_tree->the_data[neighbor[0].idx][1]; 254 | 255 | // model point normal 256 | double nx = M_normal[neighbor[0].idx*2+0]; 257 | double ny = M_normal[neighbor[0].idx*2+1]; 258 | 259 | // check if it is an inlier 260 | if (/*neighbor[0].dis<3*indist && */abs((sx-dx)*nx+(sy-dy)*ny)n_nearest(query,1,neighbor); 283 | 284 | // model point 285 | double dx = m_kd_tree->the_data[neighbor[0].idx][0]; 286 | double dy = m_kd_tree->the_data[neighbor[0].idx][1]; 287 | double dz = m_kd_tree->the_data[neighbor[0].idx][2]; 288 | 289 | // model point normal 290 | double nx = M_normal[neighbor[0].idx*3+0]; 291 | double ny = M_normal[neighbor[0].idx*3+1]; 292 | double nz = M_normal[neighbor[0].idx*3+2]; 293 | 294 | // check if it is an inlier 295 | if (abs((sx-dx)*nx+(sy-dy)*ny+(sz-dz))*nzthe_data[neighbors[i].idx][0]; 314 | double y = m_kd_tree->the_data[neighbors[i].idx][1]; 315 | P.val[i][0] = x; 316 | P.val[i][1] = y; 317 | mu.val[0][0] += x; 318 | mu.val[0][1] += y; 319 | } 320 | // zero mean 321 | mu = mu/(double)neighbors.size(); 322 | Matrix Q = P - Matrix::ones(neighbors.size(),1)*mu; 323 | 324 | // principal component analysis 325 | Matrix H = ~Q*Q; 326 | Matrix U,W,V; 327 | H.svd(U,W,V); 328 | 329 | // normal 330 | M_normal[0] = U.val[0][1]; 331 | M_normal[1] = U.val[1][1]; 332 | 333 | // dimensionality 3 334 | } else { 335 | 336 | // extract neighbors 337 | Matrix P(neighbors.size(),3); 338 | Matrix mu(1,3); 339 | for (uint32_t i=0; ithe_data[neighbors[i].idx][0]; 341 | double y = m_kd_tree->the_data[neighbors[i].idx][1]; 342 | double z = m_kd_tree->the_data[neighbors[i].idx][2]; 343 | P.val[i][0] = x; 344 | P.val[i][1] = y; 345 | P.val[i][2] = z; 346 | mu.val[0][0] += x; 347 | mu.val[0][1] += y; 348 | mu.val[0][2] += z; 349 | } 350 | 351 | // zero mean 352 | mu = mu/(double)neighbors.size(); 353 | Matrix Q = P - Matrix::ones(neighbors.size(),1)*mu; 354 | 355 | // principal component analysis 356 | Matrix H = ~Q*Q; 357 | Matrix U,W,V; 358 | H.svd(U,W,V); 359 | 360 | // normal 361 | M_normal[0] = U.val[0][2]; 362 | M_normal[1] = U.val[1][2]; 363 | M_normal[2] = U.val[2][2]; 364 | } 365 | } 366 | 367 | double* IcpPointToPlane::computeNormals (const int32_t num_neighbors,const double flatness) { 368 | double *M_normal = (double*)malloc(m_kd_tree->N*m_dim*sizeof(double)); 369 | kdtree::KDTreeResultVector neighbors; 370 | for (int32_t i=0; iN; i++) { 371 | m_kd_tree->n_nearest_around_point(i,0,num_neighbors,neighbors); 372 | // m_kd_tree->r_nearest_around_point(i,0,0.05,neighbors); 373 | if (m_dim==2) computeNormal(neighbors,M_normal+i*2,flatness); 374 | else computeNormal(neighbors,M_normal+i*3,flatness); 375 | } 376 | 377 | return M_normal; 378 | } 379 | 380 | double IcpPointToPlane::getResidual( double *T,const int32_t T_num,const Matrix &R,const Matrix &t,const std::vector &active ) 381 | { 382 | if(active.empty()) return 0; 383 | int nact = active.size(); 384 | double residual = 0; 385 | 386 | std::vector query(m_dim); 387 | kdtree::KDTreeResultVector result; 388 | 389 | if (m_dim==2) { 390 | // extract matrix and translation vector 391 | double r00 = R.val[0][0]; double r01 = R.val[0][1]; 392 | double r10 = R.val[1][0]; double r11 = R.val[1][1]; 393 | double t0 = t.val[0][0]; double t1 = t.val[1][0]; 394 | for (int32_t i=0; in_nearest(query,1,result); 406 | // model point 407 | double mx = m_kd_tree->the_data[result[0].idx][0]; 408 | double my = m_kd_tree->the_data[result[0].idx][1]; 409 | // model point normal 410 | double nx = M_normal[result[0].idx*2+0]; 411 | double ny = M_normal[result[0].idx*2+1]; 412 | 413 | residual += abs(nx * (mx-tx) + ny * (my-ty)); 414 | 415 | } 416 | // dimensionality 3 417 | } else { 418 | // extract matrix and translation vector 419 | double r00 = R.val[0][0]; double r01 = R.val[0][1]; double r02 = R.val[0][2]; 420 | double r10 = R.val[1][0]; double r11 = R.val[1][1]; double r12 = R.val[1][2]; 421 | double r20 = R.val[2][0]; double r21 = R.val[2][1]; double r22 = R.val[2][2]; 422 | double t0 = t.val[0][0]; double t1 = t.val[1][0]; double t2 = t.val[2][0]; 423 | for (int32_t i=0; i query(m_dim); 426 | kdtree::KDTreeResultVector result; 427 | // get index of active point 428 | int32_t idx = active[i]; 429 | // transform point according to R|t 430 | double tx = r00*T[idx*3+0] + r01*T[idx*3+1] + r02*T[idx*3+2] + t0; 431 | double ty = r10*T[idx*3+0] + r11*T[idx*3+1] + r12*T[idx*3+2] + t1; 432 | double tz = r20*T[idx*3+0] + r21*T[idx*3+1] + r22*T[idx*3+2] + t2; 433 | query[0] = (float)tx; 434 | query[1] = (float)ty; 435 | query[2] = (float)tz; 436 | // search nearest neighbor 437 | m_kd_tree->n_nearest(query,1,result); 438 | // 439 | // model point 440 | double mx = m_kd_tree->the_data[result[0].idx][0]; 441 | double my = m_kd_tree->the_data[result[0].idx][1]; 442 | double mz = m_kd_tree->the_data[result[0].idx][2]; 443 | 444 | // model point normal 445 | double nx = M_normal[result[0].idx*3+0]; 446 | double ny = M_normal[result[0].idx*3+1]; 447 | double nz = M_normal[result[0].idx*3+2]; 448 | 449 | residual += nx * (mx-tx) + ny * (my-ty) + nz * (mz-tz); 450 | } 451 | } 452 | residual /= nact; 453 | return residual; 454 | } 455 | 456 | 457 | -------------------------------------------------------------------------------- /src/kdtree.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // (c) Matthew B. Kennel, Institute for Nonlinear Science, UCSD (2004) 3 | // 4 | // Licensed under the Academic Free License version 1.1 found in file LICENSE 5 | // with additional provisions in that same file. 6 | 7 | 8 | #include "kdtree.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace kdtree { 15 | // utility 16 | 17 | inline float squared(const float x) { 18 | return(x*x); 19 | } 20 | 21 | inline void swap(int& a, int&b) { 22 | int tmp; 23 | tmp = a; 24 | a = b; 25 | b = tmp; 26 | } 27 | 28 | inline void swap(float& a, float&b) { 29 | float tmp; 30 | tmp = a; 31 | a = b; 32 | b = tmp; 33 | } 34 | 35 | // 36 | // KDTREERESULT implementation 37 | // 38 | inline bool operator<(const KDTreeResult& e1, const KDTreeResult& e2) { 39 | return (e1.dis < e2.dis); 40 | } 41 | 42 | // 43 | // KDTREE2_RESULT_VECTOR implementation 44 | // 45 | float KDTreeResultVector::max_value() { 46 | return( (*begin()).dis ); // very first element 47 | } 48 | 49 | void KDTreeResultVector::push_element_and_heapify(KDTreeResult& e) { 50 | push_back(e); // what a vector does. 51 | push_heap( begin(), end() ); // and now heapify it, with the new elt. 52 | } 53 | 54 | float KDTreeResultVector::replace_maxpri_elt_return_new_maxpri(KDTreeResult& e) { 55 | // remove the maximum priority element on the queue and replace it 56 | // with 'e', and return its priority. 57 | // 58 | // here, it means replacing the first element [0] with e, and re heapifying. 59 | 60 | pop_heap( begin(), end() ); 61 | pop_back(); 62 | push_back(e); // insert new 63 | push_heap(begin(), end() ); // and heapify. 64 | return( (*this)[0].dis ); 65 | } 66 | 67 | // 68 | // KDTREE2 implementation 69 | // 70 | 71 | // constructor 72 | KDTree::KDTree(KDTreeArray& data_in, bool rearrange_in, int dim_in) 73 | : the_data(data_in), 74 | N ( data_in.shape()[0] ), 75 | dim( data_in.shape()[1] ), 76 | sort_results(false), 77 | rearrange(rearrange_in), 78 | root(NULL), 79 | data(NULL), 80 | ind(N) { 81 | // 82 | // initialize the constant references using this unusual C++ 83 | // feature. 84 | // 85 | if (dim_in > 0) 86 | dim = dim_in; 87 | 88 | build_tree(); 89 | 90 | if (rearrange) { 91 | // if we have a rearranged tree. 92 | // allocate the memory for it. 93 | rearranged_data.resize( boost::extents[N][dim] ); 94 | 95 | // permute the data for it. 96 | for (int i=0; ibox[i]); 135 | } 136 | 137 | node->cut_dim = 0; 138 | node->cut_val = 0.0; 139 | node->l = l; 140 | node->u = u; 141 | node->left = node->right = NULL; 142 | 143 | 144 | } else { 145 | // 146 | // Compute an APPROXIMATE bounding box for this node. 147 | // if parent == NULL, then this is the root node, and 148 | // we compute for all dimensions. 149 | // Otherwise, we copy the bounding box from the parent for 150 | // all coordinates except for the parent's cut dimension. 151 | // That, we recompute ourself. 152 | // 153 | int c = -1; 154 | float maxspread = 0.0; 155 | int m; 156 | 157 | for (int i=0;icut_dim == i)) { 159 | spread_in_coordinate(i, l, u, node->box[i]); 160 | } else { 161 | node->box[i] = parent->box[i]; 162 | } 163 | float spread = node->box[i].upper - node->box[i].lower; 164 | if (spread>maxspread) { 165 | maxspread = spread; 166 | c=i; 167 | } 168 | } 169 | 170 | // 171 | // now, c is the identity of which coordinate has the greatest spread 172 | // 173 | 174 | if (false) { 175 | m = (l+u)/2; 176 | select_on_coordinate(c, m, l, u); 177 | } else { 178 | float sum; 179 | float average; 180 | 181 | if (true) { 182 | sum = 0.0; 183 | for (int k=l; k <= u; k++) { 184 | sum += the_data[ind[k]][c]; 185 | } 186 | average = sum / static_cast (u-l+1); 187 | } else { 188 | // average of top and bottom nodes. 189 | average = (node->box[c].upper + node->box[c].lower)*0.5F; 190 | } 191 | 192 | m = select_on_coordinate_value(c, average, l, u); 193 | } 194 | 195 | 196 | // move the indices around to cut on dim 'c'. 197 | node->cut_dim=c; 198 | node->l = l; 199 | node->u = u; 200 | 201 | node->left = build_tree_for_range(l, m, node); 202 | node->right = build_tree_for_range(m+1, u, node); 203 | 204 | if (node->right == NULL) { 205 | for (int i=0; ibox[i] = node->left->box[i]; 207 | node->cut_val = node->left->box[c].upper; 208 | node->cut_val_left = node->cut_val_right = node->cut_val; 209 | } else if (node->left == NULL) { 210 | for (int i=0; ibox[i] = node->right->box[i]; 212 | node->cut_val = node->right->box[c].upper; 213 | node->cut_val_left = node->cut_val_right = node->cut_val; 214 | } else { 215 | node->cut_val_right = node->right->box[c].lower; 216 | node->cut_val_left = node->left->box[c].upper; 217 | node->cut_val = (node->cut_val_left + node->cut_val_right) / 2.0F; 218 | // 219 | // now recompute true bounding box as union of subtree boxes. 220 | // This is now faster having built the tree, being logarithmic in 221 | // N, not linear as would be from naive method. 222 | // 223 | for (int i=0; ibox[i].upper = std::max(node->left->box[i].upper, 225 | node->right->box[i].upper); 226 | 227 | node->box[i].lower = std::min(node->left->box[i].lower, 228 | node->right->box[i].lower); 229 | } 230 | } 231 | } 232 | return(node); 233 | } 234 | 235 | void KDTree::spread_in_coordinate(int c, int l, int u, interval& interv) { 236 | // return the minimum and maximum of the indexed data between l and u in 237 | // smin_out and smax_out. 238 | 239 | float smin, smax; 240 | float lmin, lmax; 241 | int i; 242 | 243 | smin = the_data[ind[l]][c]; 244 | smax = smin; 245 | 246 | // process two at a time. 247 | for (i=l+2; i<= u; i+=2) { 248 | lmin = the_data[ind[i-1]] [c]; 249 | lmax = the_data[ind[i] ] [c]; 250 | 251 | if (lmin > lmax) { 252 | swap(lmin, lmax); 253 | // float t = lmin; 254 | // lmin = lmax; 255 | // lmax = t; 256 | } 257 | 258 | if (smin > lmin) smin = lmin; 259 | if (smax last) smin = last; 265 | if (smax= k) u = m-1; 291 | } // while loop 292 | } 293 | 294 | int KDTree::select_on_coordinate_value(int c, float alpha, int l, int u) { 295 | // 296 | // Move indices in ind[l..u] so that the elements in [l .. return] 297 | // are <= alpha, and hence are less than the [return+1..u] 298 | // elments, viewed across dimension 'c'. 299 | // 300 | int lb = l, ub = u; 301 | 302 | while (lb < ub) { 303 | if (the_data[ind[lb]][c] <= alpha) { 304 | lb++; // good where it is. 305 | } else { 306 | swap(ind[lb], ind[ub]); 307 | ub--; 308 | } 309 | } 310 | 311 | // here ub=lb 312 | if (the_data[ind[lb]][c] <= alpha) 313 | return(lb); 314 | else 315 | return(lb-1); 316 | 317 | } 318 | 319 | // search record substructure 320 | // 321 | // one of these is created for each search. 322 | // this holds useful information to be used 323 | // during the search 324 | 325 | static const float infinity = 1.0e38F; 326 | 327 | class SearchRecord { 328 | 329 | private: 330 | friend class KDTree; 331 | friend class KDTreeNode; 332 | 333 | std::vector& qv; 334 | int dim; 335 | bool rearrange; 336 | unsigned int nn; // , nfound; 337 | float ballsize; 338 | int centeridx, correltime; 339 | 340 | KDTreeResultVector& result; // results 341 | const KDTreeArray* data; 342 | const std::vector& ind; 343 | // constructor 344 | 345 | public: 346 | SearchRecord(std::vector& qv_in, KDTree& tree_in, 347 | KDTreeResultVector& result_in) : 348 | qv(qv_in), 349 | result(result_in), 350 | data(tree_in.data), 351 | ind(tree_in.ind) { 352 | dim = tree_in.dim; 353 | rearrange = tree_in.rearrange; 354 | ballsize = infinity; 355 | nn = 0; 356 | }; 357 | 358 | }; 359 | 360 | void KDTree::n_nearest_brute_force(std::vector& qv, int nn, KDTreeResultVector& result) { 361 | 362 | result.clear(); 363 | 364 | for (int i=0; i& qv, int nn, KDTreeResultVector& result) { 379 | SearchRecord sr(qv, *this, result); 380 | std::vector vdiff(dim, 0.0); 381 | 382 | result.clear(); 383 | 384 | sr.centeridx = -1; 385 | sr.correltime = 0; 386 | sr.nn = nn; 387 | 388 | root->search(sr); 389 | 390 | if (sort_results) sort(result.begin(), result.end()); 391 | } 392 | 393 | void KDTree::n_nearest_around_point(int idxin, int correltime, int nn, 394 | KDTreeResultVector& result) { 395 | 396 | std::vector qv(dim); // query vector 397 | result.clear(); 398 | for (int i=0; isearch(sr); 410 | } 411 | 412 | if (sort_results) sort(result.begin(), result.end()); 413 | } 414 | 415 | 416 | void KDTree::r_nearest(std::vector& qv, float r2, KDTreeResultVector& result) { 417 | // search for all within a ball of a certain radius 418 | SearchRecord sr(qv, *this, result); 419 | std::vector vdiff(dim, 0.0); 420 | 421 | result.clear(); 422 | 423 | sr.centeridx = -1; 424 | sr.correltime = 0; 425 | sr.nn = 0; 426 | sr.ballsize = r2; 427 | 428 | root->search(sr); 429 | 430 | if (sort_results) sort(result.begin(), result.end()); 431 | } 432 | 433 | int KDTree::r_count(std::vector& qv, float r2) { 434 | // search for all within a ball of a certain radius 435 | { 436 | KDTreeResultVector result; 437 | SearchRecord sr(qv, *this, result); 438 | 439 | sr.centeridx = -1; 440 | sr.correltime = 0; 441 | sr.nn = 0; 442 | sr.ballsize = r2; 443 | 444 | root->search(sr); 445 | return(result.size()); 446 | } 447 | } 448 | 449 | void KDTree::r_nearest_around_point(int idxin, int correltime, float r2, 450 | KDTreeResultVector& result) { 451 | std::vector qv(dim); // query vector 452 | 453 | result.clear(); 454 | 455 | for (int i=0; isearch(sr); 468 | } 469 | if (sort_results) sort(result.begin(), result.end()); 470 | } 471 | 472 | int KDTree::r_count_around_point(int idxin, int correltime, float r2) { 473 | std::vector qv(dim); // query vector 474 | 475 | for (int i=0; isearch(sr); 489 | return(result.size()); 490 | } 491 | } 492 | 493 | // 494 | // KDTREE_NODE implementation 495 | // 496 | 497 | // constructor 498 | KDTreeNode::KDTreeNode(int dim) : box(dim) { 499 | left = right = NULL; 500 | // 501 | // all other construction is handled for real in the 502 | // KDTree building operations. 503 | // 504 | } 505 | 506 | // destructor 507 | KDTreeNode::~KDTreeNode() { 508 | if (left != NULL) delete left; 509 | if (right != NULL) delete right; 510 | // maxbox and minbox 511 | // will be automatically deleted in their own destructors. 512 | } 513 | 514 | 515 | void KDTreeNode::search(SearchRecord& sr) { 516 | // the core search routine. 517 | // This uses true distance to bounding box as the 518 | // criterion to search the secondary node. 519 | // 520 | // This results in somewhat fewer searches of the secondary nodes 521 | // than 'search', which uses the vdiff vector, but as this 522 | // takes more computational time, the overall performance may not 523 | // be improved in actual run time. 524 | 525 | if ( (left == NULL) && (right == NULL)) { 526 | // we are on a terminal node 527 | if (sr.nn == 0) { 528 | process_terminal_node_fixedball(sr); 529 | } else { 530 | process_terminal_node(sr); 531 | } 532 | } else { 533 | KDTreeNode *ncloser, *nfarther; 534 | 535 | float extra; 536 | float qval = sr.qv[cut_dim]; 537 | // value of the wall boundary on the cut dimension. 538 | if (qval < cut_val) { 539 | ncloser = left; 540 | nfarther = right; 541 | extra = cut_val_right-qval; 542 | } else { 543 | ncloser = right; 544 | nfarther = left; 545 | extra = qval-cut_val_left; 546 | }; 547 | 548 | if (ncloser != NULL) ncloser->search(sr); 549 | 550 | if ((nfarther != NULL) && (squared(extra) < sr.ballsize)) { 551 | // first cut 552 | if (nfarther->box_in_search_range(sr)) { 553 | nfarther->search(sr); 554 | } 555 | } 556 | } 557 | } 558 | 559 | inline float dis_from_bnd(float x, float amin, float amax) { 560 | if (x > amax) { 561 | return(x-amax); 562 | } else if (x < amin) 563 | return (amin-x); 564 | else 565 | return 0.0; 566 | } 567 | 568 | inline bool KDTreeNode::box_in_search_range(SearchRecord& sr) { 569 | // does the bounding box, represented by minbox[*],maxbox[*] 570 | // have any point which is within 'sr.ballsize' to 'sr.qv'?? 571 | 572 | int dim = sr.dim; 573 | float dis2 =0.0; 574 | float ballsize = sr.ballsize; 575 | for (int i=0; i ballsize) 578 | return(false); 579 | } 580 | return(true); 581 | } 582 | 583 | void KDTreeNode::process_terminal_node(SearchRecord& sr) { 584 | int centeridx = sr.centeridx; 585 | int correltime = sr.correltime; 586 | unsigned int nn = sr.nn; 587 | int dim = sr.dim; 588 | float ballsize = sr.ballsize; 589 | // 590 | bool rearrange = sr.rearrange; 591 | const KDTreeArray& data = *sr.data; 592 | 593 | const bool debug = false; 594 | 595 | if (debug) { 596 | // printf("Processing terminal node %d, %d\n", l, u); 597 | // std::cout << "Query vector = ["; 598 | // for (int i=0; i 23 | 24 | #define SWAP(a,b) {temp=a;a=b;b=temp;} 25 | #define SIGN(a,b) ((b) >= 0.0 ? fabs(a) : -fabs(a)) 26 | static FLOAT sqrarg; 27 | #define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg) 28 | static FLOAT maxarg1,maxarg2; 29 | #define FMAX(a,b) (maxarg1=(a),maxarg2=(b),(maxarg1) > (maxarg2) ? (maxarg1) : (maxarg2)) 30 | static int32_t iminarg1,iminarg2; 31 | #define IMIN(a,b) (iminarg1=(a),iminarg2=(b),(iminarg1) < (iminarg2) ? (iminarg1) : (iminarg2)) 32 | 33 | 34 | using namespace std; 35 | 36 | Matrix::Matrix () { 37 | m = 0; 38 | n = 0; 39 | val = 0; 40 | } 41 | 42 | Matrix::Matrix (const int32_t m_,const int32_t n_) { 43 | allocateMemory(m_,n_); 44 | } 45 | 46 | Matrix::Matrix (const int32_t m_,const int32_t n_,const FLOAT* val_) { 47 | allocateMemory(m_,n_); 48 | int32_t k=0; 49 | for (int32_t i=0; i0) 71 | for (int32_t i=0; i=m || j1<0 || j2>=n || i2m || j1+M.n>n) { 104 | cerr << "ERROR: Cannot set submatrix [" << i1 << ".." << i1+M.m-1 << 105 | "] x [" << j1 << ".." << j1+M.n-1 << "]" << 106 | " of a (" << m << "x" << n << ") matrix." << endl; 107 | exit(0); 108 | } 109 | for (int32_t i=0; i idx) { 137 | Matrix M(m,idx.size()); 138 | for (int32_t j=0; j1 && M.n==1) { 170 | Matrix D(M.m,M.m); 171 | for (int32_t i=0; i1) { 175 | Matrix D(M.n,M.n); 176 | for (int32_t i=0; i=big) { 456 | big=fabs(A.val[j][k]); 457 | irow=j; 458 | icol=k; 459 | } 460 | ++(ipiv[icol]); 461 | 462 | // We now have the pivot element, so we interchange rows, if needed, to put the pivot 463 | // element on the diagonal. The columns are not physically interchanged, only relabeled. 464 | if (irow != icol) { 465 | for (l=0;l=0;l--) { 499 | if (indxr[l]!=indxc[l]) 500 | for (k=0;kbig) 533 | big = temp; 534 | if (big == 0.0) { // No nonzero largest element. 535 | free(vv); 536 | return false; 537 | } 538 | vv[i] = 1.0/big; // Save the scaling. 539 | } 540 | for (j=0; j=big) { 554 | big = dum; 555 | imax = i; 556 | } 557 | } 558 | if (j!=imax) { // Do we need to interchange rows? 559 | for (k=0; k=0;i--) { // Accumulation of right-hand transformations. 643 | if (i=0;i--) { // Accumulation of left-hand transformations. 659 | l = i+1; 660 | g = w[i]; 661 | for (j=l;j=0;k--) { // Diagonalization of the bidiagonal form: Loop over singular values, 674 | for (its=0;its<30;its++) { // and over allowed iterations. 675 | flag = 1; 676 | for (l=k;l>=0;l--) { // Test for splitting. 677 | nm = l-1; 678 | if ((FLOAT)(fabs(rv1[l])+anorm) == anorm) { flag = 0; break; } 679 | if ((FLOAT)(fabs( w[nm])+anorm) == anorm) { break; } 680 | } 681 | if (flag) { 682 | c = 0.0; // Cancellation of rv1[l], if l > 1. 683 | s = 1.0; 684 | for (i=l;i<=k;i++) { 685 | f = s*rv1[i]; 686 | rv1[i] = c*rv1[i]; 687 | if ((FLOAT)(fabs(f)+anorm) == anorm) break; 688 | g = w[i]; 689 | h = pythag(f,g); 690 | w[i] = h; 691 | h = 1.0/h; 692 | c = g*h; 693 | s = -f*h; 694 | for (j=0;j 1); 790 | for (k=0;k (m+n)/2) { 795 | for (i=0;i absb) 854 | return absa*sqrt(1.0+SQR(absb/absa)); 855 | else 856 | return (absb == 0.0 ? 0.0 : absb*sqrt(1.0+SQR(absa/absb))); 857 | } 858 | 859 | --------------------------------------------------------------------------------