00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00040 #include <iostream>
00041 using std::cout;
00042 using std::cerr;
00043 #include <map>
00044 #include <set>
00045 #include <cmath>
00046 #include <Eigen/Geometry>
00047 #include <pcl/pcl_macros.h>
00048 #include <pcl/common/common_headers.h>
00049 #include <pcl/range_image/range_image.h>
00050 #include <pcl/point_cloud.h>
00051 #include <pcl/common/vector_average.h>
00052 #include <pcl/features/range_image_border_extractor.h>
00053
00054 #define USE_OMP 1
00055
00056 namespace pcl {
00057
00058 RangeImageBorderExtractor::RangeImageBorderExtractor(const RangeImage* range_image) : BaseClass(), range_image_(range_image),
00059 border_scores_left_(NULL), border_scores_right_(NULL), border_scores_top_(NULL), border_scores_bottom_(NULL),
00060 surface_structure_(NULL), border_descriptions_(NULL), shadow_border_informations_(NULL), border_directions_(NULL),
00061 surface_change_scores_(NULL), surface_change_directions_(NULL)
00062 {
00063 }
00064
00065 RangeImageBorderExtractor::~RangeImageBorderExtractor()
00066 {
00067 clearData();
00068 }
00069
00070 void RangeImageBorderExtractor::setRangeImage(const RangeImage* range_image)
00071 {
00072 clearData();
00073 range_image_ = range_image;
00074 }
00075
00076 void RangeImageBorderExtractor::clearData()
00077 {
00078
00079
00080 delete[] border_scores_left_; border_scores_left_ = NULL;
00081 delete[] border_scores_right_; border_scores_right_ = NULL;
00082 delete[] border_scores_top_; border_scores_top_ = NULL;
00083 delete[] border_scores_bottom_; border_scores_bottom_ = NULL;
00084 if (range_image_==NULL)
00085 {
00086 if (surface_structure_!=NULL || shadow_border_informations_!=NULL || border_directions_!=NULL)
00087 std::cerr << __PRETTY_FUNCTION__ << ": Can't erase elements of surface_structure_ since range_image_ is NULL.\n";
00088 }
00089 else
00090 {
00091 for (int i=0; i<int(range_image_->width*range_image_->height); ++i)
00092 {
00093 if (surface_structure_!=NULL)
00094 delete surface_structure_[i];
00095 if (shadow_border_informations_!=NULL)
00096 delete shadow_border_informations_[i];
00097 if (border_directions_!=NULL)
00098 delete border_directions_[i];
00099 }
00100 }
00101 delete[] surface_structure_; surface_structure_ = NULL;
00102 delete border_descriptions_; border_descriptions_ = NULL;
00103 delete[] shadow_border_informations_; shadow_border_informations_ = NULL;
00104 delete[] border_directions_; border_directions_ = NULL;
00105
00106 delete[] surface_change_scores_; surface_change_scores_ = NULL;
00107 delete[] surface_change_directions_; surface_change_directions_ = NULL;
00108 }
00109
00110 void RangeImageBorderExtractor::extractLocalSurfaceStructure()
00111 {
00112 if (surface_structure_ != NULL)
00113 return;
00114
00115
00116 int width = range_image_->width,
00117 height = range_image_->height,
00118 array_size = width*height;
00119 surface_structure_ = new LocalSurface*[array_size];
00120 int step_size = (std::max)(1, parameters_.pixel_radius_plane_extraction/2);
00121
00122 int no_of_nearest_neighbors = pow ((double)(parameters_.pixel_radius_plane_extraction/step_size + 1), 2.0);
00123 # if USE_OMP
00124
00125 # pragma omp parallel for default(shared)
00126 # endif
00127 for (int y=0; y<height; ++y)
00128 {
00129 for (int x=0; x<width; ++x)
00130 {
00131 int index = y*width + x;
00132 LocalSurface*& local_surface = surface_structure_[index];
00133 local_surface = NULL;
00134 if (!range_image_->isValid(index))
00135 continue;
00136 local_surface = new LocalSurface;
00137 Eigen::Vector3f point;
00138 range_image_->getPoint(x, y, point);
00139
00140 if (!range_image_->getSurfaceInformation(x, y, parameters_.pixel_radius_plane_extraction, point,
00141 no_of_nearest_neighbors, step_size, local_surface->max_neighbor_distance_squared,
00142 local_surface->normal_no_jumps, local_surface->neighborhood_mean_no_jumps,
00143 local_surface->eigen_values_no_jumps, &local_surface->normal,
00144 &local_surface->neighborhood_mean, &local_surface->eigen_values))
00145 {
00146 delete local_surface;
00147 local_surface = NULL;
00148 }
00149
00150
00151 }
00152 }
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183 }
00184
00185 void RangeImageBorderExtractor::extractBorderScoreImages()
00186 {
00187 if (border_scores_left_ != NULL)
00188 return;
00189
00190 extractLocalSurfaceStructure();
00191
00192
00193
00194 int width = range_image_->width,
00195 height = range_image_->height,
00196 size = width*height;
00197 border_scores_left_ = new float[size];
00198 border_scores_right_ = new float[size];
00199 border_scores_top_ = new float[size];
00200 border_scores_bottom_ = new float[size];
00201
00202 # if USE_OMP
00203
00204 # pragma omp parallel for default(shared)
00205 # endif
00206 for (int y=0; y<height; ++y) {
00207 for (int x=0; x<width; ++x) {
00208 int index = y*width + x;
00209 float& left=border_scores_left_[index]; float& right=border_scores_right_[index];
00210 float& top=border_scores_top_[index]; float& bottom=border_scores_bottom_[index];
00211 LocalSurface* local_surface_ptr = surface_structure_[index];
00212 if (local_surface_ptr==NULL)
00213 {
00214 left=right=top=bottom = 0.0f;
00215 continue;
00216 }
00217
00218 left = getNeighborDistanceChangeScore(*local_surface_ptr, x, y, -1, 0, parameters_.pixel_radius_borders);
00219 right = getNeighborDistanceChangeScore(*local_surface_ptr, x, y, 1, 0, parameters_.pixel_radius_borders);
00220 top = getNeighborDistanceChangeScore(*local_surface_ptr, x, y, 0, -1, parameters_.pixel_radius_borders);
00221 bottom = getNeighborDistanceChangeScore(*local_surface_ptr, x, y, 0, 1, parameters_.pixel_radius_borders);
00222 }
00223 }
00224 }
00225
00226 float* RangeImageBorderExtractor::updatedScoresAccordingToNeighborValues(const float* border_scores) const
00227 {
00228 float* new_scores = new float[range_image_->width*range_image_->height];
00229 float* new_scores_ptr = new_scores;
00230 for (int y=0; y<(int)range_image_->height; ++y) {
00231 for (int x=0; x<(int)range_image_->width; ++x) {
00232 *(new_scores_ptr++) = updatedScoreAccordingToNeighborValues(x, y, border_scores);
00233 }
00234 }
00235 return new_scores;
00236 }
00237
00238 void RangeImageBorderExtractor::updateScoresAccordingToNeighborValues()
00239 {
00240 extractBorderScoreImages();
00241
00242
00243
00244 float* left_with_propagated_neighbors = updatedScoresAccordingToNeighborValues(border_scores_left_);
00245 delete[] border_scores_left_;
00246 border_scores_left_ = left_with_propagated_neighbors;
00247 float* right_with_propagated_neighbors = updatedScoresAccordingToNeighborValues(border_scores_right_);
00248 delete[] border_scores_right_;
00249 border_scores_right_ = right_with_propagated_neighbors;
00250 float* top_with_propagated_neighbors = updatedScoresAccordingToNeighborValues(border_scores_top_);
00251 delete[] border_scores_top_;
00252 border_scores_top_ = top_with_propagated_neighbors;
00253 float* bottom_with_propagated_neighbors = updatedScoresAccordingToNeighborValues(border_scores_bottom_);
00254 delete[] border_scores_bottom_;
00255 border_scores_bottom_ = bottom_with_propagated_neighbors;
00256 }
00257
00258 void RangeImageBorderExtractor::findAndEvaluateShadowBorders()
00259 {
00260 if (shadow_border_informations_ != NULL)
00261 return;
00262
00263 if (border_scores_left_==NULL)
00264 {
00265 std::cerr << __PRETTY_FUNCTION__<<": border score images not available!\n";
00266 }
00267
00268
00269
00270 int width = range_image_->width,
00271 height = range_image_->height;
00272 shadow_border_informations_ = new ShadowBorderIndices*[width*height];
00273 for (int y=0; y<(int)height; ++y) {
00274 for (int x=0; x<(int)width; ++x) {
00275 int index = y*width+x;
00276 ShadowBorderIndices*& shadow_border_indices = shadow_border_informations_[index];
00277 shadow_border_indices = NULL;
00278 int shadow_border_idx;
00279
00280 if (changeScoreAccordingToShadowBorderValue(x, y, -1, 0, border_scores_left_, border_scores_right_, shadow_border_idx))
00281 {
00282 shadow_border_indices = (shadow_border_indices==NULL ? new ShadowBorderIndices : shadow_border_indices);
00283 shadow_border_indices->left = shadow_border_idx;
00284 }
00285 if (changeScoreAccordingToShadowBorderValue(x, y, 1, 0, border_scores_right_, border_scores_left_, shadow_border_idx))
00286 {
00287 shadow_border_indices = (shadow_border_indices==NULL ? new ShadowBorderIndices : shadow_border_indices);
00288 shadow_border_indices->right = shadow_border_idx;
00289 }
00290 if (changeScoreAccordingToShadowBorderValue(x, y, 0, -1, border_scores_top_, border_scores_bottom_, shadow_border_idx))
00291 {
00292 shadow_border_indices = (shadow_border_indices==NULL ? new ShadowBorderIndices : shadow_border_indices);
00293 shadow_border_indices->top = shadow_border_idx;
00294 }
00295 if (changeScoreAccordingToShadowBorderValue(x, y, 0, 1, border_scores_bottom_, border_scores_top_, shadow_border_idx))
00296 {
00297 shadow_border_indices = (shadow_border_indices==NULL ? new ShadowBorderIndices : shadow_border_indices);
00298 shadow_border_indices->bottom = shadow_border_idx;
00299 }
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 }
00322 }
00323 }
00324
00325 float* RangeImageBorderExtractor::getAnglesImageForBorderDirections()
00326 {
00327
00328
00329 calculateBorderDirections();
00330
00331 int width = range_image_->width,
00332 height = range_image_->height,
00333 array_size = width*height;
00334 float* angles_image = new float[array_size];
00335
00336 for (int y=0; y<height; ++y)
00337 {
00338 for (int x=0; x<width; ++x)
00339 {
00340 int index = y*width + x;
00341 float& angle = angles_image[index];
00342 angle = -std::numeric_limits<float>::infinity ();
00343 const Eigen::Vector3f* border_direction_ptr = border_directions_[index];
00344 if (border_direction_ptr == NULL)
00345 continue;
00346 const Eigen::Vector3f& border_direction = *border_direction_ptr;
00347 const PointWithRange& point = range_image_->getPoint(index);
00348
00349 float border_direction_in_image_x, border_direction_in_image_y;
00350 float tmp_factor = point.range*range_image_->getAngularResolution();
00351 range_image_->getImagePoint(point.x+tmp_factor*border_direction[0], point.y+tmp_factor*border_direction[1], point.z+tmp_factor*border_direction[2],
00352 border_direction_in_image_x, border_direction_in_image_y);
00353 border_direction_in_image_x -= x; border_direction_in_image_y -= y;
00354 angle = atan2(border_direction_in_image_y, border_direction_in_image_x);
00355 }
00356 }
00357 return angles_image;
00358 }
00359
00360 float* RangeImageBorderExtractor::getAnglesImageForSurfaceChangeDirections()
00361 {
00362
00363
00364 calculateSurfaceChanges();
00365
00366 int width = range_image_->width,
00367 height = range_image_->height,
00368 array_size = width*height;
00369 float* angles_image = new float[array_size];
00370
00371 for (int y=0; y<height; ++y)
00372 {
00373 for (int x=0; x<width; ++x)
00374 {
00375 int index = y*width + x;
00376 float& angle = angles_image[index];
00377 angle = -std::numeric_limits<float>::infinity ();
00378 float surface_change_score = surface_change_scores_[index];
00379 if (surface_change_score <= 0.1f)
00380 continue;
00381 const Eigen::Vector3f& direction = surface_change_directions_[index];
00382 const PointWithRange& point = range_image_->getPoint(index);
00383
00384 float border_direction_in_image_x, border_direction_in_image_y;
00385 float tmp_factor = point.range*range_image_->getAngularResolution();
00386 range_image_->getImagePoint(point.x+tmp_factor*direction[0], point.y+tmp_factor*direction[1], point.z+tmp_factor*direction[2],
00387 border_direction_in_image_x, border_direction_in_image_y);
00388 border_direction_in_image_x -= x; border_direction_in_image_y -= y;
00389 angle = atan2(border_direction_in_image_y, border_direction_in_image_x);
00390
00391
00392 if (angle <= deg2rad(-90.0f))
00393 angle += M_PI;
00394 else if (angle > deg2rad(90.0f))
00395 angle -= M_PI;
00396 }
00397 }
00398 return angles_image;
00399 }
00400
00401
00402
00403 void RangeImageBorderExtractor::classifyBorders()
00404 {
00405 if (border_descriptions_ != NULL)
00406 return;
00407
00408
00409 extractLocalSurfaceStructure();
00410
00411
00412 extractBorderScoreImages();
00413
00414
00415 updateScoresAccordingToNeighborValues();
00416
00417
00418 findAndEvaluateShadowBorders();
00419
00420
00421
00422 int width = range_image_->width,
00423 height = range_image_->height,
00424 size = width*height;
00425
00426 BorderDescription initial_border_description;
00427 initial_border_description.traits = 0;
00428 border_descriptions_ = new PointCloudOut;
00429 border_descriptions_->width = width;
00430 border_descriptions_->height = height;
00431 border_descriptions_->is_dense = true;
00432 border_descriptions_->points.resize(size, initial_border_description);
00433
00434
00435 for (int y=0; y<(int)height; ++y) {
00436 for (int x=0; x<(int)width; ++x) {
00437 int index = y*width+x;
00438 BorderDescription& border_description = border_descriptions_->points[index];
00439 border_description.x = x;
00440 border_description.y = y;
00441 BorderTraits& border_traits = border_description.traits;
00442
00443 ShadowBorderIndices* shadow_border_indices = shadow_border_informations_[index];
00444 if (shadow_border_indices == NULL)
00445 continue;
00446
00447 int shadow_border_index = shadow_border_indices->left;
00448 if (shadow_border_index >= 0 && checkIfMaximum(x, y, -1, 0, border_scores_left_, shadow_border_index))
00449 {
00450 BorderTraits& shadow_traits = border_descriptions_->points[shadow_border_index].traits;
00451 border_traits[BORDER_TRAIT__OBSTACLE_BORDER] = border_traits[BORDER_TRAIT__OBSTACLE_BORDER_LEFT] = true;
00452 shadow_traits[BORDER_TRAIT__SHADOW_BORDER] = shadow_traits[BORDER_TRAIT__SHADOW_BORDER_RIGHT] = true;
00453 for (int index3=index-1; index3>shadow_border_index; --index3)
00454 {
00455 BorderTraits& veil_point = border_descriptions_->points[index3].traits;
00456 veil_point[BORDER_TRAIT__VEIL_POINT] = veil_point[BORDER_TRAIT__VEIL_POINT_RIGHT] = true;
00457 }
00458 }
00459
00460 shadow_border_index = shadow_border_indices->right;
00461 if (shadow_border_index >= 0 && checkIfMaximum(x, y, 1, 0, border_scores_right_, shadow_border_index))
00462 {
00463 BorderTraits& shadow_traits = border_descriptions_->points[shadow_border_index].traits;
00464 border_traits[BORDER_TRAIT__OBSTACLE_BORDER] = border_traits[BORDER_TRAIT__OBSTACLE_BORDER_RIGHT] = true;
00465 shadow_traits[BORDER_TRAIT__SHADOW_BORDER] = shadow_traits[BORDER_TRAIT__SHADOW_BORDER_LEFT] = true;
00466 for (int index3=index+1; index3<shadow_border_index; ++index3)
00467 {
00468 BorderTraits& veil_point = border_descriptions_->points[index3].traits;
00469 veil_point[BORDER_TRAIT__VEIL_POINT] = veil_point[BORDER_TRAIT__VEIL_POINT_LEFT] = true;
00470 }
00471 }
00472
00473 shadow_border_index = shadow_border_indices->top;
00474 if (shadow_border_index >= 0 && checkIfMaximum(x, y, 0, -1, border_scores_top_, shadow_border_index))
00475 {
00476 BorderTraits& shadow_traits = border_descriptions_->points[shadow_border_index].traits;
00477 border_traits[BORDER_TRAIT__OBSTACLE_BORDER] = border_traits[BORDER_TRAIT__OBSTACLE_BORDER_TOP] = true;
00478 shadow_traits[BORDER_TRAIT__SHADOW_BORDER] = shadow_traits[BORDER_TRAIT__SHADOW_BORDER_BOTTOM] = true;
00479 for (int index3=index-width; index3>shadow_border_index; index3-=width)
00480 {
00481
00482 BorderTraits& veil_point = border_descriptions_->points[index3].traits;
00483 veil_point[BORDER_TRAIT__VEIL_POINT] = veil_point[BORDER_TRAIT__VEIL_POINT_BOTTOM] = true;
00484 }
00485 }
00486
00487 shadow_border_index = shadow_border_indices->bottom;
00488 if (shadow_border_index >= 0 && checkIfMaximum(x, y, 0, 1, border_scores_bottom_, shadow_border_index))
00489 {
00490 BorderTraits& shadow_traits = border_descriptions_->points[shadow_border_index].traits;
00491 border_traits[BORDER_TRAIT__OBSTACLE_BORDER] = border_traits[BORDER_TRAIT__OBSTACLE_BORDER_BOTTOM] = true;
00492 shadow_traits[BORDER_TRAIT__SHADOW_BORDER] = shadow_traits[BORDER_TRAIT__SHADOW_BORDER_TOP] = true;
00493 for (int index3=index+width; index3<shadow_border_index; index3+=width)
00494 {
00495
00496 BorderTraits& veil_point = border_descriptions_->points[index3].traits;
00497 veil_point[BORDER_TRAIT__VEIL_POINT] = veil_point[BORDER_TRAIT__VEIL_POINT_TOP] = true;
00498 }
00499 }
00500
00501
00502
00503
00504
00505 }
00506 }
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00587
00588
00589
00590
00591
00592
00593
00594
00595
00598
00599
00600
00601
00602
00603
00604
00605
00606
00609
00610
00612
00613
00614
00615
00616
00617
00618
00621
00622
00624
00625
00626
00627
00628
00629
00630 }
00631
00632 void RangeImageBorderExtractor::calculateBorderDirections()
00633 {
00634 if (border_directions_!=NULL)
00635 return;
00636 classifyBorders();
00637
00638
00639
00640 int width = range_image_->width,
00641 height = range_image_->height,
00642 size = width*height;
00643 border_directions_ = new Eigen::Vector3f*[size];
00644 for (int y=0; y<height; ++y)
00645 {
00646 for (int x=0; x<width; ++x)
00647 {
00648 calculateBorderDirection(x, y);
00649 }
00650 }
00651
00652 Eigen::Vector3f** average_border_directions = new Eigen::Vector3f*[size];
00653 int radius = parameters_.pixel_radius_border_direction;
00654 int minimum_weight = radius+1;
00655 float min_cos_angle=cosf(deg2rad(120.0f));
00656 for (int y=0; y<height; ++y)
00657 {
00658 for (int x=0; x<width; ++x)
00659 {
00660 int index = y*width + x;
00661 Eigen::Vector3f*& average_border_direction = average_border_directions[index];
00662 average_border_direction = NULL;
00663 const Eigen::Vector3f* border_direction = border_directions_[index];
00664 if (border_direction==NULL)
00665 continue;
00666 average_border_direction = new Eigen::Vector3f(*border_direction);
00667 float weight_sum = 1.0f;
00668 for (int y2=(std::max)(0, y-radius); y2<=(std::min)(y+radius, height-1); ++y2)
00669 {
00670 for (int x2=(std::max)(0, x-radius); x2<=(std::min)(x+radius, width-1); ++x2)
00671 {
00672 int index2 = y2*width + x2;
00673 const Eigen::Vector3f* neighbor_border_direction = border_directions_[index2];
00674 if (neighbor_border_direction==NULL || index2==index)
00675 continue;
00676
00677
00678 float cos_angle = neighbor_border_direction->dot(*border_direction);
00679 if (cos_angle<min_cos_angle)
00680 {
00681
00682 continue;
00683 }
00684
00685
00686
00687
00688 float border_between_points_score = getNeighborDistanceChangeScore(*surface_structure_[index], x, y, x2-x, y2-y, 1);
00689 if (fabsf(border_between_points_score) >= 0.95f*parameters_.minimum_border_probability)
00690 continue;
00691
00692 *average_border_direction += *neighbor_border_direction;
00693 weight_sum += 1.0f;
00694 }
00695 }
00696 if (lrint (weight_sum) < minimum_weight)
00697 {
00698 delete average_border_direction;
00699 average_border_direction=NULL;
00700 }
00701 else
00702 average_border_direction->normalize();
00703 }
00704 }
00705
00706 for (int i=0; i<size; ++i)
00707 delete border_directions_[i];
00708 delete[] border_directions_;
00709 border_directions_ = average_border_directions;
00710 }
00711
00712 void RangeImageBorderExtractor::calculateSurfaceChanges()
00713 {
00714 if (surface_change_scores_!=NULL)
00715 return;
00716
00717 calculateBorderDirections();
00718
00719
00720
00721 int width = range_image_->width,
00722 height = range_image_->height,
00723 size = width*height;
00724 surface_change_scores_ = new float[size];
00725 surface_change_directions_ = new Eigen::Vector3f[size];
00726 Eigen::Vector3f sensor_pos = range_image_->getSensorPos();
00727 # if USE_OMP
00728
00729 # pragma omp parallel for default(shared)
00730 # endif
00731 for (int y=0; y<height; ++y)
00732 {
00733 for (int x=0; x<width; ++x)
00734 {
00735 int index = y*width + x;
00736 float& surface_change_score = surface_change_scores_[index];
00737 surface_change_score = 0.0f;
00738 Eigen::Vector3f& surface_change_direction = surface_change_directions_[index];
00739 surface_change_direction.setZero();
00740
00741 const BorderTraits& border_traits = border_descriptions_->points[index].traits;
00742 if (border_traits[BORDER_TRAIT__VEIL_POINT] || border_traits[BORDER_TRAIT__SHADOW_BORDER])
00743 continue;
00744 if (border_directions_[index]!=NULL)
00745 {
00746 surface_change_score = 1.0f;
00747 surface_change_direction = *border_directions_[index];
00748
00749
00750
00751
00752
00753 }
00754 else
00755 {
00756 if (!calculateMainPrincipalCurvature(x, y, parameters_.pixel_radius_principal_curvature,
00757 surface_change_score, surface_change_direction))
00758 {
00759 surface_change_score = 0.0f;
00760 continue;
00761 }
00762 }
00763 }
00764 }
00765
00766 }
00767
00768
00769 void RangeImageBorderExtractor::blurSurfaceChanges()
00770 {
00771
00772
00773
00774 int blur_radius = 1;
00775 if (blur_radius==0)
00776 return;
00777
00778 const RangeImage& range_image = *range_image_;
00779
00780 Eigen::Vector3f* blurred_directions = new Eigen::Vector3f[range_image.width*range_image.height];
00781 float* blurred_scores = new float[range_image.width*range_image.height];
00782 for (int y=0; y<int(range_image.height); ++y)
00783 {
00784 for (int x=0; x<int(range_image.width); ++x)
00785 {
00786 int index = y*range_image.width + x;
00787 Eigen::Vector3f& new_point = blurred_directions[index];
00788 new_point.setZero();
00789 float& new_score = blurred_scores[index];
00790 new_score = 0.0f;
00791 if (!range_image.isValid(index))
00792 continue;
00793 const BorderTraits& border_traits = border_descriptions_->points[index].traits;
00794 if (border_traits[BORDER_TRAIT__VEIL_POINT] || border_traits[BORDER_TRAIT__SHADOW_BORDER])
00795 continue;
00796 const Eigen::Vector3f& point = surface_change_directions_[index];
00797 float counter = 0.0f;
00798 for (int y2=y-blur_radius; y2<y+blur_radius; ++y2)
00799 {
00800 for (int x2=x-blur_radius; x2<x+blur_radius; ++x2)
00801 {
00802 if (!range_image.isInImage(x2,y2))
00803 continue;
00804 int index2 = y2*range_image.width + x2;
00805 float score = surface_change_scores_[index2];
00806
00807
00808
00809 if (score > 0.0f)
00810 {
00811 Eigen::Vector3f& neighbor = surface_change_directions_[index2];
00812
00813
00814 if (point.dot(neighbor)<0.0f)
00815 neighbor *= -1.0f;
00816 new_point += score*neighbor;
00817 }
00818 new_score += score;
00819 counter += 1.0f;
00820 }
00821 }
00822 new_point.normalize();
00823 if (counter > 0.0f)
00824 new_score /= counter;
00825 }
00826 }
00827 delete[] surface_change_directions_;
00828 surface_change_directions_ = blurred_directions;
00829 delete[] surface_change_scores_;
00830 surface_change_scores_ = blurred_scores;
00831 }
00832
00833 void RangeImageBorderExtractor::computeFeature(PointCloudOut& output)
00834 {
00835
00836
00837 output.points.clear();
00838
00839 if (indices_)
00840 {
00841 std::cerr << __PRETTY_FUNCTION__
00842 << ": Sorry, usage of indices for the extraction is not supported for range image border extraction (yet).\n\n";
00843 output.width = output.height = 0;
00844 output.points.clear ();
00845 return;
00846 }
00847
00848 if (range_image_==NULL)
00849 {
00850 std::cerr << __PRETTY_FUNCTION__
00851 << ": RangeImage is not set. Sorry, the border extraction works on range images, not on normal point clouds."
00852 << " Use setRangeImage(...).\n\n";
00853 output.width = output.height = 0;
00854 output.points.clear ();
00855 return;
00856 }
00857 output = getBorderDescriptions();
00858 }
00859
00860 void RangeImageBorderExtractor::compute(PointCloudOut& output)
00861 {
00862 computeFeature(output);
00863 }
00864
00865
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00905
00923
00924
00925
00927
00928
00929
00930
00931
00932
00933
00934
00935
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00976
00977
00978
00979
00980
00982
00984
00986
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01001
01004
01005
01006
01007
01008
01009
01012
01013
01014
01015
01016
01019
01020
01022
01023
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039
01040
01041
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01070
01071
01072
01084
01085
01097
01105
01118
01121
01126
01129
01133
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202
01203
01204
01205
01206
01207
01208
01209
01210
01211
01212
01213
01214
01215
01216
01217
01218
01219
01222
01223
01224
01225
01226
01227
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238
01239
01241
01242
01243
01244
01245
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01295
01296
01297
01298
01300
01301
01302
01303
01304
01305
01306
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320
01321
01322
01325
01326
01327
01329
01330
01331
01333
01335
01336
01337
01338
01339
01340
01341
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352
01353
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01398
01399
01400
01401
01402
01403 #if 0
01404 std::vector<float> acuteness_values, acuteness_change_values, acuteness_values_border, acuteness_change_values_border;
01405 void RangeImageBorderExtractor::updateStatistic(float acuteness, float acuteness_change, bool is_border) const
01406 {
01407 acuteness_values.push_back(fabs(acuteness));
01408 acuteness_change_values.push_back(acuteness_change);
01409 if (is_border)
01410 {
01411
01412 acuteness_values_border.push_back(fabs(acuteness));
01413 acuteness_change_values_border.push_back(acuteness_change);
01414 }
01415 }
01416
01417 void RangeImageBorderExtractor::outputStatistic() const
01418 {
01419 float step_size = 0.1f;
01420
01421 #define ADD_STATISTIC_OUTPUT(STATISTICS_VECTOR, PARAM_MEMBER, TMP_NAME) \
01422 { \
01423 std::sort(STATISTICS_VECTOR.begin(), STATISTICS_VECTOR.end()); \
01424 cout << " float "<<#TMP_NAME<<"[11] = {1, "; \
01425 float current_step = 0.1f; \
01426 for (int idx=0; idx<int(STATISTICS_VECTOR.size()); ++idx) \
01427 { \
01428 float value = STATISTICS_VECTOR[idx]; \
01429 while (value > current_step) \
01430 { \
01431 cout << 1.0f - (float(idx)/float(STATISTICS_VECTOR.size()))<<", "; \
01432 current_step += step_size; \
01433 } \
01434 } \
01435 cout << "0};\n" \
01436 << " std::copy("<<#TMP_NAME<<", "<<#TMP_NAME<<" + sizeof("<<#TMP_NAME<<")/sizeof(*"<<#TMP_NAME<<"),\n" \
01437 " std::inserter("<<#PARAM_MEMBER<<".getDataPoints(),\n" \
01438 << " "<<#PARAM_MEMBER<<".getDataPoints().end()));\n"; \
01439 }
01440
01441 ADD_STATISTIC_OUTPUT(acuteness_values, probability_distribution_acuteness, pda_tmp);
01442 ADD_STATISTIC_OUTPUT(acuteness_values_border, probability_distribution_acuteness_given_border, pdagb_tmp);
01443 ADD_STATISTIC_OUTPUT(acuteness_change_values, probability_distribution_acuteness_change, pdac_tmp);
01444 ADD_STATISTIC_OUTPUT(acuteness_change_values_border, probability_distribution_acuteness_change_given_border, pdacgb_tmp);
01445
01446 #undef ADD_STATISTIC_OUTPUT
01447 }
01448
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01492
01494
01496
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01509
01510
01511
01520
01526
01528
01529
01530 float RangeImageBorderExtractor::getNormalChangeBorderProbability(const RangeImage& range_image, int radius, int x, int y, int offset_x, int offset_y) const
01531 {
01532 float ret = 0.0f;
01533 int neighbor_x = x+offset_x,
01534 neighbor_y = y+offset_y;
01535 const PointWithRange& point = range_image.getPoint(x, y);
01536
01537 Eigen::Vector3f normal1, normal2;
01538 if (range_image.getNormal(neighbor_x, neighbor_y, 1, normal2, 1))
01539 {
01540 int other_neighbor_x = x-offset_x, other_neighbor_y = y-offset_y;
01541 if (range_image.getNormalForClosestNeighbors(other_neighbor_x, other_neighbor_y, 2, point, 8, normal1, 1))
01542 {
01543 Eigen::Vector3f viewing_direction = (range_image.getSensorPos() - range_image.getEigenVector3f(point)).normalized();
01544
01545 float viewing_angle1 = acosf(fabs(viewing_direction.dot(normal1))),
01546 viewing_angle2 = acosf(fabs(viewing_direction.dot(normal2)));
01547 if (viewing_angle1 < viewing_angle2)
01548 ret = (viewing_angle2-viewing_angle1)/deg2rad(90.0f);
01549
01550 }
01551 }
01552 return ret;
01553 }
01554
01555 float RangeImageBorderExtractor::getDistanceChangeScore(const RangeImage& range_image, int x, int y, int offset_x, int offset_y, int max_pixel_distance) const
01556 {
01557 float average_neighbor_distance1 = range_image.getAverageEuclideanDistance(x, y, offset_x, offset_y, max_pixel_distance),
01558 average_neighbor_distance2 = range_image.getAverageEuclideanDistance(x, y, -offset_x, -offset_y, max_pixel_distance);
01559 if ((pcl_isinf(average_neighbor_distance1) && pcl_isinf(average_neighbor_distance2)) ||
01560 average_neighbor_distance1<0.0f || average_neighbor_distance2<0.0)
01561 return 0.0f;
01562 if (pcl_isinf(average_neighbor_distance1) || pcl_isinf(average_neighbor_distance2))
01563 return 1.0f;
01564 float distance_change_score = (std::min)(average_neighbor_distance1, average_neighbor_distance2) /
01565 (std::max)(average_neighbor_distance1, average_neighbor_distance2);
01566 distance_change_score = 1.0f - pow(distance_change_score, 1);
01567 return distance_change_score;
01568 }
01569
01570
01571 float RangeImageBorderExtractor::getBorderProbability(const RangeImage& range_image, int x, int y, int offset_x, int offset_y,
01572 const float* acuteness_value_image_x, const float* acuteness_value_image_y) const
01573 {
01574 float acuteness = getPrecalculatedAcuteness(x, y, offset_x, offset_y, range_image.width, range_image.height, acuteness_value_image_x, acuteness_value_image_y);
01575
01576 if (!pcl_isfinite(acuteness))
01577 return 0.0f;
01578
01579
01580
01581
01582 float prob_acuteness = parameters_.probability_distribution_acuteness.getValue(fabsf(acuteness)),
01583 prob_acuteness_given_border = parameters_.probability_distribution_acuteness_given_border.getValue(fabsf(acuteness)),
01584 border_prob_acuteness_only = (prob_acuteness_given_border*parameters_.border_probability_prior)/prob_acuteness;
01585 float border_prob = border_prob_acuteness_only;
01586
01587
01588
01589
01590 float acuteness_other_side = getPrecalculatedAcuteness(x, y, -offset_x, -offset_y, range_image.width, range_image.height,
01591 acuteness_value_image_x, acuteness_value_image_y);
01592 if (pcl_isinf(acuteness_other_side))
01593 return 0.0f;
01594 float acuteness_change = 0.5f*(acuteness+acuteness_other_side);
01595
01596
01597
01598 float prob_acuteness_change = parameters_.probability_distribution_acuteness_change.getValue(fabsf(acuteness_change)),
01599 prob_acuteness_change_given_border = parameters_.probability_distribution_acuteness_change_given_border.getValue(fabsf(acuteness_change));
01600 border_prob *= (prob_acuteness_change_given_border)/prob_acuteness_change;
01601
01602 float average_acuteness = getAverageAcuteness(range_image, x, y, offset_x, offset_y, acuteness),
01603 average_acuteness_other_side = getAverageAcuteness(range_image, x, y, -offset_x, -offset_y, acuteness_other_side),
01604 average_acuteness_change = 0.5f*(average_acuteness + average_acuteness_other_side);
01605 if (average_acuteness*average_acuteness_change <= 0.0f)
01606 return 0.0f;
01607
01608 float prob_average_acuteness = parameters_.probability_distribution_acuteness.getValue(fabsf(average_acuteness)),
01609 prob_average_acuteness_given_border = parameters_.probability_distribution_acuteness_given_border.getValue(fabsf(average_acuteness)),
01610 prob_average_acuteness_change = parameters_.probability_distribution_acuteness_change.getValue(fabsf(average_acuteness_change)),
01611 prob_average_acuteness_change_given_border = parameters_.probability_distribution_acuteness_change_given_border.getValue(fabsf(average_acuteness_change));
01612
01613 float border_prob_from_average_acuteness = (prob_average_acuteness_given_border*prob_average_acuteness_change_given_border*parameters_.border_probability_prior) /
01614 (prob_average_acuteness*prob_average_acuteness_change);
01615 if (!pcl_isfinite(border_prob_from_average_acuteness))
01616 return 0.0f;
01617 border_prob = (std::min)(border_prob, border_prob_from_average_acuteness);
01618
01619 if (average_acuteness < 0.0f)
01620 border_prob *= -1.0f;
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664
01665
01666
01667
01668
01674
01675
01676
01678
01679
01680
01686
01688
01690
01692
01695
01709
01714
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734
01735
01736 return border_prob;
01737 }
01738
01739 float RangeImageBorderExtractor::getPrecalculatedAcuteness(int x, int y, int offset_x, int offset_y, int width, int height,
01740 const float* acuteness_value_image_x, const float* acuteness_value_image_y) const
01741 {
01742 offset_x *= parameters_.pixel_radius_borders;
01743 offset_y *= parameters_.pixel_radius_borders;
01744 if (offset_y == 0)
01745 {
01746 if (offset_x > 0)
01747 return (acuteness_value_image_x[y*width+x]);
01748 else
01749 return (x+offset_x >= 0 ? -acuteness_value_image_x[y*width + x+offset_x] : -std::numeric_limits<float>::infinity ());
01750 }
01751 else
01752 {
01753 if (offset_y > 0)
01754 return (acuteness_value_image_y[y*width+x]);
01755 else
01756 return (y+offset_y >= 0 ? -acuteness_value_image_y[(y+offset_y)*width + x] : -std::numeric_limits<float>::infinity ());
01757 }
01758 }
01759
01760 float RangeImageBorderExtractor::getAverageAcuteness(const RangeImage& range_image, int x, int y,
01761 int offset_x, int offset_y, float acuteness_in_pixel_radius_borders) const
01762 {
01763 float average_acuteness = acuteness_in_pixel_radius_borders;
01764 for (int i=1; i<parameters_.pixel_radius_borders; ++i)
01765 {
01766 int neighbor_x = x+i*offset_x,
01767 neighbor_y = y+i*offset_y;
01768 average_acuteness += range_image.getAcutenessValue(x, y, neighbor_x, neighbor_y);
01769 }
01770 average_acuteness /= parameters_.pixel_radius_borders;
01771 return average_acuteness;
01772 }
01773
01774
01775
01776
01777
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01808
01809
01810
01811
01812
01813
01814
01815 #endif
01816
01817
01818 }