NARF Keypoint Test

NARF is a method for interest point detection developed by the PCL-community. However the algorithm is different, it is mostly used as a license free variant of the SIFT-algorithm. These kind of algorithms have proven to be very effective for object recognition, which is an important reason I found it necessary to check them out. A second reason is that I still haven't succeeded in getting good results with the ICP-algorithm for point cloud alignment (registration). I hope that, when using ICP on two sets of keypoints, the algorithm will be faster and less prone to accumulative errors.

To implement the NARF-detector I took a quick look at the tutorial on the PCL-website. I used the code as a starting point to make my own cleaner version of it. It is given in the code block underneath. Note that this is part of a class called "Model3D". The code basically creates a range image, and then simply detects the keypoints on that image. Afterwards the found points are transformed back to 3D, and added to the original cloud in green (for visualization purposes!).

void Model3D::CreateRangeImage()
{
   pcl::PointCloud<PointType>& pointCloud = *this->cloud;
 
   Eigen::Affine3f sceneSensorPose = Eigen::Affine3f(Eigen::Translation3f(pointCloud.sensor_origin_[0], pointCloud.sensor_origin_[1], pointCloud.sensor_origin_[2]))*Eigen::Affine3f (pointCloud.sensor_orientation_);
 
   this->rangeImage->createFromPointCloud (pointCloud, pcl::deg2rad (0.5f), pcl::deg2rad (360.0f), pcl::deg2rad (180.0f), sceneSensorPose, pcl::RangeImage::CAMERA_FRAME, 0.0, 0.0f, 1);
 
   this->rangeImage->setUnseenToMaxRange();
}
 
void Model3D::DetectNarfKeypoints()
{
   this->CreateRangeImage();
 
       /* Extract NARF keypoints */
   pcl::RangeImageBorderExtractor rangeImageBorderExtractor;
   pcl::NarfKeypoint narfKeypointDetector;
   narfKeypointDetector.setRangeImageBorderExtractor (&rangeImageBorderExtractor);
   narfKeypointDetector.setRangeImage (this->rangeImage.get());
   narfKeypointDetector.getParameters().support_size = 0.2f;
   narfKeypointDetector.setRadiusSearch(0.01);
   //narfKeypointDetector.setSearchMethod(tree);
 
   pcl::PointCloud<int> keypointIndices;
   narfKeypointDetector.compute (keypointIndices);
 
   cout << "Found "<<keypointIndices.points.size ()<<" key points.\n";
 
   /* Put the points in a cloud */
   this->keyPoints->points.resize(keypointIndices.points.size());
   for (size_t i=0; i<keypointIndices.points.size(); ++i)
   {
       this->keyPoints->points[i].getVector3fMap () = this->rangeImage->points[keypointIndices.points[i]].getVector3fMap();
       this->keyPoints->points[i].r = 0;
       this->keyPoints->points[i].g = 255;
       this->keyPoints->points[i].b = 0;
       //this->keyPoints->points[i].size
   }
 
   *this->cloud += *this->keyPoints;
 
   /* Extract NARF descriptors for interest points */
   std::vector<int> keypointIndices2;
   keypointIndices2.resize (keypointIndices.points.size ());
   for (unsigned int i=0; i<keypointIndices.size (); ++i) // This step is necessary to get the right vector type
       keypointIndices2[i]=keypointIndices.points[i];
   pcl::NarfDescriptor narfDescriptor (this->rangeImage.get(), &keypointIndices2);
   narfDescriptor.getParameters().support_size = 0.2f;
   narfDescriptor.getParameters().rotation_invariant = true;
   pcl::PointCloud<pcl::Narf36> narfDescriptors;
   narfDescriptor.compute (narfDescriptors);
   cout << "Extracted "<<narfDescriptors.size ()<<" descriptors for "
                         <<keypointIndices.points.size ()<< " keypoints.\n";
}

The following video demonstrates the software I have created for my master thesis. In the end there is a quick demo of the NARF-feature using the above code. Because the points where not very visible I added an image underneath, which shows them better because I set the point-size of the visualizer to a bigger value.