$search
00001 /* 00002 * normals_vfh_db_estimator_service.cpp 00003 * 00004 * Created on: Jan 25, 2011 00005 * Author: aaldoma 00006 */ 00007 00008 #include "ros/ros.h" 00009 #include <ros/message_traits.h> 00010 #include <ros/serialization.h> 00011 #include "sensor_msgs/PointCloud2.h" 00012 #include "geometry_msgs/Pose.h" 00013 #include "vfh_recognizer_db/remove_duplicate_views.h" 00014 #include <pcl/common/common.h> 00015 #include "household_objects_database/database_view.h" 00016 #include "household_objects_database/database_vfh.h" 00017 #include "household_objects_database/database_vfh_orientation.h" 00018 #include "household_objects_database/objects_database.h" 00019 #include "household_objects_database/database_helper_classes.h" 00020 #include <fstream> 00021 #include <iostream> 00022 #include <pcl_ros/point_cloud.h> 00023 #include <vfh_recognizer_db/vfh_recognition.h> 00024 #include <pcl/registration/registration.h> 00025 #include <pcl/registration/icp.h> 00026 #include <pcl/segmentation/segment_differences.h> 00027 00028 using namespace std; 00029 namespace ser = ros::serialization; 00030 00031 00032 void 00033 getVFHFromView (boost::shared_ptr<household_objects_database::DatabaseView> & view, pcl::PointCloud< 00034 pcl::VFHSignature308> & vfh_signature, household_objects_database::ObjectsDatabase & database) 00035 { 00036 //database->getViewFromVFHId (vfh_id, view); 00037 boost::shared_ptr < household_objects_database::DatabaseVFH > vfh; 00038 database.getVFHFromView (vfh, view); 00039 00040 //deserealize into vfh_signature 00041 boost::shared_array < uint8_t > bufferRead (new uint8_t[vfh->vfh_descriptor_.data ().size ()]); 00042 memcpy (&bufferRead[0], &(vfh->vfh_descriptor_.data ()[0]), vfh->vfh_descriptor_.data ().size ()); 00043 ser::IStream streamIn (bufferRead.get (), vfh->vfh_descriptor_.data ().size ()); 00044 ser::deserialize (streamIn, vfh_signature); 00045 } 00046 00047 void 00048 getPointCloudFromView (pcl::PointCloud<pcl::PointNormal> & cloud, boost::shared_ptr< 00049 household_objects_database::DatabaseView> & view, household_objects_database::ObjectsDatabase & database) 00050 { 00051 //database->getViewFromVFHId (vfh_id, view); 00052 database.loadFromDatabase (&view->view_point_cloud_data_); 00053 boost::shared_array < uint8_t > bufferRead (new uint8_t[view->view_point_cloud_data_.data ().size ()]); 00054 memcpy (&bufferRead[0], &(view->view_point_cloud_data_.data ()[0]), view->view_point_cloud_data_.data ().size ()); 00055 ser::IStream streamIn (bufferRead.get (), view->view_point_cloud_data_.data ().size ()); 00056 ser::deserialize (streamIn, cloud); 00057 } 00058 00059 bool 00060 getUniqueViews (vfh_recognizer_db::remove_duplicate_views::Request &req, 00061 vfh_recognizer_db::remove_duplicate_views::Response &res) 00062 { 00063 00064 vfh_recognizer_db::VFHRecognizerDB < flann::ChiSquareDistance > vfh_recognizer; 00065 //vfh_recognition::VFHRecognizer<flann::HistIntersectionDistance > vfh_recognizer; 00066 00067 //store in the database 00068 household_objects_database::ObjectsDatabase database ("wgs36.willowgarage.com", "5432", "willow", "willow", 00069 "household_objects"); 00070 if (!database.isConnected ()) 00071 { 00072 std::cerr << "Database failed to connect \n"; 00073 return -1; 00074 } 00075 std::cerr << "Database connected successfully \n"; 00076 00077 //get views from the database with req.scaled_model_id 00078 00079 std::vector < boost::shared_ptr<household_objects_database::DatabaseView> > views; 00080 database.getViewsFromScaledModelId (req.scaled_model_id.data, req.iteration.data, views); 00081 00082 if (views.size() == 0) { 00083 ROS_WARN("Not removing duplicate views, model has no views"); 00084 return false; 00085 } 00086 00087 //build roll histograms 00088 std::vector<pcl::PointCloud<pcl::VFHSignature308>::Ptr> roll_histograms; 00089 roll_histograms.resize (views.size ()); 00090 std::vector<Eigen::Vector4f> centroids; 00091 centroids.resize (views.size ()); 00092 00093 for (size_t i = 0; i < views.size (); i++) 00094 { 00095 boost::shared_ptr < household_objects_database::DatabaseView > view; 00096 view = views.at (i); 00097 00098 //get point cloud from view 00099 pcl::PointCloud < pcl::PointNormal >::Ptr cloud_normals(new pcl::PointCloud<pcl::PointNormal> ()); 00100 getPointCloudFromView (*cloud_normals, view, database); 00101 00102 //compute centroid 00103 Eigen::Vector4f centroid; 00104 pcl::compute3DCentroid (*cloud_normals, centroid); 00105 Eigen::Vector3f ci3f (centroid[0], centroid[1],centroid[2]); 00106 00107 //compute roll angle orientation 00108 pcl::PointCloud<pcl::VFHSignature308>::Ptr vfh_o_signature (new pcl::PointCloud<pcl::VFHSignature308> ()); 00109 cv::Mat frequency_domain; 00110 vfh_recognizer.computeVFHRollOrientation (cloud_normals, vfh_o_signature, ci3f,frequency_domain); 00111 00112 roll_histograms[i] = vfh_o_signature; 00113 centroids[i] = centroid; 00114 } 00115 00116 //check for duplicates 00117 std::vector<bool> unique (views.size (), true); 00118 //PCLVisualizer vis ("VFH Cluster Classifier"); 00119 //PCLVisualizer vis_diff ("Difference"); 00120 00121 for (size_t i = 0; i < views.size (); i++) 00122 { 00123 00124 boost::shared_ptr < household_objects_database::DatabaseView > view_i; 00125 view_i = views.at (i); 00126 00127 Eigen::Vector3f plane_normal; 00128 plane_normal[0] = -centroids.at(i)[0]; 00129 plane_normal[1] = -centroids.at(i)[1]; 00130 plane_normal[2] = -centroids.at(i)[2]; 00131 Eigen::Vector3f z_vector = Eigen::Vector3f::UnitZ (); 00132 plane_normal.normalize (); 00133 Eigen::Vector3f axis = plane_normal.cross (z_vector); 00134 double rotation = -asin (axis.norm ()); 00135 axis.normalize (); 00136 Eigen::Affine3f transformRM (Eigen::AngleAxisf (rotation, axis)); 00137 00138 pcl::PointCloud<pcl::VFHSignature308>::Ptr roll_i_ptr; 00139 roll_i_ptr = roll_histograms[i]; //access the correct roll histogram 00140 00141 pcl::PointCloud < pcl::PointNormal >::Ptr cloud_normals_i(new pcl::PointCloud<pcl::PointNormal> ()); 00142 getPointCloudFromView (*cloud_normals_i, view_i, database); 00143 00144 Eigen::Vector4f centroid_input (centroids.at(i)[0], centroids.at(i)[1], centroids.at(i)[2], 0); 00145 00146 pcl::PointCloud<pcl::VFHSignature308>::Ptr vfh_o_signature_trash (new pcl::PointCloud<pcl::VFHSignature308> ()); 00147 Eigen::Vector3f ci3f (centroids.at(i)[0], centroids.at(i)[1], centroids.at(i)[2]); 00148 cv::Mat frequency_domain_input; 00149 vfh_recognizer.computeVFHRollOrientation (cloud_normals_i, vfh_o_signature_trash, ci3f, frequency_domain_input); 00150 00151 for (size_t j = (i+1); j < views.size (); j++) { 00152 //compare view i with the rest of the views and mark it as unique or not unique 00153 /*vis.removePointCloud ("cloud_i"); 00154 vis.removePointCloud ("cloud_j"); 00155 vis_diff.removePointCloud ("difference");*/ 00156 00157 boost::shared_ptr < household_objects_database::DatabaseView > view_j; 00158 view_j = views.at (j); 00159 00160 pcl::PointCloud<pcl::VFHSignature308>::Ptr roll_j_ptr; 00161 roll_j_ptr = roll_histograms[j]; //access the correct roll histogram 00162 00163 Eigen::Vector4f centroid_view (centroids.at(j)[0], centroids.at(j)[1], centroids.at(j)[2], 0); 00164 00165 pcl::PointCloud < pcl::PointNormal >::Ptr cloud_normals_j(new pcl::PointCloud<pcl::PointNormal> ()); 00166 getPointCloudFromView (*cloud_normals_j, view_j, database); 00167 00168 pcl::PointCloud<pcl::VFHSignature308>::Ptr vfh_o_signature_trash (new pcl::PointCloud<pcl::VFHSignature308> ()); 00169 Eigen::Vector3f ci3f (centroids.at(j)[0], centroids.at(j)[1], centroids.at(j)[2]); 00170 cv::Mat frequency_domain_view; 00171 vfh_recognizer.computeVFHRollOrientation (cloud_normals_j, vfh_o_signature_trash, ci3f, frequency_domain_view); 00172 00173 //compute roll angle! 00174 int angle = 0; 00175 angle = vfh_recognizer.computeAngleRollOrientationFrequency (frequency_domain_input, frequency_domain_view, 90, centroid_view, centroid_input , *cloud_normals_j, *cloud_normals_i, 0, *vfh_o_signature_trash, *vfh_o_signature_trash); 00176 //TODO: Fix this!! computeAngleRollOrientationFrequency 00177 00178 //std::cout << "Computed angle:" << angle << std::endl; 00179 plane_normal[0] = -centroids.at(j)[0]; 00180 plane_normal[1] = -centroids.at(j)[1]; 00181 plane_normal[2] = -centroids.at(j)[2]; 00182 plane_normal.normalize (); 00183 axis = plane_normal.cross (z_vector); 00184 rotation = -asin (axis.norm ()); 00185 axis.normalize (); 00186 Eigen::Affine3f transformRS (Eigen::AngleAxisf (rotation, axis)); 00187 transformRS = transformRS.inverse(); //invert transformation 00188 //roll transformation 00189 00190 Eigen::Affine3f transformRoll(Eigen::AngleAxisf((angle*M_PI/180), Eigen::Vector3f::UnitZ())); 00191 Eigen::Affine3f final_trans = transformRS * transformRoll * transformRM; 00192 00193 pcl::PointCloud < pcl::PointNormal > cloud_xyz; 00194 pcl::PointCloud < pcl::PointNormal >::Ptr gridTransformed (new pcl::PointCloud < pcl::PointNormal > ()); 00195 pcl::transformPointCloudWithNormals(*cloud_normals_j,*gridTransformed,final_trans); 00196 cloud_xyz = *gridTransformed; 00197 00198 // Demean the cloud 00199 pcl::PointCloud < pcl::PointNormal >::Ptr cloud_xyz_demean(new pcl::PointCloud<pcl::PointNormal> ()); 00200 Eigen::Vector4f diff = Eigen::Vector4f::Zero(); 00201 00202 Eigen::Vector3f centr(centroids.at(j)[0],centroids.at(j)[1],centroids.at(j)[2]); 00203 centr = final_trans * centr; 00204 00205 diff[0] = -centroids.at(i)[0] + centr[0]; 00206 diff[1] = -centroids.at(i)[1] + centr[1]; 00207 diff[2] = -centroids.at(i)[2] + centr[2]; 00208 00209 pcl::demeanPointCloud (cloud_xyz, diff, *cloud_xyz_demean); 00210 00211 //we can compare cloud_xyz_demean with cloud_normals_i 00212 pcl::IterativeClosestPoint < pcl::PointNormal, pcl::PointNormal > reg; 00213 reg.setInputCloud (cloud_xyz_demean); 00214 reg.setInputTarget (cloud_normals_i); 00215 double fscore = reg.getFitnessScore (0.005); 00216 00217 //segment difference 00218 pcl::SegmentDifferences<pcl::PointNormal> seg; 00219 typedef pcl::KdTree<pcl::PointNormal>::Ptr KdTreePtr; 00220 KdTreePtr normals_tree = boost::make_shared<pcl::KdTreeFLANN<pcl::PointNormal> > (true); 00221 //normals_tree->setInputCloud (cloud_xyz_demean); 00222 seg.setDistanceThreshold (0.01*0.01); //1cm 00223 seg.setSearchMethod(normals_tree); 00224 seg.setInputCloud(cloud_normals_i); 00225 seg.setTargetCloud(cloud_xyz_demean); 00226 00227 pcl::PointCloud < pcl::PointNormal > difference; 00228 seg.segment(difference); 00229 00230 //std::cout << "Fitness score:" << fscore << std::endl; 00231 fscore = (double)(difference.points.size()) / (double)(cloud_normals_i->points.size()); 00232 std::cout << "% of remaining points:" << fscore << " i:" << i << " j:" << j << " size diff:" << difference.points.size() << std::endl; 00233 if (fscore < 0.025) { //if less than 2.5% of the points have their nearest neighbor outside threshold, then view is not unique 00234 //std::cout << "View is not unique" << std::endl; 00235 unique[i] = false; 00236 break; //we have found at least one view after i that is the same 00237 } 00238 } 00239 } 00240 00241 //remove duplicate views and descriptors from the database 00242 00243 int unique_views = 0; 00244 for (size_t i = 0; i < unique.size (); i++) 00245 { 00246 if (!unique.at (i)) //if its not unique, delete it from database 00247 { 00248 00249 std::cout << "View "<< i << " not unique" << std::endl; 00250 //get the view from the vfh_id 00251 boost::shared_ptr < household_objects_database::DatabaseView > view; 00252 view = views.at(i); 00253 00254 //get roll histograms and delete them 00255 std::vector < boost::shared_ptr<household_objects_database::DatabaseVFHOrientation> > vfhOrientations; 00256 std::stringstream where; 00257 where << "view_id =" << view->view_id_.data (); 00258 std::string where_clause (where.str ()); 00259 if (!database.getList (vfhOrientations, where_clause)) { 00260 ROS_WARN("NO VFH orientation found\n"); 00261 } else { 00262 for (size_t j=0; j < vfhOrientations.size(); j++) { 00263 database.deleteFromDatabase(vfhOrientations[j].get()); 00264 } 00265 } 00266 00267 //get VFH histogram and delete them 00268 std::vector < boost::shared_ptr<household_objects_database::DatabaseVFH> > vfhs; 00269 if (!database.getList (vfhs, where_clause)) { 00270 ROS_WARN("NO VFH found\n"); 00271 } else { 00272 for (size_t j=0; j < vfhOrientations.size(); j++) { 00273 database.deleteFromDatabase(vfhs[j].get()); 00274 } 00275 } 00276 00277 //delete view 00278 database.deleteFromDatabase(view.get()); 00279 } else { 00280 unique_views++; 00281 } 00282 } 00283 00284 std::cout << "Number of unique views:" << unique_views << std::endl; 00285 00286 return true; 00287 } 00288 00289 int 00290 main (int argc, char **argv) 00291 { 00292 ros::init (argc, argv, "remove_duplicate_views_server"); 00293 ros::NodeHandle n; 00294 00295 ros::ServiceServer service = n.advertiseService ("remove_duplicate_views", getUniqueViews); 00296 ros::spin (); 00297 00298 return 0; 00299 }