00001 #include "normal_descriptor_alg.h"
00002
00003 #define PI 3.1415926535
00004
00005
00006
00007 inline
00008 int get_bin(float x, float y, std::vector<float> &bin_boundsX, std::vector<float> &bin_boundsY)
00009 {
00010 int row=0;
00011 int col=0;
00012 int nb=bin_boundsX.size();
00013
00014
00015
00016 for(int i=0;i<nb;i++)
00017 {
00018 if(x<bin_boundsX[i] && y<bin_boundsY[i])
00019 break;
00020 if(x>bin_boundsX[i])
00021 col++;
00022 if(y>bin_boundsY[i])
00023 row+=nb;
00024 }
00025 return row+col;
00026 }
00027
00028
00029 NormalDescriptorAlgorithm::NormalDescriptorAlgorithm()
00030 {
00031
00032 this->desc_num_side_spatial_bins_ = 1;
00033 this->desc_num_orient_bins_ = 24;
00034 this->desc_patch_radius_=15;
00035
00036
00037 this->set_desc_patch_radius(15);
00038
00039
00040 this->set_num_side_spatial_bins(1);
00041
00042
00043 this->set_num_orientation_bins(24);
00044
00045
00046
00047
00048 this->sample_each_ = 1;
00049 }
00050
00051 NormalDescriptorAlgorithm::~NormalDescriptorAlgorithm()
00052 {
00053 }
00054
00055 void NormalDescriptorAlgorithm::config_update(const Config& new_cfg, uint32_t level)
00056 {
00057 this->lock();
00058
00059 if(this->config_.num_spatial_bins != new_cfg.num_spatial_bins)
00060 {
00061 this->set_num_side_spatial_bins(new_cfg.num_spatial_bins);
00062 }
00063 if(this->config_.num_orientation_bins != new_cfg.num_orientation_bins)
00064 {
00065 this->set_num_orientation_bins(new_cfg.num_orientation_bins);
00066 }
00067 if(this->config_.desc_patch_radius != new_cfg.desc_patch_radius)
00068 {
00069 this->set_desc_patch_radius(new_cfg.desc_patch_radius);
00070 }
00071 if(this->config_.sample_each != new_cfg.sample_each)
00072 {
00073 this->set_sample_each(new_cfg.sample_each);
00074 }
00075
00076
00077 this->config_=new_cfg;
00078
00079 this->unlock();
00080 }
00081
00082
00083
00084 void NormalDescriptorAlgorithm::compute_spherical_coords(pcl::PointCloud<pcl::Normal> &pcl_normal, pcl::PointCloud<pcl::PointXY> &pcl_spherical)
00085 {
00086 for (size_t i = 0; i < pcl_normal.points.size (); ++i)
00087 {
00088 pcl_spherical.points[i].x = acos(pcl_normal.points[i].normal[2]);
00089 pcl_spherical.points[i].y = atan2(pcl_normal.points[i].normal[1], pcl_normal.points[i].normal[0]);
00090
00091 }
00092 }
00093
00094 class II
00095 {
00096 public:
00097 std::vector<unsigned int*> ii_;
00098 unsigned int bins_;
00099 unsigned int width_;
00100 unsigned int height_;
00101
00102
00103 II(unsigned int bins, unsigned int width, unsigned int height):bins_(bins),width_(width),height_(height){
00104 ii_.resize(bins);
00105 for(unsigned int i=0;i<bins;i++)
00106 ii_[i]=new unsigned int[width*height];
00107 }
00108 ~II(){
00109 for(unsigned int i=0;i<this->bins_;i++)
00110 delete [] ii_[i];
00111 }
00112 void construct(std::vector<unsigned int> &im){
00113
00114 unsigned int u=0;
00115 unsigned int v=0;
00116 for(unsigned int b=0;b<this->bins_;b++)
00117 {
00118
00119 ii_[b][this->width_*v+u] = \
00120 (im[this->width_*v+u]==b ? 1:0);
00121 }
00122
00123
00124 v=0;
00125 for(u=1;u<this->width_;u++)
00126 {
00127 for(unsigned int b=0;b<this->bins_;b++)
00128 {
00129
00130 ii_[b][this->width_*v+u] = \
00131 ii_[b][this->width_*v+(u-1)] + \
00132 (im[this->width_*v+u]==b ? 1:0);
00133
00134 }
00135 }
00136
00137
00138 u=0;
00139 for(v=1;v<this->height_;v++)
00140 {
00141 for(unsigned int b=0;b<this->bins_;b++)
00142 {
00143
00144 ii_[b][this->width_*v+u] = \
00145 ii_[b][this->width_*(v-1)+u] + \
00146 (im[this->width_*v+u]==b ? 1:0);
00147
00148 }
00149 }
00150
00151 for(v=1;v<this->height_;v++)
00152 {
00153 for(u=1;u<this->width_;u++)
00154 {
00155 for(unsigned int b=0;b<this->bins_;b++)
00156 {
00157
00158 ii_[b][this->width_*v+u] = \
00159 ii_[b][this->width_*(v-1)+u] + \
00160 ii_[b][this->width_*v+(u-1)] - \
00161 ii_[b][this->width_*(v-1)+(u-1)] + \
00162 (im[this->width_*v+u]==b ? 1:0);
00163
00164 }
00165 }
00166 }
00167 }
00168 std::vector<unsigned int> get_sub_rect(unsigned int tu, unsigned int tv, unsigned int bu, unsigned int bv)
00169 {
00170 std::vector<unsigned int> ret(this->bins_);
00171 for(unsigned int b=0;b<this->bins_;b++)
00172 {
00173 ret[b] = ii_[b][this->width_*tv+tu] + ii_[b][this->width_*bv+bu] - ii_[b][this->width_*tv+bu] - ii_[b][this->width_*bv+tu];
00174 }
00175 return ret;
00176 }
00177 };
00178
00179
00180
00181
00182
00183
00184
00185 void NormalDescriptorAlgorithm::compute_ndescs_integral_spatial(pcl::PointCloud<pcl::PointXYZ>& cloud, normal_descriptor_node::ndesc_pc &ndesc_pc_msg)
00186 {
00187
00188 ROS_INFO("PointCloud received");
00189
00190
00191
00192 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimator;
00193 pcl::PointCloud<pcl::Normal> pcl_normals;
00194 normal_estimator.setInputCloud(boost::make_shared<pcl::PointCloud<pcl::PointXYZ> > (cloud));
00195 normal_estimator.setKSearch (20);
00196 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
00197
00198 normal_estimator.setSearchMethod (tree);
00199 normal_estimator.compute (pcl_normals);
00200
00201
00202 pcl::PointCloud<pcl::PointXY> pcl_spherical;
00203 pcl_spherical.width = cloud.width;
00204 pcl_spherical.height = cloud.height;
00205 pcl_spherical.points.resize (pcl_spherical.width * pcl_spherical.height);
00206 this->compute_spherical_coords(pcl_normals, pcl_spherical);
00207
00208
00209 ndesc_pc_msg.descriptors.clear();
00210 ndesc_pc_msg.len = this->desc_num_total_bins_;
00211 ndesc_pc_msg.width = pcl_spherical.width;
00212 ndesc_pc_msg.height = pcl_spherical.height;
00213 ndesc_pc_msg.num_orient_bins = this->desc_num_orient_bins_;
00214 ndesc_pc_msg.num_spa_bins = this->desc_num_side_spatial_bins_;
00215
00216 std::vector<unsigned int> binned(cloud.width*cloud.height);
00217
00218 for(uint v=0;v<cloud.height;v++)
00219 {
00220 for(uint u=0;u<cloud.width;u++)
00221 {
00222 if(isnan(pcl_spherical(u,v).x) || isnan(pcl_spherical(u,v).y))
00223 binned[u+cloud.width*v]=-1;
00224 else
00225 binned[u+cloud.width*v]=get_bin(pcl_spherical(u,v).x, pcl_spherical(u,v).y, this->orient_bin_boundsX_, this->orient_bin_boundsY_);
00226 }
00227 }
00228
00229 II intim(this->desc_num_orient_bins_*this->desc_num_orient_bins_, cloud.width, cloud.height);
00230 intim.construct(binned);
00231
00232 unsigned int spatial_bin_size = (2*this->desc_patch_radius_+1)/this->desc_num_side_spatial_bins_;
00233 unsigned int spatial_bin_orients = this->desc_num_orient_bins_*this->desc_num_orient_bins_;
00234
00235 for(unsigned int v=this->desc_patch_radius_;v<cloud.height-this->desc_patch_radius_-1;v+=this->sample_each_)
00236 {
00237 for(unsigned int u=this->desc_patch_radius_;u<cloud.width-this->desc_patch_radius_-1;u+=this->sample_each_)
00238 {
00239
00240
00241
00242 normal_descriptor_node::ndesc desc;
00243
00244 desc.point3d.x=cloud(u,v).x;
00245 desc.point3d.y=cloud(u,v).y;
00246 desc.point3d.z=cloud(u,v).z;
00247
00248
00249 desc.u=u;
00250 desc.v=v;
00251
00252 desc.descriptor.resize(this->desc_num_total_bins_);
00253
00254 float total_votes=0;
00255
00256 unsigned int absolute_top = v-this->desc_patch_radius_;
00257
00258 unsigned int absolute_left = u-this->desc_patch_radius_;
00259
00260
00261
00262 for(unsigned int k=0;k<this->desc_num_side_spatial_bins_; k++)
00263 {
00264 unsigned int bound_left = absolute_left + k*spatial_bin_size;
00265 unsigned int bound_right = absolute_left + (k+1)*spatial_bin_size;
00266 for(unsigned int l=0; l<this->desc_num_side_spatial_bins_; l++)
00267 {
00268 unsigned int bound_top = absolute_top + l*spatial_bin_size;
00269 unsigned int bound_bottom = absolute_top + (l+1)*spatial_bin_size;
00270
00271
00272 std::vector<unsigned int> tmp = intim.get_sub_rect(bound_left, bound_top, bound_right, bound_bottom);
00273 for(unsigned int i=0;i<spatial_bin_orients;i++)
00274 {
00275 unsigned int offset_full_rows = l*this->desc_num_side_spatial_bins_*spatial_bin_orients;
00276 unsigned int offset_this_row = k*spatial_bin_orients;
00277 desc.descriptor[offset_full_rows + offset_this_row + i]=tmp[i];
00278 total_votes+=tmp[i];
00279 }
00280
00281
00282
00283
00284 }
00285 }
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298 ndesc_pc_msg.descriptors.push_back(desc);
00299 ndesc_pc_msg.num++;
00300
00301 }
00302 }
00303 ROS_INFO("Computed %d descriptors", ndesc_pc_msg.num);
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322 }
00323
00324
00325
00326
00327
00328 void NormalDescriptorAlgorithm::compute_descriptor_spatial_rot_inv(pcl::PointCloud<pcl::PointXYZ> &cloud, normal_descriptor_node::ndesc_pc &ndesc_pc_msg)
00329 {
00330
00331
00332
00333 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimator;
00334 pcl::PointCloud<pcl::Normal> pcl_normals;
00335 normal_estimator.setInputCloud(boost::make_shared<pcl::PointCloud<pcl::PointXYZ> > (cloud));
00336 normal_estimator.setKSearch (20);
00337
00338 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);
00339
00340 normal_estimator.setSearchMethod (tree);
00341 normal_estimator.compute (pcl_normals);
00342
00343
00344 pcl::PointCloud<pcl::PointXY> pcl_spherical;
00345 pcl_spherical.width = cloud.width;
00346 pcl_spherical.height = cloud.height;
00347 pcl_spherical.points.resize (pcl_spherical.width * pcl_spherical.height);
00348 this->compute_spherical_coords(pcl_normals, pcl_spherical);
00349
00350 for(unsigned int v=this->desc_patch_radius_;v<cloud.height-this->desc_patch_radius_;v+=this->sample_each_)
00351 {
00352 for(unsigned int u=this->desc_patch_radius_;u<cloud.width-this->desc_patch_radius_;u+=this->sample_each_)
00353 {
00354 ndesc_pc_msg.descriptors.push_back(this->compute_descriptor_one_spatial_rot_inv(cloud, pcl_spherical, u, v));
00355 ndesc_pc_msg.num++;
00356 }
00357 }
00358 ROS_INFO("Computed %d descriptors", ndesc_pc_msg.num);
00359 }
00360
00361
00362 normal_descriptor_node::ndesc NormalDescriptorAlgorithm::compute_descriptor_one_spatial_rot_inv(pcl::PointCloud<pcl::PointXYZ> &cloud, pcl::PointCloud<pcl::PointXY> &pcl_spherical, uint u, uint v)
00363 {
00364
00365 normal_descriptor_node::ndesc desc;
00366
00367 desc.point3d.x = cloud(u,v).x;
00368 desc.point3d.y = cloud(u,v).y;
00369 desc.point3d.z = cloud(u,v).z;
00370
00371
00372 desc.u = u;
00373 desc.v = v;
00374
00375
00376
00377
00378
00379 int nbins = 36;
00380 float orientation[36];
00381
00382 memset(orientation, 0, sizeof(float)*36);
00383
00384 int absolute_top = v-this->desc_patch_radius_;
00385 int absolute_bottom = v+this->desc_patch_radius_;
00386 int absolute_left = u-this->desc_patch_radius_;
00387 int absolute_right = u+this->desc_patch_radius_;
00388 for(int j=absolute_top;j<absolute_bottom;j++)
00389 {
00390 for(int i=absolute_left;i<absolute_right;i++)
00391 {
00392 if(isnan(pcl_spherical(i,j).y))
00393 continue;
00394 int bin = floor(nbins*(PI+pcl_spherical(i,j).y)/(2*PI));
00395
00396 orientation[bin]+=1;
00397 }
00398 }
00399
00400
00401 int max_ori=0;
00402 float max_val=0;
00403 for(int ii=0;ii<nbins;ii++)
00404 {
00405
00406 if(max_val<orientation[ii])
00407 {
00408
00409 max_val=orientation[ii];
00410 max_ori=ii;
00411 }
00412 }
00413
00414
00415 float ori=float(max_ori)/float(nbins)*2*PI-PI;
00416 desc.ori=ori;
00417
00418
00419
00420
00421
00422
00423 desc.descriptor.resize(this->desc_num_total_bins_);
00424
00425
00426
00427
00428 int size_bin = (2*this->desc_patch_radius_+1)/this->desc_num_side_spatial_bins_;
00429
00430 for(uint k=0; k<this->desc_num_side_spatial_bins_; k++)
00431 {
00432 uint bound_left = absolute_left + k*size_bin;
00433 uint bound_right = absolute_left + (k+1)*size_bin;
00434 for(uint l=0; l<this->desc_num_side_spatial_bins_; l++)
00435 {
00436 uint bound_top = absolute_top + l*size_bin;
00437 uint bound_bottom = absolute_top + (l+1)*size_bin;
00438 for(uint i=bound_left; i<=bound_right; i++)
00439 {
00440 for (uint j=bound_top; j<=bound_bottom; j++)
00441 {
00442
00443 int i_s = (int)round( (cos(ori)*(i-u) - sin(ori)*(j-v)) + u);
00444 int j_s = (int)round( (sin(ori)*(i-u) + cos(ori)*(j-v)) + v);
00445
00446
00447 if((i_s<0) || (j_s<0) || (i_s>=cloud.width) || (j_s>=cloud.height))
00448 continue;
00449
00450
00451 if(isnan(pcl_spherical(i_s,j_s).x) || isnan(pcl_spherical(i_s,j_s).y))
00452 continue;
00453
00454
00455
00456
00457 uint offset = (l*this->desc_num_side_spatial_bins_+k) * this->desc_num_orient_bins_;
00458 float anglemod2pi=(pcl_spherical(i_s,j_s).y+PI)-(ori+PI);
00459 while(anglemod2pi<0){
00460
00461 anglemod2pi+=2*PI;
00462 }
00463 anglemod2pi-=PI;
00464 uint bin = get_bin(pcl_spherical(i_s,j_s).x, anglemod2pi, this->orient_bin_boundsX_,this->orient_bin_boundsY_);
00465
00466
00467
00468
00469
00470
00471
00472
00473 desc.descriptor[bin+offset]++;
00474 }
00475 }
00476 }
00477 }
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 return desc;
00491 }