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
00035
00036
00037 #include <cstddef>
00038 #include <iostream>
00039 #include <cmath>
00040 #include <set>
00041 #include <pcl/common/eigen.h>
00042 #include <pcl/range_image/range_image.h>
00043 #include <pcl/common/transformation_from_correspondences.h>
00044
00045 namespace pcl
00046 {
00047
00048 bool RangeImage::debug = false;
00049 int RangeImage::max_no_of_threads = 1;
00050 const int RangeImage::lookup_table_size = 20001;
00051 std::vector<float> RangeImage::asin_lookup_table;
00052 std::vector<float> RangeImage::atan_lookup_table;
00053 std::vector<float> RangeImage::cos_lookup_table;
00054
00056 void
00057 RangeImage::createLookupTables ()
00058 {
00059 if (!asin_lookup_table.empty ())
00060 return;
00061
00062 asin_lookup_table.resize (lookup_table_size);
00063 for (int i=0; i<lookup_table_size; ++i) {
00064 float value = static_cast<float> (i-(lookup_table_size-1)/2)/static_cast<float> ((lookup_table_size-1)/2);
00065 asin_lookup_table[i] = asinf (value);
00066 }
00067
00068 atan_lookup_table.resize (lookup_table_size);
00069 for (int i=0; i<lookup_table_size; ++i)
00070 {
00071 float value = static_cast<float> (i-(lookup_table_size-1)/2)/static_cast<float> ((lookup_table_size-1)/2);
00072 atan_lookup_table[i] = atanf (value);
00073 }
00074
00075 cos_lookup_table.resize (lookup_table_size);
00076
00077 for (int i = 0; i < lookup_table_size; ++i)
00078 {
00079 float value = static_cast<float> (i) * 2.0f * static_cast<float> (M_PI) / static_cast<float> (lookup_table_size-1);
00080 cos_lookup_table[i] = cosf (value);
00081 }
00082 }
00083
00084
00085
00087 void
00088 RangeImage::getCoordinateFrameTransformation (RangeImage::CoordinateFrame coordinate_frame,
00089 Eigen::Affine3f& transformation)
00090 {
00091 switch (coordinate_frame)
00092 {
00093 case LASER_FRAME:
00094 transformation (0,0)= 0.0f; transformation (0,1)= 0.0f; transformation (0,2)=1.0f; transformation (0,3)=0.0f;
00095 transformation (1,0)=-1.0f; transformation (1,1)= 0.0f; transformation (1,2)=0.0f; transformation (1,3)=0.0f;
00096 transformation (2,0)= 0.0f; transformation (2,1)=-1.0f; transformation (2,2)=0.0f; transformation (2,3)=0.0f;
00097 transformation (3,0)= 0.0f; transformation (3,1)= 0.0f; transformation (3,2)=0.0f; transformation (3,3)=1.0f;
00098 break;
00099 case CAMERA_FRAME:
00100 default:
00101 transformation.setIdentity ();
00102 break;
00103 }
00104 }
00105
00107 RangeImage::RangeImage () :
00108 RangeImage::BaseClass (),
00109 to_range_image_system_ (Eigen::Affine3f::Identity ()),
00110 to_world_system_ (Eigen::Affine3f::Identity ()),
00111 angular_resolution_x_ (0), angular_resolution_y_ (0),
00112 angular_resolution_x_reciprocal_ (0), angular_resolution_y_reciprocal_ (0),
00113 image_offset_x_ (0), image_offset_y_ (0),
00114 unobserved_point ()
00115 {
00116 createLookupTables ();
00117 reset ();
00118 unobserved_point.x = unobserved_point.y = unobserved_point.z = std::numeric_limits<float>::quiet_NaN ();
00119 unobserved_point.range = -std::numeric_limits<float>::infinity ();
00120 }
00121
00123 RangeImage::~RangeImage ()
00124 {
00125 }
00126
00128 void
00129 RangeImage::reset ()
00130 {
00131 is_dense = true;
00132 width = height = 0;
00133 points.clear ();
00134 to_range_image_system_.setIdentity ();
00135 to_world_system_.setIdentity ();
00136 setAngularResolution (deg2rad (0.5f));
00137 image_offset_x_ = image_offset_y_ = 0;
00138 }
00139
00141 void
00142 RangeImage::createEmpty (float angular_resolution, const Eigen::Affine3f& sensor_pose,
00143 RangeImage::CoordinateFrame coordinate_frame, float angle_width, float angle_height)
00144 {
00145 createEmpty (angular_resolution, angular_resolution, sensor_pose, coordinate_frame, angle_width, angle_height);
00146 }
00147
00149 void
00150 RangeImage::createEmpty (float angular_resolution_x, float angular_resolution_y, const Eigen::Affine3f& sensor_pose,
00151 RangeImage::CoordinateFrame coordinate_frame, float angle_width, float angle_height)
00152 {
00153 setAngularResolution(angular_resolution_x, angular_resolution_y);
00154 width = static_cast<uint32_t> (pcl_lrint (floor (angle_width * angular_resolution_x_reciprocal_)));
00155 height = static_cast<uint32_t> (pcl_lrint (floor (angle_height * angular_resolution_y_reciprocal_)));
00156
00157 int full_width = static_cast<int> (pcl_lrint (floor (pcl::deg2rad (360.0f)*angular_resolution_x_reciprocal_))),
00158 full_height = static_cast<int> (pcl_lrint (floor (pcl::deg2rad (180.0f)*angular_resolution_y_reciprocal_)));
00159 image_offset_x_ = (full_width-width)/2;
00160 image_offset_y_ = (full_height-height)/2;
00161 is_dense = false;
00162 getCoordinateFrameTransformation (coordinate_frame, to_world_system_);
00163 to_world_system_ = sensor_pose * to_world_system_;
00164 to_range_image_system_ = to_world_system_.inverse (Eigen::Isometry);
00165 unsigned int size = width*height;
00166 points.clear ();
00167 points.resize (size, unobserved_point);
00168 }
00169
00171 void
00172 RangeImage::cropImage (int borderSize, int top, int right, int bottom, int left) {
00173
00174
00175 bool topIsDone=true, rightIsDone=true, bottomIsDone=true, leftIsDone=true;
00176 if (top < 0) {
00177 top=-1;
00178 topIsDone=false;
00179 }
00180 if (right < 0)
00181 {
00182 right= static_cast<int> (width);
00183 rightIsDone=false;
00184 }
00185 if (bottom < 0)
00186 {
00187 bottom= static_cast<int> (height);
00188 bottomIsDone=false;
00189 }
00190 if (left < 0)
00191 {
00192 left = -1;
00193 leftIsDone = false;
00194 }
00195
00196
00197 while (!topIsDone && top<=bottom)
00198 {
00199 ++top;
00200 int lineStart = top*width;
00201 int min_x=std::max(0, left), max_x=std::min(static_cast<int> (width)-1, right);
00202 for (int x=min_x; x<=max_x && !topIsDone; ++x)
00203 if (pcl_isfinite (points[lineStart + x].range))
00204 topIsDone = true;
00205 }
00206
00207 if (top >= static_cast<int> (height))
00208 {
00209 points.clear ();
00210 width = height = 0;
00211 return;
00212 }
00213
00214 while (!rightIsDone)
00215 {
00216 --right;
00217 int min_y=std::max(0, top), max_y=std::min(static_cast<int> (height)-1, bottom);
00218 for (int y=min_y; y<=max_y && !rightIsDone; ++y)
00219 if (pcl_isfinite (points[y*width + right].range))
00220 rightIsDone = true;
00221 }
00222
00223 while (!bottomIsDone)
00224 {
00225 --bottom;
00226 int lineStart = bottom*width;
00227 int min_x=std::max(0, left), max_x=std::min(static_cast<int> (width)-1, right);
00228 for (int x=min_x; x<=max_x && !bottomIsDone; ++x)
00229 if (pcl_isfinite (points[lineStart + x].range))
00230 bottomIsDone = true;
00231 }
00232
00233 while (!leftIsDone)
00234 {
00235 ++left;
00236 int min_y=std::max(0, top), max_y=std::min(static_cast<int> (height)-1, bottom);
00237 for (int y=min_y; y<=max_y && !leftIsDone; ++y)
00238 if (pcl_isfinite (points[y*width + left].range))
00239 leftIsDone = true;
00240 }
00241 left-=borderSize; top-=borderSize; right+=borderSize; bottom+=borderSize;
00242
00243
00244 PointCloud<PointWithRange>::VectorType tmpPoints;
00245 points.swap (tmpPoints);
00246 RangeImage oldRangeImage = *this;
00247 tmpPoints.swap (oldRangeImage.points);
00248
00249 width = right-left+1; height = bottom-top+1;
00250 image_offset_x_ = left+oldRangeImage.image_offset_x_;
00251 image_offset_y_ = top+oldRangeImage.image_offset_y_;
00252 points.resize (width*height);
00253
00254
00255
00256
00257 for (int y=0, oldY=top; y< static_cast<int> (height); ++y,++oldY)
00258 {
00259 for (int x=0, oldX=left; x< static_cast<int> (width); ++x,++oldX)
00260 {
00261 PointWithRange& currentPoint = points[y*width + x];
00262 if (oldX<0 || oldX>= static_cast<int> (oldRangeImage.width) || oldY<0 || oldY>= static_cast<int> (oldRangeImage.height))
00263 {
00264 currentPoint = unobserved_point;
00265 continue;
00266 }
00267 currentPoint = oldRangeImage.points[oldY*oldRangeImage.width + oldX];
00268 }
00269 }
00270 }
00271
00273 void
00274 RangeImage::recalculate3DPointPositions ()
00275 {
00276 for (int y = 0; y < static_cast<int> (height); ++y)
00277 {
00278 for (int x = 0; x < static_cast<int> (width); ++x)
00279 {
00280 PointWithRange& point = points[y*width + x];
00281 if (!pcl_isinf (point.range))
00282 calculate3DPoint (static_cast<float> (x), static_cast<float> (y), point.range, point);
00283 }
00284 }
00285 }
00286
00288 float*
00289 RangeImage::getRangesArray () const
00290 {
00291 int arraySize = width * height;
00292 float* ranges = new float[arraySize];
00293 for (int i=0; i<arraySize; ++i)
00294 ranges[i] = points[i].range;
00295 return ranges;
00296 }
00297
00298
00300 void
00301 RangeImage::getIntegralImage (float*& integral_image, int*& valid_points_num_image) const
00302 {
00303 integral_image = new float[width*height];
00304 float* integral_image_ptr = integral_image;
00305 valid_points_num_image = new int[width*height];
00306 int* valid_points_num_image_ptr = valid_points_num_image;
00307 for (int y = 0; y < static_cast<int> (height); ++y)
00308 {
00309 for (int x = 0; x < static_cast<int> (width); ++x)
00310 {
00311 float& integral_pixel = * (integral_image_ptr++);
00312 integral_pixel = getPoint (x, y).range;
00313 int& valid_points_num = * (valid_points_num_image_ptr++);
00314 valid_points_num = 1;
00315 if (pcl_isinf (integral_pixel))
00316 {
00317 integral_pixel = 0.0f;
00318 valid_points_num = 0;
00319 }
00320 float left_value=0, top_left_value=0, top_value=0;
00321 int left_valid_points=0, top_left_valid_points=0, top_valid_points=0;
00322 if (x>0)
00323 {
00324 left_value = integral_image[y*width+x-1];
00325 left_valid_points = valid_points_num_image[y*width+x-1];
00326 if (y>0)
00327 {
00328 top_left_value = integral_image[ (y-1)*width+x-1];
00329 top_left_valid_points = valid_points_num_image[ (y-1)*width+x-1];
00330 }
00331 }
00332 if (y>0)
00333 {
00334 top_value = integral_image[ (y-1)*width+x];
00335 top_valid_points = valid_points_num_image[ (y-1)*width+x];
00336 }
00337
00338 integral_pixel += left_value + top_value - top_left_value;
00339 valid_points_num += left_valid_points + top_valid_points - top_left_valid_points;
00340 }
00341 }
00342 }
00343
00345 void
00346 RangeImage::setUnseenToMaxRange ()
00347 {
00348 for (unsigned int i=0; i<points.size (); ++i)
00349 if (pcl_isinf (points[i].range))
00350 points[i].range = std::numeric_limits<float>::infinity ();
00351 }
00352
00354 void
00355 RangeImage::getHalfImage (RangeImage& half_image) const
00356 {
00357 half_image.setAngularResolution (2.0f*angular_resolution_x_, 2.0f*angular_resolution_y_);
00358 half_image.image_offset_x_ = image_offset_x_/2;
00359 half_image.image_offset_y_ = image_offset_y_/2;
00360 half_image.width = width/2;
00361 half_image.height = height/2;
00362 half_image.is_dense = is_dense;
00363 half_image.points.clear ();
00364 half_image.points.resize (half_image.width*half_image.height);
00365
00366 int src_start_x = 2*half_image.image_offset_x_ - image_offset_x_,
00367 src_start_y = 2*half_image.image_offset_y_ - image_offset_y_;
00368
00369 for (int dst_y=0; dst_y < static_cast<int> (half_image.height); ++dst_y)
00370 {
00371 for (int dst_x=0; dst_x < static_cast<int> (half_image.width); ++dst_x)
00372 {
00373 PointWithRange& dst_point = half_image.getPoint (dst_x, dst_y);
00374 dst_point=unobserved_point;
00375 int src_x_min = src_start_x + 2*dst_x,
00376 src_x_max = src_x_min + 1,
00377 src_y_min = src_start_y + 2*dst_y,
00378 src_y_max = src_y_min + 1;
00379 for (int src_x=src_x_min; src_x<=src_x_max; ++src_x)
00380 {
00381 for (int src_y=src_y_min; src_y<=src_y_max; ++src_y)
00382 {
00383 if (!isObserved (src_x, src_y))
00384 continue;
00385 const PointWithRange& src_point = getPoint (src_x, src_y);
00386 if (pcl_isfinite (dst_point.range) && src_point.range > dst_point.range)
00387 continue;
00388 dst_point = src_point;
00389 }
00390 }
00391 }
00392 }
00393 }
00394
00396 void
00397 RangeImage::getSubImage (int sub_image_image_offset_x, int sub_image_image_offset_y, int sub_image_width,
00398 int sub_image_height, int combine_pixels, RangeImage& sub_image) const
00399 {
00400 sub_image.setAngularResolution (static_cast<float> (combine_pixels)*angular_resolution_x_,
00401 static_cast<float> (combine_pixels)*angular_resolution_y_);
00402 sub_image.image_offset_x_ = sub_image_image_offset_x;
00403 sub_image.image_offset_y_ = sub_image_image_offset_y;
00404 sub_image.width = sub_image_width;
00405 sub_image.height = sub_image_height;
00406 sub_image.is_dense = is_dense;
00407 sub_image.points.clear ();
00408 sub_image.points.resize (sub_image.width*sub_image.height);
00409
00410 int src_start_x = combine_pixels*sub_image.image_offset_x_ - image_offset_x_,
00411 src_start_y = combine_pixels*sub_image.image_offset_y_ - image_offset_y_;
00412
00413 for (int dst_y=0; dst_y < static_cast<int> (sub_image.height); ++dst_y)
00414 {
00415 for (int dst_x=0; dst_x < static_cast<int> (sub_image.width); ++dst_x)
00416 {
00417 PointWithRange& dst_point = sub_image.getPoint (dst_x, dst_y);
00418 dst_point=unobserved_point;
00419 int src_x_min = src_start_x + combine_pixels*dst_x,
00420 src_x_max = src_x_min + combine_pixels-1,
00421 src_y_min = src_start_y + combine_pixels*dst_y,
00422 src_y_max = src_y_min + combine_pixels-1;
00423 for (int src_x=src_x_min; src_x<=src_x_max; ++src_x)
00424 {
00425 for (int src_y=src_y_min; src_y<=src_y_max; ++src_y)
00426 {
00427 if (!isInImage (src_x, src_y))
00428 continue;
00429 const PointWithRange& src_point = getPoint (src_x, src_y);
00430 if (pcl_isfinite (dst_point.range) && src_point.range > dst_point.range)
00431 continue;
00432 dst_point = src_point;
00433 }
00434 }
00435 }
00436 }
00437 }
00438
00439
00441 void
00442 RangeImage::getMinMaxRanges (float& min_range, float& max_range) const
00443 {
00444 min_range = std::numeric_limits<float>::infinity ();
00445 max_range = -std::numeric_limits<float>::infinity ();
00446 for (unsigned int i=0; i<points.size (); ++i)
00447 {
00448 float range = points[i].range;
00449 if (!pcl_isfinite (range))
00450 continue;
00451 min_range = (std::min) (min_range, range);
00452 max_range = (std::max) (max_range, range);
00453 }
00454 }
00455
00457 void
00458 RangeImage::change3dPointsToLocalCoordinateFrame ()
00459 {
00460 to_world_system_.setIdentity ();
00461 to_range_image_system_.setIdentity ();
00462 recalculate3DPointPositions ();
00463 }
00464
00466 float*
00467 RangeImage::getInterpolatedSurfaceProjection (const Eigen::Affine3f& pose, int pixel_size, float world_size) const
00468 {
00469 float max_dist = 0.5f*world_size,
00470 cell_size = world_size/float (pixel_size);
00471 float world2cell_factor = 1.0f/cell_size,
00472 world2cell_offset = 0.5f*float (pixel_size)-0.5f;
00473 float cell2world_factor = cell_size,
00474 cell2world_offset = -max_dist + 0.5f*cell_size;
00475 Eigen::Affine3f inverse_pose = pose.inverse (Eigen::Isometry);
00476
00477 int no_of_pixels = pixel_size*pixel_size;
00478 float* surface_patch = new float[no_of_pixels];
00479 SET_ARRAY (surface_patch, -std::numeric_limits<float>::infinity (), no_of_pixels);
00480
00481 Eigen::Vector3f position = inverse_pose.translation ();
00482 int middle_x, middle_y;
00483 getImagePoint (position, middle_x, middle_y);
00484 int min_search_radius = 2;
00485 bool still_in_range = true;
00486
00487 for (int radius=0; still_in_range; ++radius)
00488 {
00489 int x=middle_x-radius-1, y=middle_y-radius;
00490 still_in_range = radius<min_search_radius;
00491 for (int i=0; i<8*radius || (radius==0&&i==0); ++i)
00492 {
00493 if (i<=2*radius) ++x; else if (i<=4*radius) ++y; else if (i<=6*radius) --x; else --y;
00494
00495 Eigen::Vector3f point1, point2, point3;
00496 if (!isValid (x,y) || !isValid (x+1,y+1))
00497 continue;
00498 getPoint (x, y, point1);
00499 point1 = pose*point1;
00500 if (fabs (point1[2]) > max_dist)
00501 continue;
00502
00503 getPoint (x+1, y+1, point2);
00504 point2 = pose*point2;
00505 if (fabs (point2[2]) > max_dist)
00506 continue;
00507
00508 for (int triangle_idx=0; triangle_idx<=1; ++triangle_idx)
00509 {
00510 if (triangle_idx==0)
00511 {
00512 if (!isValid (x,y+1))
00513 continue;
00514 getPoint (x, y+1, point3);
00515 }
00516 else
00517 {
00518 if (!isValid (x+1,y))
00519 continue;
00520 getPoint (x+1, y, point3);
00521 }
00522 point3 = pose*point3;
00523 if (fabs (point3[2]) > max_dist)
00524 continue;
00525
00526
00527 if ( (point1[0] < -max_dist && point2[0] < -max_dist && point3[0] < -max_dist) ||
00528 (point1[0] > max_dist && point2[0] > max_dist && point3[0] > max_dist) ||
00529 (point1[1] < -max_dist && point2[1] < -max_dist && point3[1] < -max_dist) ||
00530 (point1[1] > max_dist && point2[1] > max_dist && point3[1] > max_dist))
00531 {
00532 continue;
00533 }
00534
00535 still_in_range = true;
00536
00537
00538 float cell1_x = world2cell_factor*point1[0] + world2cell_offset,
00539 cell1_y = world2cell_factor*point1[1] + world2cell_offset,
00540 cell1_z = point1[2],
00541 cell2_x = world2cell_factor*point2[0] + world2cell_offset,
00542 cell2_y = world2cell_factor*point2[1] + world2cell_offset,
00543 cell2_z = point2[2],
00544 cell3_x = world2cell_factor*point3[0] + world2cell_offset,
00545 cell3_y = world2cell_factor*point3[1] + world2cell_offset,
00546 cell3_z = point3[2];
00547
00548 int min_cell_x = (std::max) (0, int (pcl_lrint (ceil ( (std::min) (cell1_x, (std::min) (cell2_x, cell3_x)))))),
00549 max_cell_x = (std::min) (pixel_size-1, int (pcl_lrint (floor ( (std::max) (cell1_x,
00550 (std::max) (cell2_x, cell3_x)))))),
00551 min_cell_y = (std::max) (0, int (pcl_lrint (ceil ( (std::min) (cell1_y, (std::min) (cell2_y, cell3_y)))))),
00552 max_cell_y = (std::min) (pixel_size-1, int (pcl_lrint (floor ( (std::max) (cell1_y,
00553 (std::max) (cell2_y, cell3_y))))));
00554 if (max_cell_x<min_cell_x || max_cell_y<min_cell_y)
00555 continue;
00556
00557
00558
00559
00560
00561
00562 Eigen::Vector2f cell1 (cell1_x, cell1_y),
00563 cell2 (cell2_x, cell2_y),
00564 cell3 (cell3_x, cell3_y),
00565 v0 = cell3 - cell1,
00566 v1 = cell2 - cell1;
00567 float dot00 = v0.dot (v0),
00568 dot01 = v0.dot (v1),
00569 dot11 = v1.dot (v1),
00570 invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
00571
00572 for (int cell_x=min_cell_x; cell_x<=max_cell_x; ++cell_x)
00573 {
00574 for (int cell_y=min_cell_y; cell_y<=max_cell_y; ++cell_y)
00575 {
00576 Eigen::Vector2f current_cell (cell_x, cell_y),
00577 v2 = current_cell - cell1;
00578 float dot02 = v0.dot (v2),
00579 dot12 = v1.dot (v2),
00580 u = (dot11 * dot02 - dot01 * dot12) * invDenom,
00581 v = (dot00 * dot12 - dot01 * dot02) * invDenom;
00582 bool point_in_triangle = (u > -0.01) && (v >= -0.01) && (u + v <= 1.01);
00583
00584 if (!point_in_triangle)
00585 continue;
00586
00587 float new_value = cell1_z + u* (cell3_z-cell1_z) + v* (cell2_z-cell1_z);
00588
00589 float& value = surface_patch[cell_y*pixel_size + cell_x];
00590 if (pcl_isinf (value))
00591 value = new_value;
00592 else
00593 value = (std::min) (value, new_value);
00594 }
00595 }
00596 }
00597 }
00598 }
00599
00600
00601 for (int cell_y=0; cell_y<pixel_size; ++cell_y)
00602 {
00603 for (int cell_x=0; cell_x<pixel_size; ++cell_x)
00604 {
00605 int index= cell_y*pixel_size + cell_x;
00606 float& value = surface_patch[index];
00607 if (!pcl_isinf (value))
00608 continue;
00609
00610
00611 bool is_background = false;
00612 for (int cell2_y=cell_y-1; cell2_y<=cell_y+1&&!is_background; ++cell2_y)
00613 {
00614 for (int cell2_x=cell_x-1; cell2_x<=cell_x+1; ++cell2_x)
00615 {
00616 if (cell2_x<0||cell2_x>=pixel_size||cell2_y<0||cell2_y>=pixel_size || (cell2_x==cell_x && cell2_y==cell_y))
00617 continue;
00618 float neighbor_value = surface_patch[cell2_y*pixel_size + cell2_x];
00619 if (pcl_isfinite (neighbor_value))
00620 {
00621 float cell_pos_x = static_cast<float> (cell_x) + 0.6f * static_cast<float> (cell_x - cell2_x),
00622 cell_pos_y = static_cast<float> (cell_y) + 0.6f * static_cast<float> (cell_y - cell2_y);
00623 Eigen::Vector3f fake_point (cell2world_factor* (cell_pos_x)+cell2world_offset,
00624 cell2world_factor*cell_pos_y+cell2world_offset, neighbor_value);
00625 fake_point = inverse_pose*fake_point;
00626 float range_difference = getRangeDifference (fake_point);
00627 if (range_difference > max_dist)
00628 {
00629 value = std::numeric_limits<float>::infinity ();
00630 is_background = true;
00631 break;
00632 }
00633 }
00634 }
00635 }
00636 if (is_background)
00637 {
00638
00639 for (int cell2_y=cell_y-1; cell2_y<=cell_y+1; ++cell2_y)
00640 {
00641 for (int cell2_x=cell_x-1; cell2_x<=cell_x+1; ++cell2_x)
00642 {
00643 if (cell2_x<0||cell2_x>=pixel_size||cell2_y<0||cell2_y>=pixel_size || (cell2_x==cell_x && cell2_y==cell_y))
00644 continue;
00645 int index2 = cell2_y*pixel_size + cell2_x;
00646 float& neighbor_value = surface_patch[index2];
00647 if (pcl_isinf (neighbor_value) && neighbor_value<0)
00648 neighbor_value = std::numeric_limits<float>::infinity ();
00649 }
00650 }
00651 }
00652 }
00653 }
00654
00655 return surface_patch;
00656 }
00657
00659 float* RangeImage::getInterpolatedSurfaceProjection (const Eigen::Vector3f& point, int pixel_size,
00660 float world_size) const
00661 {
00662 Eigen::Affine3f pose = getTransformationToViewerCoordinateFrame (point);
00663 return (getInterpolatedSurfaceProjection (pose, pixel_size, world_size));
00664 }
00665
00667 bool
00668 RangeImage::getNormalBasedUprightTransformation (const Eigen::Vector3f& point, float max_dist,
00669 Eigen::Affine3f& transformation) const
00670 {
00671 int x, y;
00672 getImagePoint (point, x, y);
00673
00674 Eigen::Vector3f neighbor;
00675 VectorAverage3f vector_average;
00676 float max_dist_squared=max_dist*max_dist, max_dist_reciprocal=1.0f/max_dist;
00677
00678 bool still_in_range = true;
00679 for (int radius=1; still_in_range; ++radius)
00680 {
00681 int x2=x-radius-1, y2=y-radius;
00682 still_in_range = false;
00683 for (int i=0; i<8*radius; ++i)
00684 {
00685 if (i<=2*radius) ++x2; else if (i<=4*radius) ++y2; else if (i<=6*radius) --x2; else --y2;
00686 if (!isValid (x2, y2))
00687 {
00688 continue;
00689 }
00690 getPoint (x2, y2, neighbor);
00691 float distance_squared = (neighbor-point).squaredNorm ();
00692 if (distance_squared > max_dist_squared)
00693 {
00694 continue;
00695 }
00696 still_in_range = true;
00697 float distance = sqrtf (distance_squared),
00698 weight = distance*max_dist_reciprocal;
00699 vector_average.add (neighbor, weight);
00700 }
00701 }
00702
00703 Eigen::Vector3f normal, point_on_plane;
00704 if (vector_average.getNoOfSamples () > 10)
00705 {
00706 Eigen::Vector3f eigen_values, eigen_vector2, eigen_vector3;
00707 vector_average.doPCA (eigen_values, normal, eigen_vector2, eigen_vector3);
00708 if (normal.dot ( (vector_average.getMean ()-getSensorPos ()).normalized ()) < 0.0f)
00709 normal *= -1.0f;
00710 point_on_plane = (normal.dot (vector_average.getMean ()) - normal.dot (point))*normal + point;
00711 }
00712 else
00713 {
00714 if (!getNormalForClosestNeighbors (x, y, 2, point, 15, normal, &point_on_plane, 1))
00715 return false;
00716 }
00717 getTransformationFromTwoUnitVectorsAndOrigin (Eigen::Vector3f (0.0f, 1.0f, 0.0f),
00718 normal, point_on_plane, transformation);
00719
00720 return (true);
00721 }
00722
00724 void
00725 RangeImage::getSurfaceAngleChangeImages (int radius, float*& angle_change_image_x, float*& angle_change_image_y) const
00726 {
00727 MEASURE_FUNCTION_TIME;
00728 int size = width*height;
00729 angle_change_image_x = new float[size];
00730 angle_change_image_y = new float[size];
00731 for (int y=0; y<int (height); ++y)
00732 {
00733 for (int x=0; x<int (width); ++x)
00734 {
00735 int index = y*width+x;
00736 getSurfaceAngleChange (x, y, radius, angle_change_image_x[index], angle_change_image_y[index]);
00737 }
00738 }
00739 }
00740
00742 void
00743 RangeImage::getAcutenessValueImages (int pixel_distance, float*& acuteness_value_image_x,
00744 float*& acuteness_value_image_y) const
00745 {
00746 MEASURE_FUNCTION_TIME;
00747 int size = width*height;
00748 acuteness_value_image_x = new float[size];
00749 acuteness_value_image_y = new float[size];
00750 for (int y=0; y<int (height); ++y)
00751 {
00752 for (int x=0; x<int (width); ++x)
00753 {
00754 int index = y*width+x;
00755 acuteness_value_image_x[index] = getAcutenessValue (x, y, x+pixel_distance, y);
00756 acuteness_value_image_y[index] = getAcutenessValue (x, y, x, y+pixel_distance);
00757 }
00758 }
00759 }
00760
00762 float*
00763 RangeImage::getImpactAngleImageBasedOnLocalNormals (int radius) const
00764 {
00765 MEASURE_FUNCTION_TIME;
00766 int size = width*height;
00767 float* impact_angle_image = new float[size];
00768 for (int y=0; y<int (height); ++y)
00769 {
00770 for (int x=0; x<int (width); ++x)
00771 {
00772 impact_angle_image[y*width+x] = getImpactAngleBasedOnLocalNormal (x, y, radius);
00773 }
00774 }
00775 return impact_angle_image;
00776 }
00777
00779 void
00780 RangeImage::getRangeImageWithSmoothedSurface (int radius, RangeImage& smoothed_range_image) const
00781 {
00782 int step_size = (std::max) (1, radius/2);
00783 int no_of_nearest_neighbors = static_cast<int> (pow (static_cast<double> (radius / step_size + 1), 2.0));
00784
00785 smoothed_range_image = *this;
00786 Eigen::Vector3f sensor_pos = getSensorPos ();
00787 for (int y=0; y<int (height); ++y)
00788 {
00789 for (int x=0; x<int (width); ++x)
00790 {
00791 PointWithRange& point = smoothed_range_image.getPoint (x, y);
00792 if (pcl_isinf (point.range))
00793 continue;
00794 Eigen::Vector3f normal, mean, eigen_values;
00795 float used_squared_max_distance;
00796 getSurfaceInformation (x, y, radius, point.getVector3fMap (), no_of_nearest_neighbors,
00797 step_size, used_squared_max_distance,
00798 normal, mean, eigen_values);
00799
00800 Eigen::Vector3f viewing_direction = (point.getVector3fMap ()-sensor_pos).normalized ();
00801 float new_range = normal.dot (mean-sensor_pos) / normal.dot (viewing_direction);
00802 point.range = new_range;
00803 calculate3DPoint (static_cast<float> (x), static_cast<float> (y), point.range, point);
00804
00805 const PointWithRange& original_point = getPoint (x, y);
00806 float distance_squared = squaredEuclideanDistance (original_point, point);
00807 if (distance_squared > used_squared_max_distance)
00808 point = original_point;
00809 }
00810 }
00811 }
00812
00814 void
00815 RangeImage::extractFarRanges (const pcl::PCLPointCloud2& point_cloud_data,
00816 PointCloud<PointWithViewpoint>& far_ranges)
00817 {
00818 int x_idx = -1, y_idx = -1, z_idx = -1,
00819 vp_x_idx = -1, vp_y_idx = -1, vp_z_idx = -1, distance_idx = -1;
00820 for (int d = 0; d < static_cast<int> (point_cloud_data.fields.size ()); ++d)
00821 {
00822 if (point_cloud_data.fields[d].name == "x") x_idx = d;
00823 if (point_cloud_data.fields[d].name == "y") y_idx = d;
00824 if (point_cloud_data.fields[d].name == "z") z_idx = d;
00825 if (point_cloud_data.fields[d].name == "vp_x") vp_x_idx = d;
00826 if (point_cloud_data.fields[d].name == "vp_y") vp_y_idx = d;
00827 if (point_cloud_data.fields[d].name == "vp_z") vp_z_idx = d;
00828 if (point_cloud_data.fields[d].name == "distance") distance_idx = d;
00829 }
00830
00831 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)
00832 {
00833 return;
00834 }
00835
00836 int point_step = point_cloud_data.point_step;
00837 const unsigned char* data = &point_cloud_data.data[0];
00838 int x_offset = point_cloud_data.fields[x_idx].offset,
00839 y_offset = point_cloud_data.fields[y_idx].offset,
00840 z_offset = point_cloud_data.fields[z_idx].offset,
00841 vp_x_offset = point_cloud_data.fields[vp_x_idx].offset,
00842 vp_y_offset = point_cloud_data.fields[vp_y_idx].offset,
00843 vp_z_offset = point_cloud_data.fields[vp_z_idx].offset,
00844 distance_offset = point_cloud_data.fields[distance_idx].offset;
00845
00846 for (size_t point_idx = 0; point_idx < point_cloud_data.width*point_cloud_data.height; ++point_idx)
00847 {
00848 float x = *reinterpret_cast<const float*> (data+x_offset),
00849 y = *reinterpret_cast<const float*> (data+y_offset),
00850 z = *reinterpret_cast<const float*> (data+z_offset),
00851 vp_x = *reinterpret_cast<const float*> (data+vp_x_offset),
00852 vp_y = *reinterpret_cast<const float*> (data+vp_y_offset),
00853 vp_z = *reinterpret_cast<const float*> (data+vp_z_offset),
00854 distance = *reinterpret_cast<const float*> (data+distance_offset);
00855 data+=point_step;
00856
00857 if (!pcl_isfinite (x) && pcl_isfinite (distance))
00858 {
00859 PointWithViewpoint point;
00860 point.x=distance; point.y=y; point.z=z;
00861 point.vp_x=vp_x; point.vp_y=vp_y; point.vp_z=vp_z;
00862 far_ranges.points.push_back (point);
00863 }
00864 }
00865 far_ranges.width= static_cast<uint32_t> (far_ranges.points.size ()); far_ranges.height = 1;
00866 far_ranges.is_dense = false;
00867 }
00868
00870 float
00871 RangeImage::getOverlap (const RangeImage& other_range_image, const Eigen::Affine3f& relative_transformation,
00872 int search_radius, float max_distance, int pixel_step) const
00873 {
00874 int hits_counter=0, valid_points_counter=0;
00875
00876 float max_distance_squared = max_distance*max_distance;
00877
00878 # pragma omp parallel for num_threads (max_no_of_threads) default (shared) schedule (dynamic, 1) \
00879 reduction (+ : valid_points_counter) reduction (+ : hits_counter)
00880 for (int other_y=0; other_y<int (other_range_image.height); other_y+=pixel_step)
00881 {
00882 for (int other_x=0; other_x<int (other_range_image.width); other_x+=pixel_step)
00883 {
00884 const PointWithRange& point = other_range_image.getPoint (other_x, other_y);
00885 if (!pcl_isfinite (point.range))
00886 continue;
00887 ++valid_points_counter;
00888 Eigen::Vector3f transformed_point = relative_transformation * point.getVector3fMap ();
00889 int x,y;
00890 getImagePoint (transformed_point, x, y);
00891 float closest_distance = max_distance_squared;
00892 Eigen::Vector3f closest_point (0.0f, 0.0f, 0.0f);
00893 bool found_neighbor = false;
00894 for (int y2=y-pixel_step*search_radius; y2<=y+pixel_step*search_radius; y2+=pixel_step)
00895 {
00896 for (int x2=x-pixel_step*search_radius; x2<=x+pixel_step*search_radius; x2+=pixel_step)
00897 {
00898 const PointWithRange& neighbor = getPoint (x2, y2);
00899 if (!pcl_isfinite (neighbor.range))
00900 continue;
00901 float distance = (transformed_point-neighbor.getVector3fMap ()).squaredNorm ();
00902 if (distance < closest_distance)
00903 {
00904 closest_distance = distance;
00905 closest_point = neighbor.getVector3fMap ();
00906 found_neighbor = true;
00907 }
00908 }
00909 }
00910
00911 if (found_neighbor)
00912 {
00913 ++hits_counter;
00914 }
00915 }
00916 }
00917 return static_cast<float> (hits_counter)/static_cast<float> (valid_points_counter);
00918 }
00919
00921 void
00922 RangeImage::getBlurredImageUsingIntegralImage (int blur_radius, float* integral_image, int* valid_points_num_image,
00923 RangeImage& blurred_image) const
00924 {
00925 this->copyTo(blurred_image);
00926 for (int y=0; y<int (height); ++y)
00927 {
00928 for (int x=0; x<int (width); ++x)
00929 {
00930 const PointWithRange& old_point = getPoint (x, y);
00931 PointWithRange& new_point = blurred_image.getPoint (x, y);
00932 if (!pcl_isfinite (old_point.range))
00933 continue;
00934
00935 int top= (std::max) (-1, y-blur_radius-1), right = (std::min) (static_cast<int> (width)-1, x+blur_radius), bottom =
00936 (std::min) (static_cast<int> (height)-1, y+blur_radius), left= (std::max) (-1, x-blur_radius-1);
00937
00938 float top_left_value=0, top_right_value=0,
00939 bottom_right_value=integral_image[bottom*width+right], bottom_left_value=0;
00940 int top_left_valid_points=0, top_right_valid_points=0,
00941 bottom_right_valid_points=valid_points_num_image[bottom*width+right], bottom_left_valid_points=0;
00942 if (left>=0)
00943 {
00944 bottom_left_value = integral_image[bottom*width+left];
00945 bottom_left_valid_points = valid_points_num_image[bottom*width+left];
00946 if (top>=0)
00947 {
00948 top_left_value = integral_image[top*width+left];
00949 top_left_valid_points = valid_points_num_image[top*width+left];
00950 }
00951 }
00952 if (top>=0)
00953 {
00954 top_right_value = integral_image[top*width+right];
00955 top_right_valid_points = valid_points_num_image[top*width+right];
00956 }
00957 int valid_points_num = bottom_right_valid_points + top_left_valid_points - bottom_left_valid_points -
00958 top_right_valid_points;
00959 new_point.range = (bottom_right_value + top_left_value - bottom_left_value - top_right_value) /
00960 static_cast<float> (valid_points_num);
00961 }
00962 }
00963 blurred_image.recalculate3DPointPositions ();
00964 }
00965
00967 void
00968 RangeImage::getBlurredImage (int blur_radius, RangeImage& blurred_image) const
00969 {
00970
00971
00972 if (blur_radius > 1)
00973 {
00974 float* integral_image;
00975 int* valid_points_num_image;
00976 getIntegralImage (integral_image, valid_points_num_image);
00977 getBlurredImageUsingIntegralImage (blur_radius, integral_image, valid_points_num_image, blurred_image);
00978 delete[] integral_image;
00979 delete[] valid_points_num_image;
00980 return;
00981 }
00982
00983 this->copyTo(blurred_image);
00984
00985 if (blur_radius==0)
00986 return;
00987
00988 for (int y=0; y < static_cast<int> (height); ++y)
00989 {
00990 for (int x=0; x < static_cast<int> (width); ++x)
00991 {
00992 PointWithRange& new_point = blurred_image.getPoint (x, y);
00993 const PointWithRange& original_point = getPoint (x, y);
00994 if (!pcl_isfinite (original_point.range))
00995 continue;
00996
00997 new_point.range = 0.0f;
00998 float weight_sum = 0.0f;
00999 for (int y2=y-blur_radius; y2<y+blur_radius; ++y2)
01000 {
01001 for (int x2=x-blur_radius; x2<x+blur_radius; ++x2)
01002 {
01003 if (!isValid (x2,y2))
01004 continue;
01005 new_point.range += getPoint (x2, y2).range;
01006 weight_sum += 1.0f;
01007 }
01008 }
01009 new_point.range /= weight_sum;
01010 }
01011 }
01012 blurred_image.recalculate3DPointPositions ();
01013 }
01014
01016 void
01017 RangeImage::copyTo (RangeImage& other) const
01018 {
01019 other = *this;
01020 }
01021
01022 }
01023