VHF (Viewpoint Feature Histogram) descriptorsを使ったvfh_recognition_node.cppでsegmentation faultのエラーを解決するために数日悩んだのでメモを残す。
次のソースコード42行目のvfh.compute (*vfhs)でexit-11、セグメンテーションフォールトでプロセスが落ちる。バックトレースするとeigen3ライブラリが怪しい。結局、いろいろ試したり、調べた結果、PCL Users mailing listの過去記事に答えがあった。pclをC++11のフラグをつけてソースからビルドし直すと解決した。
bool recognize_cb(tabletop_object_detector::TabletopObjectRecognition::Request &srv_request,
tabletop_object_detector::TabletopObjectRecognition::Response &srv_response)
{
//build kdtree index
flann::Index<flann::ChiSquareDistance<float> > index (*data, flann::LinearIndexParams ());
index.buildIndex ();
//clear any models in the response:
srv_response.models.resize(0);
// Create the VFH estimation class, and pass the input dataset+normals to it
pcl::VFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::VFHSignature308> vfh;
std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> clouds;
//Euclidean segmentation:
SegmentCloud(fromKinect, clouds);
//For storing results:
pcl::PointCloud<pcl::PointXYZ>::Ptr aligned_template (new pcl::PointCloud<pcl::PointXYZ>);
sensor_msgs::PointCloud2 recognized_msg;
Eigen::Matrix4f objectToView;
int numFound = 0;
std::cout << "Found " << clouds.size() << " clusters.\n";
//For each segment passed in:
for(unsigned int segment_it = 0; segment_it < clouds.size(); segment_it++){
vfh.setInputCloud (clouds.at(segment_it));
//Estimate normals:
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud (clouds.at(segment_it));
pcl::search::KdTree<pcl::PointXYZ>::Ptr treeNorm (new pcl::search::KdTree<pcl::PointXYZ> ());
ne.setSearchMethod (treeNorm);
pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
ne.setRadiusSearch (0.03);
ne.compute (*cloud_normals);
//VFH estimation
vfh.setInputNormals (cloud_normals);
pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
vfh.setSearchMethod (tree);
pcl::PointCloud<pcl::VFHSignature308>::Ptr vfhs (new pcl::PointCloud<pcl::VFHSignature308> ());
vfh.compute (*vfhs);
//Load histogram
vfh_model histogram;
histogram.second.resize(308);
for (size_t i = 0; i < 308; ++i)
{
histogram.second[i] = vfhs->points[0].histogram[i];
}
//Algorithm parameters
float thresh = 100; //similarity threshold
int k = 1; //number of neighbors
//KNN classification
flann::Index<flann::ChiSquareDistance<float> > index (*data, flann::LinearIndexParams ());
index.buildIndex ();
nearestKSearch (index, histogram, k, k_indices, k_distances);
//If model match is close enough, do finer pose estimation by RANSAC fitting.
if(k_distances[0][0] < thresh){
numFound++;
//Load nearest match
std::string cloud_name = models.at(k_indices[0][0]).first;
//Extract object label and view number from file name:
cloud_name.erase(cloud_name.end()-8, cloud_name.end()-4);
std::string recognitionLabel, viewNumber;
recognitionLabel.assign(cloud_name.begin()+5, cloud_name.end()-6);
viewNumber.assign(cloud_name.end()-5, cloud_name.end()-4);
//ROS_INFO the recognitionLabel and view number. This info will later be used to look the object up in a manipulation database.
ROS_INFO("%s", recognitionLabel.c_str());
ROS_INFO("%i", atoi(viewNumber.c_str()));
//Here, objectToView is the transformation of the detected object to its nearest viewpoint in the database.
//To get the object pose in the world frame: T(camera_to_world)*T(training_view_to_camera)*objectToView.
//The transformation to camera coordinates would then happen here by finding T(view_cam) in a lookup table and premultiplying
//by objectToView
alignTemplate(clouds.at(segment_it), cloud_name, aligned_template, objectToView);
//Convert rotational component of objectToView to Quaternion for messaging:
Eigen::Matrix3f rotation = objectToView.block<3,3>(0, 0);
Eigen::Quaternionf rotQ(rotation);
//Set num models in request:
srv_request.num_models = numFound;
//Build service response:
srv_response.models.resize(numFound);
srv_response.models[numFound-1].model_list.resize(1);
//model_id
srv_response.models[numFound-1].model_list[0].model_id = atoi(viewNumber.c_str()); //This ID will eventually correspond to the object label.
//PoseStamped
//Header
srv_response.models[numFound-1].model_list[0].pose.header.seq = 1; //Don't know what this is, but it's set.
srv_response.models[numFound-1].model_list[0].pose.header.stamp = fromKinect.header.stamp;
srv_response.models[numFound-1].model_list[0].pose.header.frame_id = "/camera_depth_optical_frame";
//Pose
//Position:
srv_response.models[numFound-1].model_list[0].pose.pose.position.x = objectToView(0,3);
srv_response.models[numFound-1].model_list[0].pose.pose.position.y = objectToView(1,3);
srv_response.models[numFound-1].model_list[0].pose.pose.position.z = objectToView(2,3);
//Orientation:
srv_response.models[numFound-1].model_list[0].pose.pose.orientation.x = rotQ.x();
srv_response.models[numFound-1].model_list[0].pose.pose.orientation.y = rotQ.y();
srv_response.models[numFound-1].model_list[0].pose.pose.orientation.z = rotQ.z();
srv_response.models[numFound-1].model_list[0].pose.pose.orientation.w = rotQ.w();
//confidence and cluster_model_indcices are not currently used.
}//end threshold if statement
}//end segment iterator
return(1);
}
環 境
- Ubuntu-16.04, PCL-1.8.1, gcc-5.4.0
実施した作業
- ここでは、pclのソースコードが~/src/pcl/pcl-1.8.1にあるする。
- PCLのCMakeLists.txtの一番最後に以下を追加。
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
cd ~/src/pcl/pcl-1.8.1
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j12
sudo make install
- エラーが出ていたソースコードをビルドし直す。以下は例。
cd ~/catkin_ws
catkin_make
終わり