vosch_tools.hpp
Go to the documentation of this file.
00001 //-----------
00002 //* read
00003 template <typename T>
00004 bool readPoints( const char *name, pcl::PointCloud<T>& cloud ){
00005   if (pcl::io::loadPCDFile (name, cloud) == -1){
00006     ROS_ERROR ("Couldn't read file %s",name);
00007     return (-1);
00008   }
00009 #ifndef QUIET
00010   ROS_INFO ("Loaded %d data points from %s with the following fields: %s", (int)(cloud.width * cloud.height), name, pcl::getFieldsList (cloud).c_str ());
00011 #endif
00012   return(1);
00013 }
00014 
00015 //------------------
00016 //* compute normals
00017 template <typename T1, typename T2>
00018 void computeNormal( pcl::PointCloud<T1> input_cloud, pcl::PointCloud<T2>& output_cloud ){
00019   // if ((int)input_cloud.points.size () < k_)
00020   // {
00021   //   ROS_WARN ("Filtering returned %d points! Continuing.", (int)input_cloud.points.size ());
00022   //   //pcl::PointCloud<pcl::PointXYZRGBNormal> cloud_temp;
00023   //   //pcl::concatenateFields <Point, pcl::Normal, pcl::PointXYZRGBNormal> (cloud_filtered, cloud_normals, cloud_temp);
00024   //   //pcl::io::savePCDFile ("test.pcd", cloud, false);
00025   // }
00026   pcl::NormalEstimation<T1, T2> n3d_;
00027   //n3d_.setKSearch (k_);
00028   n3d_.setRadiusSearch (normals_radius_search);
00029   n3d_.setSearchMethod ( boost::make_shared<pcl::KdTreeFLANN<T1> > () );
00030   n3d_.setInputCloud ( input_cloud.makeShared() );
00031   n3d_.compute (output_cloud);
00032 
00033   //* TODO: move the following lines to NormalEstimation class ?
00034   for ( int i=0; i< (int)input_cloud.points.size (); i++ ){
00035     output_cloud.points[ i ].x = input_cloud.points[ i ].x;
00036     output_cloud.points[ i ].y = input_cloud.points[ i ].y;
00037     output_cloud.points[ i ].z = input_cloud.points[ i ].z;
00038     output_cloud.points[ i ].rgb = input_cloud.points[ i ].rgb;
00039   }
00040 }
00041 
00042 //--------------------
00043 //* function for GRSD 
00044 int getType (float min_radius, float max_radius)
00045 {
00046   if (min_radius > 0.100)
00047     return PLANE;
00048   else if (max_radius > 0.175)
00049     return CYLINDER;
00050   else if (min_radius < 0.015)
00051     return NOISE;
00052   else if (max_radius - min_radius < 0.050)
00053     return SPHERE;
00054   else
00055     return EDGE;
00056   /* if (min_radius > min_radius_plane_) // 0.066 */
00057   /*   return PLANE; // plane */
00058   /* else if ((min_radius < min_radius_noise_) && (max_radius < max_radius_noise_)) */
00059   /*   return NOISE; // noise/corner */
00060   /* else if (max_radius - min_radius < max_min_radius_diff_) // 0.0075 */
00061   /*   return SPHERE; // circle (corner?) */
00062   /* else if (min_radius < min_radius_edge_) /// considering small cylinders to be edges */
00063   /*   return EDGE; // edge */
00064   /* else */
00065   /*   return CYLINDER; // cylinder (rim) */
00066 }
00067 
00068 //--------------------
00069 //* extract - GRSD -
00070 template <typename T>
00071 Eigen::Vector3i extractGRSDSignature21(pcl::VoxelGrid<T> grid, pcl::PointCloud<T> cloud, pcl::PointCloud<T> cloud_downsampled, std::vector< std::vector<float> > &feature, const float voxel_size, const int subdivision_size = 0, const int offset_x = 0, const int offset_y = 0, const int offset_z = 0, const bool is_normalize  ){
00072 #ifndef QUIET
00073   ROS_INFO("rsd %f, normals %f, leaf %f", rsd_radius_search, normals_radius_search, voxel_size);
00074 #endif
00075   feature.resize( 0 );
00076   boost::shared_ptr< const pcl::PointCloud<T> > cloud_downsampled_ptr;
00077   cloud_downsampled_ptr.reset (new pcl::PointCloud<T> (cloud_downsampled));
00078 
00079   //* for computing multiple GRSD with subdivisions
00080   int hist_num = 1;
00081   float inverse_subdivision_size = 0;
00082   Eigen::Vector3i div_b_= Eigen::Vector3i::Zero();
00083   Eigen::Vector3i min_b_= Eigen::Vector3i::Zero();
00084   Eigen::Vector3i subdiv_b_ = Eigen::Vector3i::Zero();
00085   Eigen::Vector3i subdivb_mul_= Eigen::Vector3i::Zero();
00086   if( subdivision_size > 0 ){
00087     inverse_subdivision_size = 1.0 / subdivision_size;
00088     div_b_ = grid.getNrDivisions();
00089     min_b_ = grid.getMinBoxCoordinates();
00090     if( ( div_b_[0] <= offset_x ) || ( div_b_[1] <= offset_y ) || ( div_b_[2] <= offset_z ) ){
00091       std::cerr << "(In extractGRSDSignature21) offset values (" << offset_x << "," << offset_y << "," << offset_z << ") exceed voxel grid size (" << div_b_[0] << "," << div_b_[1] << "," << div_b_[2] << ")."<< std::endl;
00092       return Eigen::Vector3i::Zero();
00093     }
00094     subdiv_b_ = Eigen::Vector3i ( ceil( ( div_b_[0] - offset_x )*inverse_subdivision_size ), ceil( ( div_b_[1] - offset_y )*inverse_subdivision_size ), ceil( ( div_b_[2] - offset_z )*inverse_subdivision_size ) );
00095     subdivb_mul_ = Eigen::Vector3i ( 1, subdiv_b_[0], subdiv_b_[0] * subdiv_b_[1] );
00096     hist_num = subdiv_b_[0] * subdiv_b_[1] * subdiv_b_[2];
00097   }
00098   else if( subdivision_size < 0 ){
00099     std::cerr << "(In extractGRSDSignature21) Invalid subdivision size: " << subdivision_size << std::endl;
00100     return Eigen::Vector3i::Zero();
00101   }
00102 
00103   // Compute RSD
00104   pcl::RSDEstimation <T, T, pcl::PrincipalRadiiRSD> rsd;
00105   rsd.setInputCloud( cloud_downsampled_ptr );
00106   boost::shared_ptr< const pcl::PointCloud<T> > cloud_ptr = cloud.makeShared();
00107   rsd.setSearchSurface( cloud_ptr );
00108   rsd.setInputNormals( cloud_ptr );
00109 #ifndef QUIET
00110   ROS_INFO("radius search: %f", std::max(rsd_radius_search, voxel_size/2 * sqrt(3)));
00111 #endif
00112   rsd.setRadiusSearch(std::max(rsd_radius_search, voxel_size/2 * sqrt(3)));
00113   boost::shared_ptr< pcl::KdTree<T> > tree2 = boost::make_shared<pcl::KdTreeFLANN<T> > ();
00114   tree2->setInputCloud (cloud.makeShared());
00115   rsd.setSearchMethod(tree2);
00116   pcl::PointCloud<pcl::PrincipalRadiiRSD> radii;
00117   t1 = my_clock();
00118   rsd.compute(radii);
00119 #ifndef QUIET
00120   ROS_INFO("RSD compute done in %f seconds.", my_clock()-t1);
00121 #endif
00122   
00123   // Get rmin/rmax for adjacent 27 voxel
00124   t1 = my_clock();
00125   Eigen::MatrixXi relative_coordinates (3, 13);
00126 
00127   //Eigen::MatrixXi transition_matrix =  Eigen::MatrixXi::Zero(6, 6);
00128   std::vector< Eigen::MatrixXi > transition_matrix( hist_num );
00129   for( int i=0; i<hist_num; i++ )
00130     transition_matrix[ i ] =  Eigen::MatrixXi::Zero(6, 6);
00131 
00132   int idx = 0;
00133   
00134   // 0 - 8
00135   for( int i=-1; i<2; i++ )
00136   {
00137     for( int j=-1; j<2; j++ )
00138     {
00139       relative_coordinates( 0, idx ) = i;
00140       relative_coordinates( 1, idx ) = j;
00141       relative_coordinates( 2, idx ) = -1;
00142       idx++;
00143     }
00144   }
00145   // 9 - 11
00146   for( int i=-1; i<2; i++ )
00147   {
00148     relative_coordinates( 0, idx ) = i;
00149     relative_coordinates( 1, idx ) = -1;
00150     relative_coordinates( 2, idx ) = 0;
00151     idx++;
00152   }
00153   // 12
00154   relative_coordinates( 0, idx ) = -1;
00155   relative_coordinates( 1, idx ) = 0;
00156   relative_coordinates( 2, idx ) = 0;
00157 
00158   Eigen::MatrixXi relative_coordinates_all (3, 26);
00159   relative_coordinates_all.block<3, 13>(0, 0) = relative_coordinates;
00160   relative_coordinates_all.block<3, 13>(0, 13) = -relative_coordinates;
00161   
00162   // Get transition matrix
00163   std::vector<int> types (radii.points.size());
00164  
00165   for (size_t idx = 0; idx < radii.points.size (); ++idx)
00166     types[idx] = getType(radii.points[idx].r_min, radii.points[idx].r_max);
00167   
00168   for (size_t idx = 0; idx < cloud_downsampled_ptr->points.size (); ++idx)
00169   {
00170     // calc hist_idx
00171     int hist_idx;
00172     if( hist_num == 1 ) hist_idx = 0;
00173     else{
00174       const int tmp_x = floor( cloud_downsampled_ptr->points[ idx ].x/voxel_size ) - min_b_[ 0 ] - offset_x;
00175       const int tmp_y = floor( cloud_downsampled_ptr->points[ idx ].y/voxel_size ) - min_b_[ 1 ] - offset_y;
00176       const int tmp_z = floor( cloud_downsampled_ptr->points[ idx ].z/voxel_size ) - min_b_[ 2 ] - offset_z;
00177       /* const int x_mul_y = div_b_[0] * div_b_[1]; */
00178       /* const int tmp_z = idx / x_mul_y - offset_z; */
00179       /* const int tmp_y = ( idx % x_mul_y ) / div_b_[0] - offset_y; */
00180       /* const int tmp_x = idx % div_b_[0] - offset_x; */
00181       if( ( tmp_x < 0 ) || ( tmp_y < 0 ) || ( tmp_z < 0 ) ) continue; // ignore idx smaller than offset.
00182       Eigen::Vector3i ijk = Eigen::Vector3i ( floor ( tmp_x * inverse_subdivision_size), floor ( tmp_y * inverse_subdivision_size), floor ( tmp_z * inverse_subdivision_size) );
00183       hist_idx = ijk.dot (subdivb_mul_);
00184     }
00185 
00186     int source_type = types[idx];
00187     std::vector<int> neighbors = grid.getNeighborCentroidIndices ( cloud_downsampled_ptr->points[idx], relative_coordinates_all);
00188     for (unsigned id_n = 0; id_n < neighbors.size(); id_n++)
00189     {
00190       int neighbor_type;
00191       if (neighbors[id_n] == -1)
00192         neighbor_type = EMPTY;
00193       else
00194         neighbor_type = types[neighbors[id_n]];
00195 
00196       transition_matrix[ hist_idx ](source_type, neighbor_type)++;
00197     }
00198   }
00199 #ifndef QUIET
00200   std::cerr << "transition matrix" << std::endl << transition_matrix[0] << std::endl;
00201   ROS_INFO("GRSD compute done in %f seconds.", my_clock()-t1);
00202 #endif
00203 
00204   pcl::PointCloud<pcl::GRSDSignature21> cloud_grsd;
00205   cloud_grsd.points.resize(hist_num);
00206   
00207   for( int h=0; h<hist_num; h++ ){
00208     int nrf = 0;
00209     for (int i=0; i<NR_CLASS+1; i++)
00210       for (int j=i; j<NR_CLASS+1; j++)
00211     /* for (int i=1; i<NR_CLASS+1; i++) */
00212     /*   for (int j=0; j<=i; j++) */
00213     cloud_grsd.points[ h ].histogram[nrf++] = transition_matrix[ h ](i, j) + transition_matrix[ h ](j, i);
00214   }
00215 
00216   feature.resize( hist_num );
00217   if( is_normalize ){
00218     for( int h=0; h<hist_num; h++ ){
00219       feature[ h ].resize( 20 );
00220       for( int i=0; i<20; i++)
00221         feature[ h ][ i ] = cloud_grsd.points[ h ].histogram[ i ] * NORMALIZE_GRSD;
00222     }
00223   }
00224   else{
00225     for( int h=0; h<hist_num; h++ ){
00226       feature[ h ].resize( 20 );
00227       for( int i=0; i<20; i++)
00228         feature[ h ][ i ] = cloud_grsd.points[ h ].histogram[ i ];
00229     }
00230   }
00231   return subdiv_b_;
00232 }
00233 
00234 template <typename T>
00235 void extractGRSDSignature21(pcl::VoxelGrid<T> grid, pcl::PointCloud<T> cloud, pcl::PointCloud<T> cloud_downsampled, std::vector<float> &feature, const float voxel_size, const bool is_normalize  ){
00236   std::vector< std::vector<float> > tmp( 1 );
00237   extractGRSDSignature21( grid, cloud, cloud_downsampled, tmp, voxel_size, 0, 0, 0, 0, is_normalize ); // for one signature
00238   feature = tmp[ 0 ];
00239 }
00240 
00241 //-----------------------------------
00242 //* extract - rotation-variant GRSD -
00243 template <typename T>
00244 Eigen::Vector3i extractGRSDSignature325(pcl::VoxelGrid<T> grid, pcl::PointCloud<T> cloud, pcl::PointCloud<T> cloud_downsampled, std::vector< std::vector<float> > &feature, const float voxel_size, const int subdivision_size = 0, const int offset_x = 0, const int offset_y = 0, const int offset_z = 0, const bool is_normalize  ){
00245 #ifndef QUIET
00246   ROS_INFO("rsd %f, normals %f, leaf %f", rsd_radius_search, normals_radius_search, voxel_size);
00247 #endif
00248   feature.resize( 0 );
00249   boost::shared_ptr< const pcl::PointCloud<T> > cloud_downsampled_ptr;
00250   cloud_downsampled_ptr.reset (new pcl::PointCloud<T> (cloud_downsampled));
00251   pcl::PointCloud<pcl::GRSDSignature325> cloud_grsd;
00252   
00253   //* for computing multiple GRSD with subdivisions
00254   int hist_num = 1;
00255   float inverse_subdivision_size = 0;
00256   Eigen::Vector3i div_b_= Eigen::Vector3i::Zero();
00257   Eigen::Vector3i min_b_= Eigen::Vector3i::Zero();
00258   Eigen::Vector3i subdiv_b_= Eigen::Vector3i::Zero();
00259   Eigen::Vector3i subdivb_mul_= Eigen::Vector3i::Zero();
00260   if( subdivision_size > 0 ){
00261     inverse_subdivision_size = 1.0 / subdivision_size;
00262     div_b_ = grid.getNrDivisions();
00263     min_b_ = grid.getMinBoxCoordinates();
00264     if( ( div_b_[0] <= offset_x ) || ( div_b_[1] <= offset_y ) || ( div_b_[2] <= offset_z ) ){
00265       std::cerr << "(In extractGRSDSignature325) offset values (" << offset_x << "," << offset_y << "," << offset_z << ") exceed voxel grid size (" << div_b_[0] << "," << div_b_[1] << "," << div_b_[2] << ")."<< std::endl;
00266       return Eigen::Vector3i::Zero();
00267     }
00268     subdiv_b_ = Eigen::Vector3i ( ceil( ( div_b_[0] - offset_x )*inverse_subdivision_size ), ceil( ( div_b_[1] - offset_y )*inverse_subdivision_size ), ceil( ( div_b_[2] - offset_z )*inverse_subdivision_size ) );
00269     subdivb_mul_ = Eigen::Vector3i ( 1, subdiv_b_[0], subdiv_b_[0] * subdiv_b_[1] );
00270     hist_num = subdiv_b_[0] * subdiv_b_[1] * subdiv_b_[2];
00271   }
00272   else if( subdivision_size < 0 ){
00273     std::cerr << "(In extractGRSDSignature325) Invalid subdivision size: " << subdivision_size << std::endl;
00274     return Eigen::Vector3i::Zero();
00275   }
00276   cloud_grsd.points.resize(hist_num);
00277 
00278   // Compute RSD
00279   pcl::RSDEstimation <T, T, pcl::PrincipalRadiiRSD> rsd;
00280   rsd.setInputCloud( cloud_downsampled_ptr );
00281   boost::shared_ptr< const pcl::PointCloud<T> > cloud_ptr = cloud.makeShared();
00282   rsd.setSearchSurface( cloud_ptr );
00283   rsd.setInputNormals( cloud_ptr );
00284 #ifndef QUIET
00285   ROS_INFO("radius search: %f", std::max(rsd_radius_search, voxel_size/2 * sqrt(3)));
00286 #endif
00287   rsd.setRadiusSearch(std::max(rsd_radius_search, voxel_size/2 * sqrt(3)));
00288   boost::shared_ptr< pcl::KdTree<T> > tree2 = boost::make_shared<pcl::KdTreeFLANN<T> > ();
00289   tree2->setInputCloud (cloud.makeShared());
00290   rsd.setSearchMethod(tree2);
00291   pcl::PointCloud<pcl::PrincipalRadiiRSD> radii;
00292   t1 = my_clock();
00293   rsd.compute(radii);
00294 #ifndef QUIET
00295   ROS_INFO("RSD compute done in %f seconds.", my_clock()-t1);
00296 #endif
00297   
00298   // Get rmin/rmax for adjacent 27 voxel
00299   t1 = my_clock();
00300   Eigen::MatrixXi relative_coordinates (3, 13);
00301 
00302   int idx = 0;
00303   
00304   // 0 - 8
00305   for( int i=-1; i<2; i++ )
00306   {
00307     for( int j=-1; j<2; j++ )
00308     {
00309       relative_coordinates( 0, idx ) = i;
00310       relative_coordinates( 1, idx ) = j;
00311       relative_coordinates( 2, idx ) = -1;
00312       idx++;
00313     }
00314   }
00315   // 9 - 11
00316   for( int i=-1; i<2; i++ )
00317   {
00318     relative_coordinates( 0, idx ) = i;
00319     relative_coordinates( 1, idx ) = -1;
00320     relative_coordinates( 2, idx ) = 0;
00321     idx++;
00322   }
00323   // 12
00324   relative_coordinates( 0, idx ) = -1;
00325   relative_coordinates( 1, idx ) = 0;
00326   relative_coordinates( 2, idx ) = 0;
00327 
00328   // Get transition matrix
00329   std::vector<int> types (radii.points.size());
00330  
00331   for (size_t idx = 0; idx < radii.points.size (); ++idx)
00332     types[idx] = getType(radii.points[idx].r_min, radii.points[idx].r_max);
00333   
00334   for (size_t idx = 0; idx < cloud_downsampled_ptr->points.size (); ++idx)
00335   {
00336     // calc hist_idx
00337     int hist_idx;
00338     if( hist_num == 1 ) hist_idx = 0;
00339     else{
00340       const int tmp_x = floor( cloud_downsampled_ptr->points[ idx ].x/voxel_size ) - min_b_[ 0 ] - offset_x;
00341       const int tmp_y = floor( cloud_downsampled_ptr->points[ idx ].y/voxel_size ) - min_b_[ 1 ] - offset_y;
00342       const int tmp_z = floor( cloud_downsampled_ptr->points[ idx ].z/voxel_size ) - min_b_[ 2 ] - offset_z;
00343       /* const int x_mul_y = div_b_[0] * div_b_[1]; */
00344       /* const int tmp_z = idx / x_mul_y - offset_z; */
00345       /* const int tmp_y = ( idx % x_mul_y ) / div_b_[0] - offset_y; */
00346       /* const int tmp_x = idx % div_b_[0] - offset_x; */
00347       if( ( tmp_x < 0 ) || ( tmp_y < 0 ) || ( tmp_z < 0 ) ) continue; // ignore idx smaller than offset.
00348       Eigen::Vector3i ijk = Eigen::Vector3i ( floor ( tmp_x * inverse_subdivision_size), floor ( tmp_y * inverse_subdivision_size), floor ( tmp_z * inverse_subdivision_size) );
00349       hist_idx = ijk.dot (subdivb_mul_);
00350     }
00351 
00352     int source_type = types[idx];
00353     std::vector<int> neighbors = grid.getNeighborCentroidIndices ( cloud_downsampled_ptr->points[idx], relative_coordinates);
00354     for (unsigned id_n = 0; id_n < neighbors.size(); id_n++)
00355     {
00356       int neighbor_type;
00357       if (neighbors[id_n] == -1)
00358         neighbor_type = EMPTY;
00359       else
00360         neighbor_type = types[neighbors[id_n]];
00361 
00362       // ignore EMPTY
00363       if( neighbor_type != EMPTY )
00364         cloud_grsd.points[ hist_idx ].histogram[ source_type + neighbor_type * 5 + id_n * 25 ]++;
00365     }
00366   }
00367 #ifndef QUIET
00368   ROS_INFO("GRSD compute done in %f seconds.", my_clock()-t1);
00369 #endif
00370 
00371   feature.resize( hist_num );
00372   if( is_normalize ){
00373     for( int h=0; h<hist_num; h++ ){
00374       feature[ h ].resize( GRSD_LARGE_DIM );
00375       for( int i=0; i<GRSD_LARGE_DIM; i++)
00376         feature[ h ][ i ] = cloud_grsd.points[ h ].histogram[ i ] * NORMALIZE_GRSD;
00377     }
00378   }
00379   else{
00380     for( int h=0; h<hist_num; h++ ){
00381       feature[ h ].resize( GRSD_LARGE_DIM );
00382       for( int i=0; i<GRSD_LARGE_DIM; i++)
00383         feature[ h ][ i ] = cloud_grsd.points[ h ].histogram[ i ];
00384     }
00385   }
00386   return subdiv_b_;
00387 }
00388 
00389 template <typename T>
00390 void extractGRSDSignature325(pcl::VoxelGrid<T> grid, pcl::PointCloud<T> cloud, pcl::PointCloud<T> cloud_downsampled, std::vector<float> &feature, const float voxel_size, const bool is_normalize  ){
00391   std::vector< std::vector<float> > tmp( 1 );
00392   extractGRSDSignature325( grid, cloud, cloud_downsampled, tmp, voxel_size, 0, 0, 0, 0, is_normalize ); // for one signature
00393   feature = tmp[ 0 ];
00394 }
00395 
00396 //-----------------------------------
00397 //* extract - PlusGRSD -
00398 template <typename T>
00399 Eigen::Vector3i extractPlusGRSDSignature110(pcl::VoxelGrid<T> grid, pcl::PointCloud<T> cloud, pcl::PointCloud<T> cloud_downsampled, std::vector< std::vector<float> > &feature, const float voxel_size, const int subdivision_size = 0, const int offset_x = 0, const int offset_y = 0, const int offset_z = 0, const bool is_normalize  ){
00400 #ifndef QUIET
00401   ROS_INFO("rsd %f, normals %f, leaf %f", rsd_radius_search, normals_radius_search, voxel_size);
00402 #endif
00403   feature.resize( 0 );
00404   boost::shared_ptr< const pcl::PointCloud<T> > cloud_downsampled_ptr;
00405   cloud_downsampled_ptr.reset (new pcl::PointCloud<T> (cloud_downsampled));
00406   
00407   //* for computing multiple GRSD with subdivisions
00408   int hist_num = 1;
00409   float inverse_subdivision_size = 0;
00410   Eigen::Vector3i div_b_= Eigen::Vector3i::Zero();
00411   Eigen::Vector3i min_b_= Eigen::Vector3i::Zero();
00412   Eigen::Vector3i subdiv_b_= Eigen::Vector3i::Zero();
00413   Eigen::Vector3i subdivb_mul_= Eigen::Vector3i::Zero();
00414   if( subdivision_size > 0 ){
00415     inverse_subdivision_size = 1.0 / subdivision_size;
00416     div_b_ = grid.getNrDivisions();
00417     min_b_ = grid.getMinBoxCoordinates();
00418     if( ( div_b_[0] <= offset_x ) || ( div_b_[1] <= offset_y ) || ( div_b_[2] <= offset_z ) ){
00419       std::cerr << "(In extractPlusGRSDSignature110) offset values (" << offset_x << "," << offset_y << "," << offset_z << ") exceed voxel grid size (" << div_b_[0] << "," << div_b_[1] << "," << div_b_[2] << ")."<< std::endl;
00420       return Eigen::Vector3i::Zero();
00421     }
00422     subdiv_b_ = Eigen::Vector3i ( ceil( ( div_b_[0] - offset_x )*inverse_subdivision_size ), ceil( ( div_b_[1] - offset_y )*inverse_subdivision_size ), ceil( ( div_b_[2] - offset_z )*inverse_subdivision_size ) );
00423     subdivb_mul_ = Eigen::Vector3i ( 1, subdiv_b_[0], subdiv_b_[0] * subdiv_b_[1] );
00424     hist_num = subdiv_b_[0] * subdiv_b_[1] * subdiv_b_[2];
00425   }
00426   else if( subdivision_size < 0 ){
00427     std::cerr << "(In extractPlusGRSDSignature110) Invalid subdivision size: " << subdivision_size << std::endl;
00428     return Eigen::Vector3i::Zero();
00429   }
00430 
00431   // Compute RSD
00432   pcl::RSDEstimation <T, T, pcl::PrincipalRadiiRSD> rsd;
00433   rsd.setInputCloud( cloud_downsampled_ptr );
00434   boost::shared_ptr< const pcl::PointCloud<T> > cloud_ptr = cloud.makeShared();
00435   rsd.setSearchSurface( cloud_ptr );
00436   rsd.setInputNormals( cloud_ptr );
00437 #ifndef QUIET
00438   ROS_INFO("radius search: %f", std::max(rsd_radius_search, voxel_size/2 * sqrt(3)));
00439 #endif
00440   rsd.setRadiusSearch(std::max(rsd_radius_search, voxel_size/2 * sqrt(3)));
00441   boost::shared_ptr< pcl::KdTree<T> > tree2 = boost::make_shared<pcl::KdTreeFLANN<T> > ();
00442   tree2->setInputCloud (cloud.makeShared());
00443   rsd.setSearchMethod(tree2);
00444   pcl::PointCloud<pcl::PrincipalRadiiRSD> radii;
00445   t1 = my_clock();
00446   rsd.compute(radii);
00447 #ifndef QUIET
00448   ROS_INFO("RSD compute done in %f seconds.", my_clock()-t1);
00449   pcl::io::savePCDFile ("hoge.pcd", cloud_downsampled, false);
00450 #endif
00451   
00452   // Get rmin/rmax for adjacent 27 voxel
00453   t1 = my_clock();
00454   Eigen::MatrixXi relative_coordinates (3, 13);
00455 
00456   int idx = 0;
00457   
00458   // 0 - 8
00459   for( int i=-1; i<2; i++ )
00460   {
00461     for( int j=-1; j<2; j++ )
00462     {
00463       relative_coordinates( 0, idx ) = i;
00464       relative_coordinates( 1, idx ) = j;
00465       relative_coordinates( 2, idx ) = -1;
00466       idx++;
00467     }
00468   }
00469   // 9 - 11
00470   for( int i=-1; i<2; i++ )
00471   {
00472     relative_coordinates( 0, idx ) = i;
00473     relative_coordinates( 1, idx ) = -1;
00474     relative_coordinates( 2, idx ) = 0;
00475     idx++;
00476   }
00477   // 12
00478   relative_coordinates( 0, idx ) = -1;
00479   relative_coordinates( 1, idx ) = 0;
00480   relative_coordinates( 2, idx ) = 0;
00481 
00482   Eigen::MatrixXi relative_coordinates_all (3, 26);
00483   relative_coordinates_all.block<3, 13>(0, 0) = relative_coordinates;
00484   relative_coordinates_all.block<3, 13>(0, 13) = -relative_coordinates;
00485 
00486   // Get transition matrix
00487   std::vector<int> types (radii.points.size());
00488  
00489   for (size_t idx = 0; idx < radii.points.size (); ++idx)
00490     types[idx] = getType(radii.points[idx].r_min, radii.points[idx].r_max);
00491   
00492   // TODO voxelization does not re-normalize the normals!
00493   for (size_t idx = 0; idx < cloud_downsampled_ptr->points.size (); ++idx)
00494     cloud_downsampled.points[idx].getNormalVector3fMap ().normalize ();
00495 
00496   // TODO use consts and iterators
00497   std::vector<Eigen::MatrixXi> transition_matrix_list (hist_num * NR_DIV, Eigen::MatrixXi::Zero (NR_CLASS, NR_CLASS));
00498   std::vector<Eigen::VectorXi> transitions_to_empty( hist_num, Eigen::VectorXi::Zero (NR_CLASS));
00499 
00500   for (size_t idx = 0; idx < cloud_downsampled_ptr->points.size (); ++idx)
00501   {
00502     // calc hist_idx
00503     int hist_idx;
00504     if( hist_num == 1 ) hist_idx = 0;
00505     else{
00506       const int tmp_x = floor( cloud_downsampled_ptr->points[ idx ].x/voxel_size ) - min_b_[ 0 ] - offset_x;
00507       const int tmp_y = floor( cloud_downsampled_ptr->points[ idx ].y/voxel_size ) - min_b_[ 1 ] - offset_y;
00508       const int tmp_z = floor( cloud_downsampled_ptr->points[ idx ].z/voxel_size ) - min_b_[ 2 ] - offset_z;
00509       /* const int x_mul_y = div_b_[0] * div_b_[1]; */
00510       /* const int tmp_z = idx / x_mul_y - offset_z; */
00511       /* const int tmp_y = ( idx % x_mul_y ) / div_b_[0] - offset_y; */
00512       /* const int tmp_x = idx % div_b_[0] - offset_x; */
00513       if( ( tmp_x < 0 ) || ( tmp_y < 0 ) || ( tmp_z < 0 ) ) continue; // ignore idx smaller than offset.
00514       Eigen::Vector3i ijk = Eigen::Vector3i ( floor ( tmp_x * inverse_subdivision_size), floor ( tmp_y * inverse_subdivision_size), floor ( tmp_z * inverse_subdivision_size) );
00515       hist_idx = ijk.dot (subdivb_mul_);
00516     }
00517 
00518     int source_type = types[idx];
00519     std::vector<int> neighbors = grid.getNeighborCentroidIndices ( cloud_downsampled_ptr->points[idx], relative_coordinates_all);
00520     Eigen::Vector3f source_normal = cloud_downsampled.points[idx].getNormalVector3fMap ();
00521     if( std::isfinite( cloud_downsampled.points[idx].normal_x ) && std::isfinite( cloud_downsampled.points[idx].normal_y ) && std::isfinite( cloud_downsampled.points[idx].normal_z ) ){
00522       for (unsigned id_n = 0; id_n < neighbors.size(); id_n++)
00523         {
00524           int neighbor_type;
00525           if (neighbors[id_n] == -1)
00526             neighbor_type = EMPTY;
00527           else
00528             neighbor_type = types[neighbors[id_n]];
00529           
00530           // count transitions: TODO optimize Asako style :)  but what about empty?
00531           if (neighbors[id_n] == -1)
00532             transitions_to_empty[ hist_idx ](source_type)++;
00533           else{
00534             // compute angle between average normals of voxels
00535             assert (source_type != EMPTY);
00536             //        double sine = source_normal.cross (cloud_downsampled.points[neighbors[id_n]].getNormalVector3fMap ()).norm ();
00537             //        int angle_bin = std::min (NR_DIV-1, (int) floor (sine * NR_DIV));
00538             //        transition_matrix_list[angle_bin](source_type, neighbor_type)++;
00539             //std::cout << cloud_downsampled.points[neighbors[id_n]].getNormalVector3fMap () << std::endl;
00540             //std::cout << cloud_downsampled.points[neighbors[id_n]].normal_x << " " << cloud_downsampled.points[neighbors[id_n]].normal_y << " " << cloud_downsampled.points[neighbors[id_n]].normal_z << std::endl;
00541             if( std::isfinite( cloud_downsampled.points[neighbors[id_n]].normal_x ) && std::isfinite( cloud_downsampled.points[neighbors[id_n]].normal_y ) && std::isfinite( cloud_downsampled.points[neighbors[id_n]].normal_z ) ) 
00542               transition_matrix_list[ (std::min (NR_DIV-1, (int) floor (sqrt (source_normal.cross (cloud_downsampled.points[neighbors[id_n]].getNormalVector3fMap ()).norm ()) * NR_DIV)) )*hist_num + hist_idx ](source_type, neighbor_type)++;
00543             else
00544               transitions_to_empty[ hist_idx ](source_type)++;
00545             //        double unsigned_cosine = fabs(source_normal.dot (cloud_downsampled.points[neighbors[id_n]].getNormalVector3fMap ()));
00546             //        if (unsigned_cosine > 1) unsigned_cosine = 1;
00547             //        int angle_bin = std::min (NR_DIV-1, (int) floor (acos (unsigned_cosine) / unit_angle));
00548             //std::cerr << "angle difference = " << acos (unsigned_cosine) << "(" << unsigned_cosine << ") => index: " << angle_bin << std::endl;
00549           }
00550         }
00551     }
00552   }
00553 
00554 #ifndef QUIET
00555   std::cerr << "List of transition matrices by normal angle:" << std::endl;
00556   std::copy (transition_matrix_list.begin (), transition_matrix_list.end (), std::ostream_iterator<Eigen::MatrixXi> (std::cerr, "\n---\n"));  
00557   for( int h=0; h<hist_num; h++ )
00558     std::cerr << "Transitions to empty: " << transitions_to_empty[h].transpose () << std::endl;
00559 #endif
00560 
00561   pcl::PointCloud<pcl::PlusGRSDSignature110> cloud_grsd;
00562   cloud_grsd.points.resize(hist_num);
00563 
00564   for( int h=0; h<hist_num; h++ ){  
00565     int nrf = 0;
00566 
00567     for ( int d=0; d<NR_DIV; d++ )
00568       {
00569         for (int i=0; i<NR_CLASS; i++)
00570           for (int j=i; j<NR_CLASS; j++)
00571             cloud_grsd.points[h].histogram[nrf++] = transition_matrix_list[ d * hist_num + h ](i, j);
00572       }
00573     for (int it = 0; it < NR_CLASS; ++it)
00574       cloud_grsd.points[h].histogram[nrf++] = transitions_to_empty[ h ][it];
00575     //std::cerr << std::endl;
00576 
00577 #ifndef QUIET
00578     std::cerr << "PlusGRSDS: " << cloud_grsd.points[0] << std::endl;
00579 #endif
00580   }
00581 
00582 #ifndef QUIET
00583   ROS_INFO("GRSD compute done in %f seconds.", my_clock()-t1);
00584 #endif
00585 
00586   feature.resize( hist_num );
00587   if( is_normalize ){
00588     for( int h=0; h<hist_num; h++ ){
00589       feature[ h ].resize( 110 );
00590       for( int i=0; i<110; i++)
00591         feature[ h ][ i ] = cloud_grsd.points[ h ].histogram[ i ] * NORMALIZE_GRSD;
00592     }
00593   }
00594   else{
00595     for( int h=0; h<hist_num; h++ ){
00596       feature[ h ].resize( 110 );
00597       for( int i=0; i<110; i++)
00598         feature[ h ][ i ] = cloud_grsd.points[ h ].histogram[ i ];
00599     }
00600   }
00601   return subdiv_b_;
00602 }
00603 
00604 template <typename T>
00605 void extractPlusGRSDSignature110(pcl::VoxelGrid<T> grid, pcl::PointCloud<T> cloud, pcl::PointCloud<T> cloud_downsampled, std::vector<float> &feature, const float voxel_size, const bool is_normalize  ){
00606   std::vector< std::vector<float> > tmp( 1 );
00607   extractPlusGRSDSignature110( grid, cloud, cloud_downsampled, tmp, voxel_size, 0, 0, 0, 0, is_normalize ); // for one signature
00608   feature = tmp[ 0 ];
00609 }
00610 
00611 //--------------
00612 //* concatenate
00613 const std::vector<float> concVector( const std::vector<float> v1, const std::vector<float> v2 ){
00614   std::vector<float> vec = v1;
00615   vec.insert(vec.end(), v2.begin(), v2.end());
00616   return vec;
00617 }
00618 
00619 //--------------
00620 //* VOSCH
00621 template <typename PointT>
00622 Eigen::Vector3i extractVOSCH(pcl::VoxelGrid<PointT> grid, pcl::PointCloud<PointT> cloud, pcl::PointCloud<PointT> cloud_downsampled, std::vector< std::vector<float> > &feature, int color_threshold_r, int color_threshold_g, int color_threshold_b, const float voxel_size, const int subdivision_size = 0, const int offset_x = 0, const int offset_y = 0, const int offset_z = 0, const bool is_normalize  ){
00623   std::vector< std::vector<float> > grsd;
00624   Eigen::Vector3i subdiv_b_ = extractGRSDSignature21( grid, cloud, cloud_downsampled, grsd, voxel_size, subdivision_size, offset_x, offset_y, offset_z, is_normalize );
00625   std::vector< std::vector<float> > c3_hlac;
00626   extractC3HLACSignature117( grid, cloud_downsampled, c3_hlac, color_threshold_r, color_threshold_g, color_threshold_b, voxel_size, subdivision_size, offset_x, offset_y, offset_z );
00627 
00628   const int hist_num = grsd.size();
00629   for( int h=0; h<hist_num; h++ )
00630     feature.push_back ( concVector( grsd[ h ], c3_hlac[ h ] ) );
00631   return subdiv_b_;
00632 }
00633 
00634 template <typename PointT>
00635 void extractVOSCH(pcl::VoxelGrid<PointT> grid, pcl::PointCloud<PointT> cloud, pcl::PointCloud<PointT> cloud_downsampled, std::vector<float> &feature, int color_threshold_r, int color_threshold_g, int color_threshold_b, const float voxel_size, const int subdivision_size = 0, const int offset_x = 0, const int offset_y = 0, const int offset_z = 0 ){
00636   std::vector< std::vector<float> > tmp;
00637   extractVOSCH( grid, cloud, cloud_downsampled, tmp, color_threshold_r, color_threshold_g, color_threshold_b, voxel_size ); // for one signature
00638   feature = tmp[ 0 ];
00639 }
00640 
00641 //--------------
00642 //* ConVOSCH
00643 template <typename PointT>
00644 Eigen::Vector3i extractConVOSCH(pcl::VoxelGrid<PointT> grid, pcl::PointCloud<PointT> cloud, pcl::PointCloud<PointT> cloud_downsampled, std::vector< std::vector<float> > &feature, int color_threshold_r, int color_threshold_g, int color_threshold_b, const float voxel_size, const int subdivision_size = 0, const int offset_x = 0, const int offset_y = 0, const int offset_z = 0, const bool is_normalize  ){
00645   std::vector< std::vector<float> > grsd;
00646   Eigen::Vector3i subdiv_b_ = extractGRSDSignature21( grid, cloud, cloud_downsampled, grsd, voxel_size, subdivision_size, offset_x, offset_y, offset_z, is_normalize );
00647   std::vector< std::vector<float> > c3_hlac;
00648   extractC3HLACSignature981( grid, cloud_downsampled, c3_hlac, color_threshold_r, color_threshold_g, color_threshold_b, voxel_size, subdivision_size, offset_x, offset_y, offset_z );
00649 
00650   const int hist_num = grsd.size();
00651   for( int h=0; h<hist_num; h++ )
00652     feature.push_back ( concVector( grsd[ h ], c3_hlac[ h ] ) );
00653   return subdiv_b_;
00654 }
00655 
00656 template <typename PointT>
00657 void extractConVOSCH(pcl::VoxelGrid<PointT> grid, pcl::PointCloud<PointT> cloud, pcl::PointCloud<PointT> cloud_downsampled, std::vector<float> &feature, int color_threshold_r, int color_threshold_g, int color_threshold_b, const float voxel_size, const int subdivision_size = 0, const int offset_x = 0, const int offset_y = 0, const int offset_z = 0 ){
00658   std::vector< std::vector<float> > tmp;
00659   extractConVOSCH( grid, cloud, cloud_downsampled, tmp, color_threshold_r, color_threshold_g, color_threshold_b, voxel_size ); // for one signature
00660   feature = tmp[ 0 ];
00661 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


vosch
Author(s): Asako Kanezaki
autogenerated on Sun Oct 6 2013 12:06:15