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
00038
00039 #include <narf_recognition/object_model.h>
00040
00041 #include <pcl/common/transformation_from_correspondences.h>
00042 #include <pcl/common/transforms.h>
00043 #include <iostream>
00044 using std::cout;
00045 using std::cerr;
00046 using std::string;
00047 using std::min;
00048 using std::max;
00049 using std::vector;
00050 #include <cmath>
00051
00052 #include <pcl/common/common_headers.h>
00053
00054 #include <pcl/features/range_image_border_extractor.h>
00055 #include <pcl/keypoints/narf_keypoint.h>
00056
00057 using Eigen::Vector3f;
00058 using Eigen::Affine3f;
00059
00060 namespace pcl {
00061
00062 ObjectModel::ObjectModel()
00063 {
00064 clear();
00065 }
00066
00067 ObjectModel::~ObjectModel()
00068 {
00069 clear();
00070 }
00071
00072 void ObjectModel::clear(bool keep_point_cloud)
00073 {
00074 id_ = 0;
00075 name_ = "";
00076 if (!keep_point_cloud)
00077 point_cloud_ = PointCloudType();
00078 clearViews();
00079 center_ = Vector3f(0.0f, 0.0f, 0.0f);
00080 radius_ = 0.0f;
00081 is_single_view_model_ = false;
00082 }
00083
00084 void ObjectModel::clearViews()
00085 {
00086 views_.clear();
00087 views_for_validation_points_.clear();
00088 validation_points_.clear();
00089 }
00090
00091 void ObjectModel::updateCenterAndRadius()
00092 {
00093
00094 Vector3f bb_min(INFINITY, INFINITY, INFINITY), bb_max(-INFINITY, -INFINITY, -INFINITY);
00095 for (unsigned int i=0; i<point_cloud_.points.size(); ++i)
00096 {
00097 const PointType& p = point_cloud_.points[i];
00098 bb_min[0]=min(bb_min[0], p.x); bb_min[1]=min(bb_min[1], p.y); bb_min[2]=min(bb_min[2], p.z);
00099 bb_max[0]=max(bb_max[0], p.x); bb_max[1]=max(bb_max[1], p.y); bb_max[2]=max(bb_max[2], p.z);
00100 }
00101 center_ = 0.5f * (bb_min+bb_max);
00102
00103 radius_ = 0.0f;
00104 for (unsigned int i=0; i<point_cloud_.points.size(); ++i)
00105 {
00106 const PointType& p = point_cloud_.points[i];
00107 radius_ = max(radius_, (center_-Vector3f(p.x, p.y, p.z)).norm());
00108 }
00109
00110 }
00111
00112 void ObjectModel::sampleViews2D(int no_of_views, int first_layer, int last_layer,
00113 float angular_resolution, float distance,
00114 std::vector<RangeImage, Eigen::aligned_allocator<RangeImage> >* views)
00115 {
00116
00117 views = (views==NULL ? &views_ : views);
00118 if (radius_ == 0.0f)
00119 {
00120 cerr << __PRETTY_FUNCTION__<<": radius_ is 0.0 => calling updateCenterAndRadius()\n";
00121 updateCenterAndRadius();
00122 }
00123
00124 for (int layer=first_layer; layer<=last_layer; ++layer) {
00125 for (int view_index=0; view_index<no_of_views; ++view_index)
00126 {
00127 float angle = deg2rad(360.f)*float(view_index)/float(no_of_views) - deg2rad(180.f);
00128 Vector3f direction(cosf(angle), -0.5f*float(layer), sinf(angle));
00129 addSimulatedView(direction, angular_resolution, distance, views);
00130 }
00131 }
00132 }
00133
00134 void ObjectModel::sampleViews3D(float sample_angular_resolution, float angular_resolution, float distance,
00135 std::vector<RangeImage, Eigen::aligned_allocator<RangeImage> >* views)
00136 {
00137 views = (views==NULL ? &views_ : views);
00138 if (radius_ == 0.0f)
00139 {
00140 cerr << __PRETTY_FUNCTION__<<": radius_ is 0.0 => calling updateCenterAndRadius()\n";
00141 updateCenterAndRadius();
00142 }
00143
00144 int no_of_steps_y = lrint(deg2rad(180.0f)/sample_angular_resolution)+1;
00145
00146 float step_size_y = deg2rad(180.0f)/float(no_of_steps_y-1);
00147 for (int step_y=0; step_y<no_of_steps_y; ++step_y)
00148 {
00149 float angle_y = step_y*step_size_y - deg2rad(90.0f);
00150 int no_of_steps_x = max(1, (int)(lrint(cosf(angle_y)*deg2rad(360.0f) / sample_angular_resolution)));
00151
00152 float step_size_x = deg2rad(360.0f)/float(no_of_steps_x);
00153
00154 for (int step_x=0; step_x<no_of_steps_x; ++step_x)
00155 {
00156 float angle_x = step_x*step_size_x - deg2rad(180.0f);
00157
00158 Vector3f direction(sinf(angle_x) * cosf(angle_y), sinf(angle_y), cosf(angle_x)*cosf(angle_y));
00159
00160 addSimulatedView(direction, angular_resolution, distance, views);
00161 }
00162 }
00163 }
00164
00165 void ObjectModel::addSimulatedView(const Vector3f& direction, float angular_resolution, float distance,
00166 std::vector<RangeImage, Eigen::aligned_allocator<RangeImage> >* views)
00167 {
00168 views = (views==NULL ? &views_ : views);
00169 if (distance <= 0.0f)
00170 distance = 5.0f*radius_;
00171
00172 Vector3f viewpoint = center_ + (radius_+distance)*direction;
00173 float actual_distance = INFINITY;
00174 for (unsigned int i=0; i<point_cloud_.points.size(); ++i)
00175 {
00176 const PointType& p = point_cloud_.points[i];
00177 actual_distance = min(actual_distance, (viewpoint-Vector3f(p.x, p.y, p.z)).norm());
00178 }
00179
00180 viewpoint = viewpoint - (actual_distance-distance)*direction;
00181
00182 Affine3f viewer_pose = getViewerPose(viewpoint);
00183
00184 views->push_back(RangeImage());
00185 RangeImage& view = views->back();
00186
00187 createView(viewer_pose, angular_resolution, view);
00188 }
00189
00190 float ObjectModel::getMaxAngleSize(const Eigen::Affine3f& viewer_pose) const
00191 {
00192 return RangeImage::getMaxAngleSize(viewer_pose, center_, radius_);
00193 }
00194
00195 void ObjectModel::addView(const Eigen::Affine3f& viewer_pose, float angular_resolution)
00196 {
00197
00198 views_.push_back(RangeImage());
00199 createView(viewer_pose, angular_resolution, views_.back());
00200 }
00201
00202 void ObjectModel::createView(const Affine3f& viewer_pose, float angular_resolution, RangeImage& view) const
00203 {
00204 float noise_level = 0.05f*radius_;
00205 view.createFromPointCloud(point_cloud_, angular_resolution, deg2rad(360.0f), deg2rad(180.0f), viewer_pose, RangeImage::CAMERA_FRAME, noise_level, 0.0, 1);
00206
00207 view.setUnseenToMaxRange();
00208 }
00209
00210 Affine3f ObjectModel::getViewerPose(const Vector3f& viewpoint) const
00211 {
00212 Affine3f viewer_pose;
00213 Vector3f viewing_direction = (center_-viewpoint).normalized(),
00214 up_vector(0.0f, 1.0f, 0.0f);
00215 getTransformationFromTwoUnitVectorsAndOrigin(up_vector, viewing_direction, viewpoint, viewer_pose);
00216 viewer_pose = viewer_pose.inverse();
00217 return viewer_pose;
00218 }
00219
00220 void ObjectModel::extractNARFsForCompleteSurface(unsigned int descriptor_size, float size_in_world, bool rotation_invariant, vector<vector<Narf*>*>& features) const
00221 {
00222 freeFeatureListMemory(features);
00223
00224 std::vector<float> rotations, strengths;
00225 for (unsigned int view_index=0; view_index<views_.size(); ++view_index)
00226 {
00227 const RangeImage& view = views_[view_index];
00228
00229 features.push_back(new vector<Narf*>);
00230 vector<Narf*>& features_of_current_view = *features.back();
00231
00232 for (unsigned int y=0; y<view.height; ++y)
00233 {
00234 for (unsigned int x=0; x<view.width; ++x)
00235 {
00236 Narf::extractFromRangeImageAndAddToList(view, x, y, descriptor_size, size_in_world, rotation_invariant, features_of_current_view);
00237 }
00238 }
00239
00240 }
00241 }
00242
00243 void ObjectModel::extractInterestPoints(int view_ix, float support_size, NarfKeypoint& interest_point_detector,
00244 PointCloud<InterestPoint>& interest_points) const
00245 {
00246 float original_support_size = interest_point_detector.getParameters().support_size;
00247 interest_point_detector.getParameters().support_size = support_size;
00248 interest_point_detector.setRangeImage(&views_[view_ix]);
00249 interest_points = interest_point_detector.getInterestPoints();
00250
00251 interest_point_detector.setRangeImage(NULL);
00252 interest_point_detector.getParameters().support_size = original_support_size;
00253 }
00254
00255 void ObjectModel::extractNARFsForInterestPoints(unsigned int descriptor_size, float size_in_world,
00256 bool rotation_invariant, NarfKeypoint& interest_point_detector,
00257 vector<vector<Narf*>*>& features) const
00258 {
00259 freeFeatureListMemory(features);
00260
00261 std::vector<float> rotations, strengths;
00262 for (unsigned int view_index=0; view_index<views_.size(); ++view_index)
00263 {
00264 const RangeImage& view = views_[view_index];
00265
00266 PointCloud<InterestPoint> interest_points;
00267 extractInterestPoints(view_index, size_in_world, interest_point_detector, interest_points);
00268
00269
00270 features.push_back(new vector<Narf*>);
00271 vector<Narf*>& features_of_current_view = *features.back();
00272
00273 Narf::extractForInterestPoints(view, interest_points, descriptor_size, size_in_world, rotation_invariant, features_of_current_view);
00274
00275 }
00276 }
00277
00278
00279 void ObjectModel::getTransformedPointCloud(const Affine3f& transformation, ObjectModel::PointCloudType& output) const
00280 {
00281 pcl::transformPointCloud(point_cloud_, output, transformation);
00282 }
00283
00284 void ObjectModel::updateValidationPoints(unsigned int no_of_surface_points, unsigned int no_of_border_points, float sample_resolution,
00285 NarfKeypoint* interest_point_detector, float support_size)
00286 {
00287
00288
00289 if (is_single_view_model_)
00290 {
00291 views_for_validation_points_ = views_;
00292 }
00293 else
00294 {
00295 views_for_validation_points_.clear();
00296 sampleViews3D(sample_resolution, deg2rad(0.4f), -1.0f, &views_for_validation_points_);
00297 }
00298
00299 validation_points_.clear();
00300 validation_points_.resize(views_for_validation_points_.size());
00301
00302 for (unsigned int view_idx=0; view_idx<views_for_validation_points_.size(); ++view_idx)
00303 {
00304
00305 const RangeImage& view = views_for_validation_points_[view_idx];
00306 ValidationPoints& validation_points_for_view = validation_points_[view_idx];
00307
00308 int width=view.width, height=view.height;
00309 vector<Eigen::Vector3f> surface_points, border_points;
00310 for (int x=0; x<width; ++x)
00311 {
00312 for (int y=0; y<height; ++y)
00313 {
00314 int index = y*width+x;
00315 const PointWithRange& point = view.getPoint(index);
00316 if (!pcl_isfinite(point.range))
00317 continue;
00318 bool is_border_point=false;
00319 for (int y2=y-1; y2<=y+1; ++y2)
00320 {
00321 for (int x2=(y2==y ? x-1 : x); x2<=(y2==y ? x+1 : x); x2+=2)
00322 {
00323 if (!view.isInImage(x2,y2))
00324 continue;
00325 const PointWithRange& point2 = view.getPoint(x2, y2);
00326 if (std::isinf(point2.range) && point2.range>0.0f)
00327 {
00328 is_border_point = true;
00329 break;
00330 }
00331 }
00332 }
00333 Eigen::Vector3f point_eigen;
00334 view.getPoint(x, y, point_eigen);
00335 if (is_border_point)
00336 border_points.push_back(point_eigen);
00337 else if (interest_point_detector == NULL)
00338 surface_points.push_back(point_eigen);
00339 }
00340 }
00341
00342
00343 if (interest_point_detector != NULL)
00344 {
00345 PointCloud<InterestPoint> interest_points;
00346 float original_distance_for_additional_points = interest_point_detector->getParameters().distance_for_additional_points;
00347 interest_point_detector->getParameters().distance_for_additional_points = 0.0f;
00348 extractInterestPoints(view_idx, support_size, *interest_point_detector, interest_points);
00349 for (unsigned int i=0; i<interest_points.points.size(); ++ i)
00350 surface_points.push_back(interest_points.points[i].getVector3fMap());
00351 interest_point_detector->getParameters().distance_for_additional_points = original_distance_for_additional_points;
00352 }
00353
00354
00355 getUniformlyDistributedPoints(surface_points, no_of_surface_points, validation_points_for_view.surface);
00356 getUniformlyDistributedPoints(border_points, no_of_border_points, validation_points_for_view.border);
00357 }
00358 }
00359
00360
00361 void ObjectModel::getUniformlyDistributedPoints(const vector<Eigen::Vector3f>& points, int no_of_points, vector<Eigen::Vector3f>& result)
00362 {
00363 if (points.empty() || no_of_points==0)
00364 return;
00365
00366 no_of_points = std::min(no_of_points, (int)points.size());
00367
00368 std::multimap<float, Vector3f> distance_sorted_points1, distance_sorted_points2;
00369 std::multimap<float, Vector3f>* current_points=&distance_sorted_points1, * new_points=&distance_sorted_points2;
00370 result.push_back(points[0]);
00371
00372 for (unsigned int i=1; i<points.size(); ++i)
00373 current_points->insert(std::make_pair(INFINITY, points[i]));
00374
00375 while ((int)result.size() < no_of_points)
00376 {
00377 new_points->clear();
00378 for (std::multimap<float, Vector3f>::const_iterator it=current_points->begin(); it!=current_points->end(); ++it)
00379 {
00380 const Vector3f& point = it->second;
00381 float distance_to_last_point = (result.back()-point).squaredNorm();
00382 float distance = min(it->first, distance_to_last_point);
00383 if (distance > 0.0f)
00384 new_points->insert(std::make_pair(distance, point));
00385 }
00386 std::swap(current_points, new_points);
00387
00388 result.push_back(current_points->rbegin()->second);
00389 }
00390 }
00391
00392 Eigen::Affine3f ObjectModel::doFastICP(const Eigen::Affine3f& initial_guess, const RangeImage& range_image,
00393 int search_radius, int no_of_surface_points_to_use,
00394 int no_of_border_points_to_use, int num_iterations,
00395 float max_distance_start, float max_distance_end) const
00396 {
00397 if (max_distance_start <= 0.0f)
00398 max_distance_start = 0.05f*radius_;
00399 if (max_distance_end <= 0.0f)
00400 max_distance_end = 0.5*max_distance_start;
00401 Affine3f model_viewer_pose = initial_guess.inverse()*range_image.getTransformationToWorldSystem();
00402 int view_idx = getClosestValidationPointViewIdx(model_viewer_pose);
00403 const ValidationPoints& validation_points_for_view = validation_points_[view_idx];
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415 float max_distance = max_distance_start,
00416 max_distance_reduction = (max_distance_start-max_distance_end)/float(num_iterations);
00417 Affine3f ret = initial_guess;
00418 no_of_surface_points_to_use = min(no_of_surface_points_to_use, (int)validation_points_for_view.surface.size());
00419 no_of_border_points_to_use = min(no_of_border_points_to_use, (int)validation_points_for_view.border.size());
00420
00421
00422 TransformationFromCorrespondences transformation_from_correspondeces;
00423 for (int iteration=1; iteration<=num_iterations; ++iteration)
00424 {
00425 float max_distance_squared = max_distance*max_distance;
00426 transformation_from_correspondeces.reset();
00427 for (int point_idx=0; point_idx<no_of_surface_points_to_use+no_of_border_points_to_use; ++point_idx)
00428 {
00429 const Vector3f* point;
00430 if (point_idx<no_of_surface_points_to_use)
00431 point = &validation_points_for_view.surface[point_idx];
00432 else
00433 point = &validation_points_for_view.border[point_idx-no_of_surface_points_to_use];
00434 Vector3f transformed_point = ret * *point;
00435 int x,y;
00436 range_image.getImagePoint(transformed_point, x, y);
00437 float closest_distance = max_distance_squared;
00438 Vector3f closest_point(0,0,0);
00439 bool found_neighbor = false;
00440 for (int y2=y-search_radius; y2<=y+search_radius; ++y2)
00441 {
00442 for (int x2=x-search_radius; x2<=x+search_radius; ++x2)
00443 {
00444 const PointWithRange& neighbor = range_image.getPoint(x2, y2);
00445 if (!pcl_isfinite(neighbor.range))
00446 continue;
00447 float distance = (transformed_point-neighbor.getVector3fMap()).squaredNorm();
00448 if (distance < closest_distance)
00449 {
00450 closest_distance = distance;
00451 closest_point = neighbor.getVector3fMap();
00452 found_neighbor = true;
00453 }
00454 }
00455 }
00456 if (found_neighbor)
00457 {
00458
00459 transformation_from_correspondeces.add(*point, closest_point);
00460 }
00461 }
00462
00463
00464 if (transformation_from_correspondeces.getNoOfSamples() < 3)
00465 return ret;
00466
00467 ret = transformation_from_correspondeces.getTransformation();
00468
00469
00470 max_distance -= max_distance_reduction;
00471 }
00472
00473
00474 return ret;
00475 }
00476
00477 Eigen::Affine3f ObjectModel::doSlowICP(const Eigen::Affine3f& initial_guess, const RangeImage& range_image,
00478 int search_radius, int num_iterations, float max_distance_start,
00479 float max_distance_end) const
00480 {
00481 if (max_distance_start <= 0.0f)
00482 max_distance_start = 0.05f*radius_;
00483 if (max_distance_end <= 0.0f)
00484 max_distance_end = 0.5*max_distance_start;
00485 Affine3f viewer_pose = initial_guess.inverse()*range_image.getTransformationToWorldSystem();
00486 float angular_resolution = range_image.getAngularResolution();
00487
00488 RangeImage simulated_view;
00489 float noise_level = 0.1*radius_;
00490 simulated_view.createFromPointCloud(point_cloud_, angular_resolution, deg2rad(360.0f), deg2rad(180.0f), viewer_pose,
00491 RangeImage::CAMERA_FRAME, noise_level);
00492 RangeImage::VectorOfEigenVector3f points;
00493 for (unsigned int i=0; i<simulated_view.points.size(); ++i)
00494
00495 if (simulated_view.isValid(i))
00496 points.push_back(simulated_view.getPoint(i).getVector3fMap());
00497
00498 return range_image.doIcp(points, initial_guess, search_radius, max_distance_start, max_distance_end, num_iterations);
00499 }
00500
00501 void ObjectModel::addNoise(float max_noise)
00502 {
00503 double normalization_factor = double(2.0*max_noise) / double(RAND_MAX),
00504 offset = -max_noise;
00505 clear(true);
00506
00507 for (unsigned int point_idx=0; point_idx<point_cloud_.points.size(); ++point_idx)
00508 {
00509 PointType& point = point_cloud_.points[point_idx];
00510 point.x += normalization_factor*double(rand()) + offset;
00511 point.y += normalization_factor*double(rand()) + offset;
00512 point.z += normalization_factor*double(rand()) + offset;
00513 }
00514 }
00515
00516 float ObjectModel::getMaximumPlaneSize (float initial_max_plane_error) const
00517 {
00518 float max_plane_size = 0.0f;
00519 std::vector<RangeImage::ExtractedPlane> planes;
00520 for (int view_idx=0; view_idx<int(views_.size()); ++view_idx)
00521 {
00522 const RangeImage& view = views_[view_idx];
00523 planes.clear ();
00524 view.extractPlanes (initial_max_plane_error, planes);
00525 for (int plane_idx=0; plane_idx<int(planes.size()); ++plane_idx)
00526 max_plane_size = std::max(max_plane_size, planes[plane_idx].maximum_extensions[2]);
00527 }
00528 return max_plane_size;
00529 }
00530
00531 }
00532