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 <Eigen/StdVector>
00041 #include <iostream>
00042 using std::cout;
00043 using std::cerr;
00044 #include <cmath>
00045
00046 #include <pcl/range_image/range_image.h>
00047
00048
00049 #include <pcl/features/normal_3d.h>
00050 #include <pcl/common/transformation_from_correspondences.h>
00051
00052 namespace pcl
00053 {
00054
00055 bool RangeImage::debug = false;
00056
00058 void
00059 RangeImage::getCoordinateFrameTransformation (RangeImage::CoordinateFrame coordinate_frame,
00060 Eigen::Affine3f& transformation)
00061 {
00062 switch (coordinate_frame)
00063 {
00064 case LASER_FRAME:
00065 transformation (0,0)= 0.0f; transformation (0,1)= 0.0f; transformation (0,2)=1.0f; transformation (0,3)=0.0f;
00066 transformation (1,0)=-1.0f; transformation (1,1)= 0.0f; transformation (1,2)=0.0f; transformation (1,3)=0.0f;
00067 transformation (2,0)= 0.0f; transformation (2,1)=-1.0f; transformation (2,2)=0.0f; transformation (2,3)=0.0f;
00068 transformation (3,0)= 0.0f; transformation (3,1)= 0.0f; transformation (3,2)=0.0f; transformation (3,3)=1.0f;
00069 break;
00070 case CAMERA_FRAME:
00071 default:
00072 transformation.setIdentity ();
00073 break;
00074 }
00075
00076 }
00077
00079 RangeImage::RangeImage () : RangeImage::BaseClass ()
00080 {
00081 reset ();
00082 unobserved_point.x = unobserved_point.y = unobserved_point.z = std::numeric_limits<float>::quiet_NaN ();
00083 unobserved_point.range = -std::numeric_limits<float>::infinity ();
00084 }
00085
00087 RangeImage::~RangeImage ()
00088 {
00089 }
00090
00092 void
00093 RangeImage::reset ()
00094 {
00095 is_dense = true;
00096 width = height = 0;
00097 points.clear ();
00098 to_range_image_system_.setIdentity ();
00099 to_world_system_.setIdentity ();
00100 setAngularResolution (deg2rad (0.5f));
00101 image_offset_x_ = image_offset_y_ = 0.0f;
00102 }
00103
00105 void
00106 RangeImage::integrateFarRanges (const PointCloud<PointWithViewpoint>& far_ranges)
00107 {
00108 float x_real, y_real, range_of_current_point;
00109 for (std::vector<PointWithViewpoint, Eigen::aligned_allocator<PointWithViewpoint> >::const_iterator it
00110 =far_ranges.points.begin (); it!=far_ranges.points.end (); ++it)
00111 {
00112
00113
00114 Vector3fMapConst current_point = it->getVector3fMap ();
00115
00116 this->getImagePoint (current_point, x_real, y_real, range_of_current_point);
00117
00118 int floor_x = lrint (floor (x_real)), floor_y = lrint (floor (y_real)),
00119 ceil_x = lrint (ceil (x_real)), ceil_y = lrint (ceil (y_real));
00120
00121 int neighbor_x[4], neighbor_y[4];
00122 neighbor_x[0]=floor_x; neighbor_y[0]=floor_y;
00123 neighbor_x[1]=floor_x; neighbor_y[1]=ceil_y;
00124 neighbor_x[2]=ceil_x; neighbor_y[2]=floor_y;
00125 neighbor_x[3]=ceil_x; neighbor_y[3]=ceil_y;
00126
00127
00128 for (int i=0; i<4; ++i)
00129 {
00130 int x=neighbor_x[i], y=neighbor_y[i];
00131 if (!isInImage (x, y))
00132 continue;
00133 PointWithRange& image_point = getPoint (x, y);
00134 if (!pcl_isfinite (image_point.range))
00135 image_point.range = std::numeric_limits<float>::infinity ();
00136 }
00137 }
00138 }
00139
00141 void
00142 RangeImage::cropImage (int borderSize, int top, int right, int bottom, int left) {
00143
00144
00145
00146 bool topIsDone=true, rightIsDone=true, bottomIsDone=true, leftIsDone=true;
00147 if (top < 0) {
00148 top=-1;
00149 topIsDone=false;
00150 }
00151 if (right < 0) {
00152 right= (int)width;
00153 rightIsDone=false;
00154 }
00155 if (bottom < 0) {
00156 bottom= (int)height;
00157 bottomIsDone=false;
00158 }
00159 if (left < 0) {
00160 left=-1;
00161 leftIsDone=false;
00162 }
00163
00164
00165 while (!topIsDone && top<=bottom) {
00166 ++top;
00167 int lineStart = top*width;
00168 for (int x=left; x<=right && !topIsDone; ++x)
00169 if (pcl_isfinite (points[lineStart + x].range))
00170 topIsDone = true;
00171 }
00172
00173 if (top > bottom) {
00174 std::cerr << __PRETTY_FUNCTION__ << ": Range image is empty.\n";
00175 points.clear ();
00176 width = height = 0;
00177 return;
00178 }
00179
00180 while (!rightIsDone) {
00181 for (int y=top; y<=bottom && !rightIsDone; ++y)
00182 if (pcl_isfinite (points[y*width + right].range))
00183 rightIsDone = true;
00184 }
00185
00186 while (!bottomIsDone) {
00187 --bottom;
00188 int lineStart = bottom*width;
00189 for (int x=left; x<=right && !bottomIsDone; ++x)
00190 if (pcl_isfinite (points[lineStart + x].range))
00191 bottomIsDone = true;
00192 }
00193
00194 while (!leftIsDone) {
00195 ++left;
00196 for (int y=top; y<=bottom && !leftIsDone; ++y)
00197 if (pcl_isfinite (points[y*width + left].range))
00198 leftIsDone = true;
00199 }
00200
00201 left-=borderSize; top-=borderSize; right+=borderSize; bottom+=borderSize;
00202
00203
00204
00205
00206 std::vector<PointWithRange, Eigen::aligned_allocator<PointWithRange> > tmpPoints;
00207 points.swap (tmpPoints);
00208 RangeImage oldRangeImage = *this;
00209 tmpPoints.swap (oldRangeImage.points);
00210
00211 width = right-left+1; height = bottom-top+1;
00212 image_offset_x_ = left+oldRangeImage.image_offset_x_;
00213 image_offset_y_ = top+oldRangeImage.image_offset_y_;
00214 points.resize (width*height);
00215
00216
00217 for (int y=0, oldY=top; y< (int)height; ++y,++oldY) {
00218 for (int x=0, oldX=left; x< (int)width; ++x,++oldX) {
00219
00220 PointWithRange& currentPoint = points[y*width + x];
00221 if (oldX<0 || oldX>= (int)oldRangeImage.width || oldY<0 || oldY>= (int)oldRangeImage.height) {
00222 currentPoint = unobserved_point;
00223 continue;
00224 }
00225 currentPoint = oldRangeImage.points[oldY*oldRangeImage.width + oldX];
00226
00227 }
00228 }
00229
00230
00231 }
00232
00234 void
00235 RangeImage::recalculate3DPointPositions ()
00236 {
00237
00238 for (int y=0; y< (int)height; ++y) {
00239 for (int x=0; x< (int)width; ++x) {
00240 PointWithRange& point = points[y*width + x];
00241 if (!pcl_isinf (point.range)) {
00242 calculate3DPoint (x, y, point.range, point);
00243
00244
00245
00246
00247 }
00248 }
00249 }
00250 }
00251
00253 float*
00254 RangeImage::getRangesArray () const
00255 {
00256 int arraySize = width * height;
00257 float* ranges = new float[arraySize];
00258 for (int i=0; i<arraySize; ++i)
00259 ranges[i] = points[i].range;
00260 return ranges;
00261 }
00262
00263
00265 void
00266 RangeImage::getIntegralImage (float*& integral_image, int*& valid_points_num_image) const
00267 {
00268 integral_image = new float[width*height];
00269 float* integral_image_ptr = integral_image;
00270 valid_points_num_image = new int[width*height];
00271 int* valid_points_num_image_ptr = valid_points_num_image;
00272 for (int y=0; y< (int)height; ++y)
00273 {
00274 for (int x=0; x< (int)width; ++x)
00275 {
00276 float& integral_pixel = * (integral_image_ptr++);
00277 integral_pixel = getPoint (x, y).range;
00278 int& valid_points_num = * (valid_points_num_image_ptr++);
00279 valid_points_num = 1;
00280 if (pcl_isinf (integral_pixel))
00281 {
00282 integral_pixel = 0.0f;
00283 valid_points_num = 0;
00284 }
00285 float left_value=0, top_left_value=0, top_value=0;
00286 int left_valid_points=0, top_left_valid_points=0, top_valid_points=0;
00287 if (x>0)
00288 {
00289 left_value = integral_image[y*width+x-1];
00290 left_valid_points = valid_points_num_image[y*width+x-1];
00291 if (y>0)
00292 {
00293 top_left_value = integral_image[ (y-1)*width+x-1];
00294 top_left_valid_points = valid_points_num_image[ (y-1)*width+x-1];
00295 }
00296 }
00297 if (y>0)
00298 {
00299 top_value = integral_image[ (y-1)*width+x];
00300 top_valid_points = valid_points_num_image[ (y-1)*width+x];
00301 }
00302
00303 integral_pixel += left_value + top_value - top_left_value;
00304 valid_points_num += left_valid_points + top_valid_points - top_left_valid_points;
00305 }
00306 }
00307 }
00308
00310 void
00311 RangeImage::getBlurredImageUsingIntegralImage (int blur_radius, float* integral_image, int* valid_points_num_image,
00312 RangeImage& blurred_image) const
00313 {
00314 blurred_image = *this;
00315 for (int y=0; y<int (height); ++y)
00316 {
00317 for (int x=0; x<int (width); ++x)
00318 {
00319 const PointWithRange& old_point = getPoint (x, y);
00320 PointWithRange& new_point = blurred_image.getPoint (x, y);
00321 if (!pcl_isfinite (old_point.range))
00322 continue;
00323
00324 int top= (std::max) (-1, y-blur_radius-1), right = (std::min) (int (width)-1, x+blur_radius), bottom =
00325 (std::min) (int (height)-1, y+blur_radius), left= (std::max) (-1, x-blur_radius-1);
00326
00327 float top_left_value=0, top_right_value=0,
00328 bottom_right_value=integral_image[bottom*width+right], bottom_left_value=0;
00329 int top_left_valid_points=0, top_right_valid_points=0,
00330 bottom_right_valid_points=valid_points_num_image[bottom*width+right], bottom_left_valid_points=0;
00331 if (left>=0)
00332 {
00333 bottom_left_value = integral_image[bottom*width+left];
00334 bottom_left_valid_points = valid_points_num_image[bottom*width+left];
00335 if (top>=0)
00336 {
00337 top_left_value = integral_image[top*width+left];
00338 top_left_valid_points = valid_points_num_image[top*width+left];
00339 }
00340 }
00341 if (top>=0)
00342 {
00343 top_right_value = integral_image[top*width+right];
00344 top_right_valid_points = valid_points_num_image[top*width+right];
00345 }
00346 int valid_points_num = bottom_right_valid_points + top_left_valid_points - bottom_left_valid_points -
00347 top_right_valid_points;
00348 new_point.range = (bottom_right_value + top_left_value - bottom_left_value - top_right_value) / valid_points_num;
00349
00350
00351 }
00352 }
00353 blurred_image.recalculate3DPointPositions ();
00354 }
00355
00357 void
00358 RangeImage::getBlurredImage (int blur_radius, RangeImage& blurred_image) const
00359 {
00360 MEASURE_FUNCTION_TIME;
00361
00362 if (blur_radius > 1)
00363 {
00364 float* integral_image;
00365 int* valid_points_num_image;
00366 getIntegralImage (integral_image, valid_points_num_image);
00367 getBlurredImageUsingIntegralImage (blur_radius, integral_image, valid_points_num_image, blurred_image);
00368 delete[] integral_image;
00369 delete[] valid_points_num_image;
00370 return;
00371 }
00372
00373 blurred_image = *this;
00374
00375 if (blur_radius==0)
00376 return;
00377
00378 for (int y=0; y<int (height); ++y)
00379 {
00380 for (int x=0; x<int (width); ++x)
00381 {
00382 PointWithRange& new_point = blurred_image.getPoint (x, y);
00383 const PointWithRange& original_point = getPoint (x, y);
00384 if (!pcl_isfinite (original_point.range))
00385 continue;
00386
00387 new_point.range = 0.0f;
00388 float weight_sum = 0.0f;
00389 for (int y2=y-blur_radius; y2<y+blur_radius; ++y2)
00390 {
00391 for (int x2=x-blur_radius; x2<x+blur_radius; ++x2)
00392 {
00393 if (!isValid (x2,y2))
00394 continue;
00395 new_point.range += getPoint (x2, y2).range;
00396 weight_sum += 1.0f;
00397 }
00398 }
00399 new_point.range /= weight_sum;
00400 }
00401 }
00402 blurred_image.recalculate3DPointPositions ();
00403 }
00404
00406 void
00407 RangeImage::setUnseenToMaxRange ()
00408 {
00409 for (unsigned int i=0; i<points.size (); ++i)
00410 if (pcl_isinf (points[i].range))
00411 points[i].range = std::numeric_limits<float>::infinity ();
00412 }
00413
00415 void
00416 RangeImage::getHalfImage (RangeImage& half_image) const
00417 {
00418 half_image.angular_resolution_ = 2.0f * angular_resolution_;
00419 half_image.image_offset_x_ = image_offset_x_/2;
00420 half_image.image_offset_y_ = image_offset_y_/2;
00421 half_image.width = width/2;
00422 half_image.height = height/2;
00423 half_image.is_dense = is_dense;
00424 half_image.points.clear ();
00425 half_image.points.resize (half_image.width*half_image.height);
00426
00427 int src_start_x = 2*half_image.image_offset_x_ - image_offset_x_,
00428 src_start_y = 2*half_image.image_offset_y_ - image_offset_y_;
00429
00430 for (int dst_y=0; dst_y< (int)half_image.height; ++dst_y)
00431 {
00432 for (int dst_x=0; dst_x< (int)half_image.width; ++dst_x)
00433 {
00434 PointWithRange& dst_point = half_image.getPoint (dst_x, dst_y);
00435 dst_point=unobserved_point;
00436 int src_x_min = src_start_x + 2*dst_x,
00437 src_x_max = src_x_min + 1,
00438 src_y_min = src_start_y + 2*dst_y,
00439 src_y_max = src_y_min + 1;
00440 for (int src_x=src_x_min; src_x<=src_x_max; ++src_x)
00441 {
00442 for (int src_y=src_y_min; src_y<=src_y_max; ++src_y)
00443 {
00444 if (!isObserved (src_x, src_y))
00445 continue;
00446 const PointWithRange& src_point = getPoint (src_x, src_y);
00447 if (pcl_isfinite (dst_point.range) && src_point.range > dst_point.range)
00448 continue;
00449 dst_point = src_point;
00450 }
00451 }
00452 }
00453 }
00454 }
00455
00457 void
00458 RangeImage::getSubImage (int sub_image_image_offset_x, int sub_image_image_offset_y, int sub_image_width,
00459 int sub_image_height, int combine_pixels, RangeImage& sub_image) const
00460 {
00461 sub_image.angular_resolution_ = angular_resolution_*combine_pixels;
00462 sub_image.image_offset_x_ = sub_image_image_offset_x;
00463 sub_image.image_offset_y_ = sub_image_image_offset_y;
00464 sub_image.width = sub_image_width;
00465 sub_image.height = sub_image_height;
00466 sub_image.is_dense = is_dense;
00467 sub_image.points.clear ();
00468 sub_image.points.resize (sub_image.width*sub_image.height);
00469
00470 int src_start_x = combine_pixels*sub_image.image_offset_x_ - image_offset_x_,
00471 src_start_y = combine_pixels*sub_image.image_offset_y_ - image_offset_y_;
00472
00473 for (int dst_y=0; dst_y< (int)sub_image.height; ++dst_y)
00474 {
00475 for (int dst_x=0; dst_x< (int)sub_image.width; ++dst_x)
00476 {
00477 PointWithRange& dst_point = sub_image.getPoint (dst_x, dst_y);
00478 dst_point=unobserved_point;
00479 int src_x_min = src_start_x + combine_pixels*dst_x,
00480 src_x_max = src_x_min + combine_pixels-1,
00481 src_y_min = src_start_y + combine_pixels*dst_y,
00482 src_y_max = src_y_min + combine_pixels-1;
00483 for (int src_x=src_x_min; src_x<=src_x_max; ++src_x)
00484 {
00485 for (int src_y=src_y_min; src_y<=src_y_max; ++src_y)
00486 {
00487 if (!isInImage (src_x, src_y))
00488 continue;
00489 const PointWithRange& src_point = getPoint (src_x, src_y);
00490 if (pcl_isfinite (dst_point.range) && src_point.range > dst_point.range)
00491 continue;
00492 dst_point = src_point;
00493 }
00494 }
00495 }
00496 }
00497 }
00498
00499
00501 void
00502 RangeImage::getMinMaxRanges (float& min_range, float& max_range) const
00503 {
00504 min_range = std::numeric_limits<float>::infinity ();
00505 max_range = -std::numeric_limits<float>::infinity ();
00506 for (unsigned int i=0; i<points.size (); ++i)
00507 {
00508 float range = points[i].range;
00509 if (!pcl_isfinite (range))
00510 continue;
00511 min_range = (std::min) (min_range, range);
00512 max_range = (std::max) (max_range, range);
00513 }
00514 }
00515
00517 void
00518 RangeImage::change3dPointsToLocalCoordinateFrame ()
00519 {
00520 to_world_system_.setIdentity ();
00521 to_range_image_system_.setIdentity ();
00522 recalculate3DPointPositions ();
00523 }
00524
00526 float*
00527 RangeImage::getInterpolatedSurfaceProjection (const Eigen::Affine3f& pose, int pixel_size, float world_size) const
00528 {
00529
00530
00531
00532 float max_dist = 0.5f*world_size,
00533 cell_size = world_size/float (pixel_size);
00534 float world2cell_factor = 1.0f/cell_size,
00535 world2cell_offset = 0.5f*float (pixel_size)-0.5f;
00536 float cell2world_factor = cell_size,
00537 cell2world_offset = -max_dist + 0.5f*cell_size;
00538 Eigen::Affine3f inverse_pose = getInverse (pose);
00539
00540 int no_of_pixels = pixel_size*pixel_size;
00541 float* surface_patch = new float[no_of_pixels];
00542 SET_ARRAY (surface_patch, -std::numeric_limits<float>::infinity (), no_of_pixels);
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 Eigen::Vector3f position = getTranslation (inverse_pose);
00572 int middle_x, middle_y;
00573 getImagePoint (position, middle_x, middle_y);
00574 int min_search_radius = 2;
00575 bool still_in_range = true;
00576
00577 for (int radius=0; still_in_range; ++radius)
00578 {
00579
00580 int x=middle_x-radius-1, y=middle_y-radius;
00581 still_in_range = radius<min_search_radius;
00582 for (int i=0; i<8*radius || (radius==0&&i==0); ++i)
00583 {
00584 if (i<=2*radius) ++x; else if (i<=4*radius) ++y; else if (i<=6*radius) --x; else --y;
00585
00586
00587 Eigen::Vector3f point1, point2, point3;
00588 if (!isValid (x,y) || !isValid (x+1,y+1))
00589 continue;
00590 getPoint (x, y, point1);
00591 point1 = pose*point1;
00592 if (fabs (point1[2]) > max_dist)
00593 continue;
00594
00595 getPoint (x+1, y+1, point2);
00596 point2 = pose*point2;
00597 if (fabs (point2[2]) > max_dist)
00598 continue;
00599
00600 for (int triangle_idx=0; triangle_idx<=1; ++triangle_idx)
00601 {
00602 if (triangle_idx==0)
00603 {
00604 if (!isValid (x,y+1))
00605 continue;
00606 getPoint (x, y+1, point3);
00607 }
00608 else
00609 {
00610 if (!isValid (x+1,y))
00611 continue;
00612 getPoint (x+1, y, point3);
00613 }
00614 point3 = pose*point3;
00615 if (fabs (point3[2]) > max_dist)
00616 continue;
00617
00618
00619 if ( (point1[0] < -max_dist && point2[0] < -max_dist && point3[0] < -max_dist) ||
00620 (point1[0] > max_dist && point2[0] > max_dist && point3[0] > max_dist) ||
00621 (point1[1] < -max_dist && point2[1] < -max_dist && point3[1] < -max_dist) ||
00622 (point1[1] > max_dist && point2[1] > max_dist && point3[1] > max_dist))
00623 {
00624 continue;
00625 }
00626
00627 still_in_range = true;
00628
00629
00630 float cell1_x = world2cell_factor*point1[0] + world2cell_offset,
00631 cell1_y = world2cell_factor*point1[1] + world2cell_offset,
00632 cell1_z = point1[2],
00633 cell2_x = world2cell_factor*point2[0] + world2cell_offset,
00634 cell2_y = world2cell_factor*point2[1] + world2cell_offset,
00635 cell2_z = point2[2],
00636 cell3_x = world2cell_factor*point3[0] + world2cell_offset,
00637 cell3_y = world2cell_factor*point3[1] + world2cell_offset,
00638 cell3_z = point3[2];
00639
00640 int min_cell_x = (std::max) (0, int (lrint (ceil ( (std::min) (cell1_x, (std::min) (cell2_x, cell3_x)))))),
00641 max_cell_x = (std::min) (pixel_size-1, int (lrint (floor ( (std::max) (cell1_x,
00642 (std::max) (cell2_x, cell3_x)))))),
00643 min_cell_y = (std::max) (0, int (lrint (ceil ( (std::min) (cell1_y, (std::min) (cell2_y, cell3_y)))))),
00644 max_cell_y = (std::min) (pixel_size-1, int (lrint (floor ( (std::max) (cell1_y,
00645 (std::max) (cell2_y, cell3_y))))));
00646 if (max_cell_x<min_cell_x || max_cell_y<min_cell_y)
00647 continue;
00648
00649
00650
00651
00652
00653
00654
00655
00656 Eigen::Vector2f cell1 (cell1_x, cell1_y),
00657 cell2 (cell2_x, cell2_y),
00658 cell3 (cell3_x, cell3_y),
00659 v0 = cell3 - cell1,
00660 v1 = cell2 - cell1;
00661 float dot00 = v0.dot (v0),
00662 dot01 = v0.dot (v1),
00663 dot11 = v1.dot (v1),
00664 invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
00665
00666 for (int cell_x=min_cell_x; cell_x<=max_cell_x; ++cell_x)
00667 {
00668 for (int cell_y=min_cell_y; cell_y<=max_cell_y; ++cell_y)
00669 {
00670 Eigen::Vector2f current_cell (cell_x, cell_y),
00671 v2 = current_cell - cell1;
00672 float dot02 = v0.dot (v2),
00673 dot12 = v1.dot (v2),
00674 u = (dot11 * dot02 - dot01 * dot12) * invDenom,
00675 v = (dot00 * dot12 - dot01 * dot02) * invDenom;
00676 bool point_in_triangle = (u > -0.01) && (v >= -0.01) && (u + v <= 1.01);
00677
00678
00679
00680
00681
00682
00683
00684 if (!point_in_triangle)
00685 continue;
00686
00687 float new_value = cell1_z + u* (cell3_z-cell1_z) + v* (cell2_z-cell1_z);
00688
00689
00690
00691 float& value = surface_patch[cell_y*pixel_size + cell_x];
00692 if (pcl_isinf (value))
00693 value = new_value;
00694 else
00695 value = (std::min) (value, new_value);
00696 }
00697 }
00698 }
00699 }
00700 }
00701
00702
00703 for (int cell_y=0; cell_y<pixel_size; ++cell_y)
00704 {
00705 for (int cell_x=0; cell_x<pixel_size; ++cell_x)
00706 {
00707 int index= cell_y*pixel_size + cell_x;
00708 float& value = surface_patch[index];
00709 if (!pcl_isinf (value))
00710 continue;
00711
00712
00713 bool is_background = false;
00714 for (int cell2_y=cell_y-1; cell2_y<=cell_y+1&&!is_background; ++cell2_y)
00715 {
00716 for (int cell2_x=cell_x-1; cell2_x<=cell_x+1; ++cell2_x)
00717 {
00718 if (cell2_x<0||cell2_x>=pixel_size||cell2_y<0||cell2_y>=pixel_size || (cell2_x==cell_x && cell2_y==cell_y))
00719 continue;
00720 float neighbor_value = surface_patch[cell2_y*pixel_size + cell2_x];
00721 if (pcl_isfinite (neighbor_value))
00722 {
00723 float cell_pos_x = cell_x + 0.6f* (cell_x-cell2_x),
00724 cell_pos_y = cell_y + 0.6f* (cell_y-cell2_y);
00725 Eigen::Vector3f fake_point (cell2world_factor* (cell_pos_x)+cell2world_offset,
00726 cell2world_factor*cell_pos_y+cell2world_offset, neighbor_value);
00727 fake_point = inverse_pose*fake_point;
00728 float range_difference = getRangeDifference (fake_point);
00729 if (range_difference > max_dist)
00730 {
00731
00732 value = std::numeric_limits<float>::infinity ();
00733 is_background = true;
00734 break;
00735 }
00736 }
00737 }
00738 }
00739 if (is_background)
00740 {
00741
00742 for (int cell2_y=cell_y-1; cell2_y<=cell_y+1; ++cell2_y)
00743 {
00744 for (int cell2_x=cell_x-1; cell2_x<=cell_x+1; ++cell2_x)
00745 {
00746 if (cell2_x<0||cell2_x>=pixel_size||cell2_y<0||cell2_y>=pixel_size || (cell2_x==cell_x && cell2_y==cell_y))
00747 continue;
00748 int index2 = cell2_y*pixel_size + cell2_x;
00749 float& neighbor_value = surface_patch[index2];
00750 if (pcl_isinf (neighbor_value) && neighbor_value<0)
00751 {
00752 neighbor_value = std::numeric_limits<float>::infinity ();
00753 }
00754 }
00755 }
00756 }
00757 }
00758 }
00759
00760 return surface_patch;
00761 }
00762
00763
00764
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806
00807
00808
00809
00811
00812
00813
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830
00831
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
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
00900
00901
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00924
00925
00926
00927
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946
00947
00948
00949
00950
00951
00952
00954
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
00965
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986
00987
00988
00989
00990
00991
00992
00993
00994
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013 float* RangeImage::getInterpolatedSurfaceProjection (const Eigen::Vector3f& point, int pixel_size,
01014 float world_size) const
01015 {
01016 Eigen::Affine3f pose = getTransformationToViewerCoordinateFrame (point);
01017 return getInterpolatedSurfaceProjection (pose, pixel_size, world_size);
01018 }
01019
01020
01022 bool
01023 RangeImage::getNormalBasedUprightTransformation (const Eigen::Vector3f& point, float max_dist,
01024 Eigen::Affine3f& transformation) const
01025 {
01026
01027
01028 int x, y;
01029 getImagePoint (point, x, y);
01030
01031 Eigen::Vector3f neighbor;
01032 VectorAverage3f vector_average;
01033 float max_dist_squared=max_dist*max_dist, max_dist_reciprocal=1.0f/max_dist;
01034
01035 bool still_in_range = true;
01036 for (int radius=1; still_in_range; ++radius)
01037 {
01038 int x2=x-radius-1, y2=y-radius;
01039 still_in_range = false;
01040 for (int i=0; i<8*radius; ++i)
01041 {
01042 if (i<=2*radius) ++x2; else if (i<=4*radius) ++y2; else if (i<=6*radius) --x2; else --y2;
01043 if (!isValid (x2, y2))
01044 {
01045
01046 continue;
01047 }
01048 getPoint (x2, y2, neighbor);
01049 float distance_squared = (neighbor-point).squaredNorm ();
01050 if (distance_squared > max_dist_squared)
01051 {
01052
01053 continue;
01054 }
01055 still_in_range = true;
01056 float distance = sqrtf (distance_squared),
01057 weight = distance*max_dist_reciprocal;
01058 vector_average.add (neighbor, weight);
01059 }
01060 }
01061
01062
01063 Eigen::Vector3f normal, point_on_plane;
01064 if (vector_average.getNoOfSamples () > 10)
01065 {
01066 Eigen::Vector3f eigen_values, eigen_vector2, eigen_vector3;
01067 vector_average.doPCA (eigen_values, normal, eigen_vector2, eigen_vector3);
01068 if (normal.dot ( (vector_average.getMean ()-getSensorPos ()).normalized ()) < 0.0f)
01069 normal *= -1.0f;
01070 point_on_plane = (normal.dot (vector_average.getMean ()) - normal.dot (point))*normal + point;
01071
01072 }
01073 else
01074 {
01075 if (!getNormalForClosestNeighbors (x, y, 2, point, 15, normal, &point_on_plane, 1))
01076 return false;
01077
01078 }
01079
01080
01081 getTransformationFromTwoUnitVectorsAndOrigin (Eigen::Vector3f (0.0f, -1.0f, 0.0f),
01082 normal, point_on_plane, transformation);
01083
01084 return true;
01085 }
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01103 void
01104 RangeImage::getSurfaceAngleChangeImages (int radius, float*& angle_change_image_x, float*& angle_change_image_y) const
01105 {
01106 MEASURE_FUNCTION_TIME;
01107 int size = width*height;
01108 angle_change_image_x = new float[size];
01109 angle_change_image_y = new float[size];
01110 for (int y=0; y<int (height); ++y)
01111 {
01112 for (int x=0; x<int (width); ++x)
01113 {
01114 int index = y*width+x;
01115 getSurfaceAngleChange (x, y, radius, angle_change_image_x[index], angle_change_image_y[index]);
01116 }
01117 }
01118 }
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148
01149
01150
01151
01152
01153
01154
01155
01156
01157
01158
01159
01160
01161
01162
01163
01164
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
01234
01235
01236
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01296
01297
01298
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01320 void
01321 RangeImage::getAcutenessValueImages (int pixel_distance, float*& acuteness_value_image_x,
01322 float*& acuteness_value_image_y) const
01323 {
01324 MEASURE_FUNCTION_TIME;
01325 int size = width*height;
01326 acuteness_value_image_x = new float[size];
01327 acuteness_value_image_y = new float[size];
01328 for (int y=0; y<int (height); ++y)
01329 {
01330 for (int x=0; x<int (width); ++x)
01331 {
01332 int index = y*width+x;
01333 acuteness_value_image_x[index] = getAcutenessValue (x, y, x+pixel_distance, y);
01334 acuteness_value_image_y[index] = getAcutenessValue (x, y, x, y+pixel_distance);
01335
01336
01337
01338
01339 }
01340 }
01341 }
01342
01344 float*
01345 RangeImage::getImpactAngleImageBasedOnLocalNormals (int radius) const
01346 {
01347 MEASURE_FUNCTION_TIME;
01348 int size = width*height;
01349 float* impact_angle_image = new float[size];
01350 for (int y=0; y<int (height); ++y)
01351 {
01352 for (int x=0; x<int (width); ++x)
01353 {
01354 impact_angle_image[y*width+x] = getImpactAngleBasedOnLocalNormal (x, y, radius);
01355 }
01356 }
01357 return impact_angle_image;
01358 }
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01383 void
01384 RangeImage::getRangeImageWithSmoothedSurface (int radius, RangeImage& smoothed_range_image) const
01385 {
01386
01387
01388 int step_size = (std::max) (1, radius/2);
01389
01390 int no_of_nearest_neighbors = pow ( (double) (radius/step_size + 1), 2.0);
01391
01392 smoothed_range_image = *this;
01393 Eigen::Vector3f sensor_pos = getSensorPos ();
01394 for (int y=0; y<int (height); ++y)
01395 {
01396 for (int x=0; x<int (width); ++x)
01397 {
01398 PointWithRange& point = smoothed_range_image.getPoint (x, y);
01399 if (pcl_isinf (point.range))
01400 continue;
01401 Eigen::Vector3f normal, mean, eigen_values;
01402 float used_squared_max_distance;
01403 getSurfaceInformation (x, y, radius, point.getVector3fMap (), no_of_nearest_neighbors,
01404 step_size, used_squared_max_distance,
01405 normal, mean, eigen_values);
01406
01407 Eigen::Vector3f viewing_direction = (point.getVector3fMap ()-sensor_pos).normalized ();
01408 float new_range = normal.dot (mean-sensor_pos) / normal.dot (viewing_direction);
01409 point.range = new_range;
01410 calculate3DPoint (x, y, point.range, point);
01411
01412 const PointWithRange& original_point = getPoint (x, y);
01413 float distance_squared = squaredEuclideanDistance (original_point, point);
01414 if (distance_squared > used_squared_max_distance)
01415 point = original_point;
01416 }
01417 }
01418 }
01419
01421 void
01422 RangeImage::extractFarRanges (const sensor_msgs::PointCloud2& point_cloud_data,
01423 PointCloud<PointWithViewpoint>& far_ranges)
01424 {
01425 int x_idx = getFieldIndex (point_cloud_data, "x"),
01426 y_idx = getFieldIndex (point_cloud_data, "y"),
01427 z_idx = getFieldIndex (point_cloud_data, "z"),
01428 vp_x_idx = getFieldIndex (point_cloud_data, "vp_x"),
01429 vp_y_idx = getFieldIndex (point_cloud_data, "vp_y"),
01430 vp_z_idx = getFieldIndex (point_cloud_data, "vp_z"),
01431 distance_idx = getFieldIndex (point_cloud_data, "distance");
01432
01433 if (x_idx<0 || y_idx<0 || z_idx<0 || vp_x_idx<0 || vp_y_idx<0 || vp_z_idx<0 || distance_idx<0)
01434 {
01435
01436
01437 return;
01438 }
01439
01440
01441 int point_step = point_cloud_data.point_step;
01442 const unsigned char* data = &point_cloud_data.data[0];
01443 int x_offset = point_cloud_data.fields[x_idx].offset,
01444 y_offset = point_cloud_data.fields[y_idx].offset,
01445 z_offset = point_cloud_data.fields[z_idx].offset,
01446 vp_x_offset = point_cloud_data.fields[vp_x_idx].offset,
01447 vp_y_offset = point_cloud_data.fields[vp_y_idx].offset,
01448 vp_z_offset = point_cloud_data.fields[vp_z_idx].offset,
01449 distance_offset = point_cloud_data.fields[distance_idx].offset;
01450
01451 for (size_t point_idx = 0; point_idx < point_cloud_data.width*point_cloud_data.height; ++point_idx)
01452 {
01453 float x = * (float*) (data+x_offset), y = * (float*) (data+y_offset), z = * (float*) (data+z_offset),
01454 vp_x = * (float*) (data+vp_x_offset),
01455 vp_y = * (float*) (data+vp_y_offset),
01456 vp_z = * (float*) (data+vp_z_offset),
01457 distance = * (float*) (data+distance_offset);
01458 data+=point_step;
01459
01460 if (!pcl_isfinite (x) && pcl_isfinite (distance))
01461 {
01462
01463 PointWithViewpoint point;
01464 point.x=distance; point.y=y; point.z=z;
01465 point.vp_x=vp_x; point.vp_y=vp_y; point.vp_z=vp_z;
01466 far_ranges.points.push_back (point);
01467 }
01468 }
01469 far_ranges.width=far_ranges.points.size (); far_ranges.height = 1;
01470 far_ranges.is_dense = false;
01471 }
01472
01473 Eigen::Affine3f RangeImage::doIcp (const RangeImage::VectorOfEigenVector3f& points,
01474 const Eigen::Affine3f& initial_guess, int search_radius,
01475 float max_distance_start, float max_distance_end, int num_iterations) const
01476 {
01477 Eigen::Affine3f ret = initial_guess;
01478
01479 float max_distance = max_distance_start,
01480 max_distance_reduction = (max_distance_start-max_distance_end)/float (num_iterations);
01481
01482 TransformationFromCorrespondences transformation_from_correspondeces;
01483 for (int iteration=1; iteration<=num_iterations; ++iteration)
01484 {
01485 float max_distance_squared = max_distance*max_distance;
01486 transformation_from_correspondeces.reset ();
01487 for (int point_idx=0; point_idx< (int)points.size (); ++point_idx)
01488 {
01489 const Eigen::Vector3f& point = points[point_idx];
01490 Eigen::Vector3f transformed_point = ret * point;
01491 int x,y;
01492 getImagePoint (transformed_point, x, y);
01493 float closest_distance = max_distance_squared;
01494 Eigen::Vector3f closest_point (0.0f, 0.0f, 0.0f);
01495 bool found_neighbor = false;
01496 for (int y2=y-search_radius; y2<=y+search_radius; ++y2)
01497 {
01498 for (int x2=x-search_radius; x2<=x+search_radius; ++x2)
01499 {
01500 const PointWithRange& neighbor = getPoint (x2, y2);
01501 if (!pcl_isfinite (neighbor.range))
01502 continue;
01503 float distance = (transformed_point-neighbor.getVector3fMap ()).squaredNorm ();
01504 if (distance < closest_distance)
01505 {
01506 closest_distance = distance;
01507 closest_point = neighbor.getVector3fMap ();
01508 found_neighbor = true;
01509 }
01510 }
01511 }
01512 if (found_neighbor)
01513 {
01514
01515 transformation_from_correspondeces.add (point, closest_point);
01516 }
01517 }
01518
01519
01520 if (transformation_from_correspondeces.getNoOfSamples () < 3)
01521 return ret;
01522
01523 ret = transformation_from_correspondeces.getTransformation ();
01524
01525
01526 max_distance -= max_distance_reduction;
01527 }
01528
01529
01530
01531 return ret;
01532 }
01533
01534 }
01535