target_object_detector.cpp
Go to the documentation of this file.
00001 #include <target_object_detector.hpp>
00002 #include <Eigen/Core>
00003 #include <Eigen/Eigen>
00004 #include <Eigen/Dense>
00005 #include <algorithm>
00006 #include "libsvm/svm.h"
00007 #include <ros/package.h>
00008 using namespace pcl;
00009 
00010 EuclideanCluster::EuclideanCluster(ros::NodeHandle nh, ros::NodeHandle n)
00011   : nh_(nh),
00012     rate_(n.param("loop_rate", 10)),
00013     frame_id_(n.param<std::string>("clustering_frame_id", "base_link"))
00014 {
00015   source_pc_sub_ = nh_.subscribe(n.param<std::string>("source_pc_topic_name", "/hokuyo3d/hokuyo_cloud2"), 1, &EuclideanCluster::EuclideanCallback, this);
00016   fileterd_cloud_pub_ = nh_.advertise<sensor_msgs::PointCloud2>(n.param<std::string>("filtered_pc_topic_name", "/filtered_pointcloud"), 1);
00017   euclidean_cluster_pub_ = nh_.advertise<jsk_recognition_msgs::BoundingBoxArray>(n.param<std::string>("box_name", "/clustering_result"), 1);
00018 
00019   // クラスタリングのパラメータを初期化
00020   n.param<double>("clusterTolerance", clusterTolerance_, 0.02);
00021   n.param<int>("minSize", minSize_, 100);
00022   n.param<int>("maxSize", maxSize_, 25000);
00023   // clopboxを当てはめるエリアを定義
00024   n.param<float>("crop_x_min", crop_min_.x, 5.5);
00025   n.param<float>("crop_x_max", crop_max_.x, -5.5);
00026   n.param<float>("crop_y_min", crop_min_.y, -5.5);
00027   n.param<float>("crop_y_max", crop_max_.y, 5.5);
00028   n.param<float>("crop_z_min", crop_min_.z, -0.1);
00029   n.param<float>("crop_z_max", crop_max_.z, 0.5);
00030   n.param<std::string>("svm_model_path", svm_model_path_,
00031                        ros::package::getPath("target_object_detector")
00032                        + "/model/train.csv.model");
00033   if((model_=svm_load_model(svm_model_path_.c_str()))==0)
00034   {
00035     fprintf(stderr,"can't open model file %s\n",svm_model_path_.c_str());
00036     exit(1);
00037   }
00038   n.param<std::string>("svm_range_path", svm_range_path_,
00039                        ros::package::getPath("target_object_detector")
00040                        + "/model/train.csv.range");
00041   read_scaling_parameters(svm_range_path_);
00042 }
00043 
00044 void EuclideanCluster::EuclideanCallback(
00045     const sensor_msgs::PointCloud2::ConstPtr &source_pc) {
00046 
00047   //点群をKinect座標系からWorld座標系に変換
00048   //変換されたデータはtrans_pcに格納される.
00049   sensor_msgs::PointCloud2 trans_pc;
00050   try {
00051     pcl_ros::transformPointCloud(frame_id_, *source_pc, trans_pc, tf_);
00052   } catch (tf::ExtrapolationException e) {
00053     ROS_ERROR("pcl_ros::transformPointCloud %s", e.what());
00054   }
00055 
00056   // sensor_msgs::PointCloud2 → pcl::PointCloud
00057   pcl::PointCloud<PointXYZI> pcl_source;
00058   pcl::fromROSMsg(trans_pc, pcl_source);
00059   pcl::PointCloud<PointXYZI>::Ptr pcl_source_ptr(new pcl::PointCloud<PointXYZI>(pcl_source));
00060 
00061   // 点群の中からnanを消す
00062   // std::vector<int> dummy;
00063   // pcl::removeNaNFromPointCloud(*pcl_source_ptr, *pcl_source_ptr, dummy);
00064 
00065   // Create the filtering object
00066   // pcl::StatisticalOutlierRemoval<pcl::PointXYZI> sor;
00067   // sor.setInputCloud (pcl_source_ptr);
00068   // sor.setMeanK (100);
00069   // sor.setStddevMulThresh (0.1);
00070   // sor.filter (*pcl_source_ptr);
00071 
00072   // 平面をしきい値で除去する→Cropboxで
00073   CropBox(pcl_source_ptr, crop_min_, crop_max_);
00074 
00075   // 処理後の点群をpublish
00076   // sensor_msgs::PointCloud2 filtered_pc2;
00077   // pcl::toROSMsg(*pcl_source_ptr, filtered_pc2);
00078   // filtered_pc2.header.stamp = ros::Time::now();
00079   // filtered_pc2.header.frame_id = "base_link";
00080   // fileterd_cloud_pub_.publish(filtered_pc2);
00081 
00082   // Creating the KdTree object for the search method of the extraction
00083   Clustering(pcl_source_ptr);
00084 }
00085 
00086 void EuclideanCluster::CropBox(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud,
00087                                pcl::PointXYZ min, pcl::PointXYZ max) {
00088   Eigen::Vector4f minPoint;
00089 
00090   minPoint[0] = min.x; // define minimum point x
00091   minPoint[1] = min.y; // define minimum point y
00092   minPoint[2] = min.z; // define minimum point z
00093 
00094   Eigen::Vector4f maxPoint;
00095   maxPoint[0] = max.x; // define max point x
00096   maxPoint[1] = max.y; // define max point y
00097   maxPoint[2] = max.z; // define max point z
00098 
00099   Eigen::Vector3f boxTranslatation;
00100   boxTranslatation[0] = 0;
00101   boxTranslatation[1] = 0;
00102   boxTranslatation[2] = 0;
00103 
00104   Eigen::Vector3f boxRotation;
00105   boxRotation[0] = 0; // rotation around x-axis
00106   boxRotation[1] = 0; // rotation around y-axis
00107   boxRotation[2] = 0; // in radians rotation around z-axis. this rotates your
00108 
00109   Eigen::Affine3f boxTransform;
00110 
00111   pcl::CropBox<pcl::PointXYZI> cropFilter;
00112   cropFilter.setInputCloud(cloud);
00113   cropFilter.setMin(minPoint);
00114   cropFilter.setMax(maxPoint);
00115   cropFilter.setTranslation(boxTranslatation);
00116   cropFilter.setRotation(boxRotation);
00117 
00118   pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZI>());
00119   cropFilter.filter(*cloud_filtered);
00120   pcl::copyPointCloud<pcl::PointXYZI, pcl::PointXYZI>(*cloud_filtered, *cloud);
00121 }
00122 
00123 void EuclideanCluster::Clustering(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud) {
00124   pcl::search::KdTree<pcl::PointXYZI>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZI>);
00125   tree->setInputCloud(cloud);
00126 
00127   std::vector<pcl::PointIndices> cluster_indices;
00128   pcl::EuclideanClusterExtraction<pcl::PointXYZI> ec;
00129   ec.setClusterTolerance(clusterTolerance_);
00130   ec.setMinClusterSize(minSize_);
00131   ec.setMaxClusterSize(maxSize_);
00132   ec.setSearchMethod(tree);
00133   ec.setInputCloud(cloud);
00134   ec.extract(cluster_indices);
00135 
00136   int j = 0;
00137   jsk_recognition_msgs::BoundingBoxArray box_array; // clustering結果をぶち込む配列
00138 
00139   for (std::vector<pcl::PointIndices>::const_iterator it = cluster_indices.begin(); it != cluster_indices.end(); ++it) {
00140     pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_cluster(new pcl::PointCloud<pcl::PointXYZI>);
00141     for (std::vector<int>::const_iterator pit = it->indices.begin(); pit != it->indices.end(); ++pit){
00142       cloud_cluster->points.push_back(cloud->points[*pit]);
00143     }
00144     cloud_cluster->width = cloud_cluster->points.size();
00145     cloud_cluster->height = 1;
00146     cloud_cluster->is_dense = true;
00147 
00148     //特徴量の計算
00149     svm_node features[14];
00150     feature_calculation(cloud_cluster, features);
00151     ROS_INFO_STREAM("features are extracted");
00152     int is_target_object = static_cast<int>( svm_predict( model_, features ) );
00153     ROS_INFO_STREAM("is_target_object : " << is_target_object);
00154     if (is_target_object == 1) {
00155       // 一つのclusterをpushback
00156       jsk_recognition_msgs::BoundingBox box;
00157       box = MinAreaRect(cloud_cluster, j);
00158       box_array.boxes.push_back(box);
00159       j++;
00160     }
00161   }
00162 
00163   // int clusterLength = clusterIndices.size();
00164   ROS_INFO("Found %lu clusters:", cluster_indices.size());
00165 
00166   // publish
00167   box_array.header.stamp = ros::Time::now();
00168   box_array.header.frame_id = frame_id_;
00169   euclidean_cluster_pub_.publish(box_array);
00170 
00171   // Empty Buffer
00172   cluster_indices.clear();
00173 }
00174 
00175 jsk_recognition_msgs::BoundingBox EuclideanCluster::MinAreaRect(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud, int cluster_cnt){
00176   // PCLによる点群の最大最小エリア取得
00177   pcl::MomentOfInertiaEstimation<pcl::PointXYZI> feature_extractor;
00178   feature_extractor.setInputCloud(cloud);
00179   feature_extractor.compute();
00180 
00181   std::vector<float> moment_of_inertia;
00182   std::vector<float> eccentricity;
00183   pcl::PointXYZI min_point_AABB;
00184   pcl::PointXYZI max_point_AABB;
00185 
00186   geometry_msgs::Pose pose;
00187   geometry_msgs::Vector3 size;
00188 
00189   feature_extractor.getMomentOfInertia(moment_of_inertia);
00190   feature_extractor.getEccentricity(eccentricity);
00191   feature_extractor.getAABB(min_point_AABB, max_point_AABB);
00192 
00193   // OpenCVで最小矩形を当てはめる
00194   std::vector<cv::Point2f> points;
00195   for(unsigned int i = 0; i < cloud->points.size(); i++){
00196     cv::Point2f p2d;
00197     p2d.x = cloud->points[i].x;
00198     p2d.y = cloud->points[i].y;
00199     points.push_back(p2d);
00200   }
00201   cv::Mat points_mat(points);
00202   cv::RotatedRect rrect = cv::minAreaRect(points_mat);
00203 
00204   // ROS_INFO("Center of mass (x, y) = (%f, %f)", rrect.center.x, rrect.center.y);
00205   // ROS_INFO("Height = %f Width =  %f", rrect.size.height, rrect.size.width);
00206   // ROS_INFO("Angle = %f [deg]", rrect.angle);
00207 
00208   // jsk_recognition_msgs::BoundingBoxの型に合わせて代入していく
00209   pose.position.x = rrect.center.x;
00210   pose.position.y = rrect.center.y;
00211   pose.position.z = (min_point_AABB.z + max_point_AABB.z) / 2.0;
00212 
00213   Eigen::Matrix3f AxisAngle;
00214   Eigen::Vector3f axis(0,0,1); //z 軸を指定
00215   AxisAngle = Eigen::AngleAxisf(rrect.angle*M_PI/180.0, axis); // z軸周りに90度反時計回りに回転
00216   Eigen::Quaternionf quat(AxisAngle); // クォータニオンに変換
00217   pose.orientation.x = quat.x();
00218   pose.orientation.y = quat.y();
00219   pose.orientation.z = quat.z();
00220   pose.orientation.w = quat.w();
00221 
00222   size.x = rrect.size.width;
00223   size.y = rrect.size.height;
00224   size.z = max_point_AABB.z - min_point_AABB.z;
00225 
00226   // TFの名前付け
00227   std::stringstream ss;
00228   std::string object_name;
00229   ss << cluster_cnt;
00230   object_name = "object_" + ss.str();
00231 
00232   br_.sendTransform(tf::StampedTransform(
00233       tf::Transform(
00234           tf::Quaternion(pose.orientation.x, pose.orientation.y, pose.orientation.z, pose.orientation.w),
00235           tf::Vector3(pose.position.x, pose.position.y, max_point_AABB.z)),
00236           ros::Time::now(), "world", object_name));
00237 
00238   jsk_recognition_msgs::BoundingBox box;
00239   box.header.frame_id = frame_id_;
00240   box.pose = pose;
00241   box.dimensions = size;
00242   box.label = cluster_cnt;
00243 
00244   return box;
00245 }
00246 
00247 
00248 
00249 void EuclideanCluster::run()
00250 {
00251   while(nh_.ok()){
00252     ros::spinOnce();
00253     rate_.sleep();
00254   }
00255 }
00256 
00257 
00258 void EuclideanCluster::feature_calculation(pcl::PointCloud<pcl::PointXYZI>::Ptr cloud,
00259                          svm_node *features)
00260   {
00261     int n;
00262     float f21,f22,f23,f24,f25,f26;
00263     float v1, v2, v3;
00264     double v11, v22, v33;
00265     float f31,f32,f33,f34,f35,f36,f37;
00266     pcl::PointXYZI min_point;
00267     pcl::PointXYZI max_point;
00268     std::vector<float> moment_of_inertia;
00269     std::vector<float> eccentricity;
00270     Eigen::Matrix3f cmat;
00271     Eigen::Vector4f xyz_centroid;
00272     EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
00273     pcl::MomentOfInertiaEstimation <pcl::PointXYZI> feature_extractor;
00274     feature_extractor.setInputCloud (cloud);
00275     feature_extractor.compute ();
00276     feature_extractor.getMomentOfInertia (moment_of_inertia);
00277     feature_extractor.getEccentricity (eccentricity);
00278     feature_extractor.getAABB (min_point, max_point);
00279     pcl::compute3DCentroid (*cloud, xyz_centroid);
00280     pcl::computeCovarianceMatrix (*cloud, xyz_centroid, covariance_matrix);
00281     n = cloud->points.size();
00282     f21 = covariance_matrix (0,0) / (n - 1);
00283     f22 = covariance_matrix (0,1) / (n - 1);
00284     f23 = covariance_matrix (0,2) / (n - 1);
00285     f24 = covariance_matrix (1,1) / (n - 1);
00286     f25 = covariance_matrix (1,2) / (n - 1);
00287     f26 = covariance_matrix (2,2) / (n - 1);
00288     cmat (0,0) = f21;
00289     cmat (0,1) = f22;
00290     cmat (0,2) = f23;
00291     cmat (1,0) = f22;
00292     cmat (1,1) = f24;
00293     cmat (1,2) = f25;
00294     cmat (2,0) = f23;
00295     cmat (2,1) = f25;
00296     cmat (2,2) = f26;
00297     Eigen::EigenSolver<Eigen::MatrixXf> es(cmat, false);
00298     std::complex<double> lambda1 = es.eigenvalues()[0];
00299     std::complex<double> lambda2 = es.eigenvalues()[1];
00300     std::complex<double> lambda3 = es.eigenvalues()[2];
00301     v11 = lambda1.real();
00302     v22 = lambda2.real();
00303     v33 = lambda3.real();
00304     std::vector<double> v;
00305     v.push_back (v11);
00306     v.push_back (v22);
00307     v.push_back (v33);
00308     std::sort(v.begin(), v.end() );
00309     v3 = v[0];
00310     v2 = v[1];
00311     v1 = v[2];
00312     v.clear();
00313 
00314     double nnn = v1 * v2 * v3;
00315     f31 = (v1 - v2) / v1;
00316     f32 = (v2 - v3) / v1;
00317     f33 = v3 / v1;
00318     f34 = pow(nnn, 1.0 / 3.0);
00319     f35 = (v1 - v3) / v1;
00320     f36 = -(v1 * log(v1) + v2 * log(v2) + v3 * log(v3));
00321     f37 = v3 / (v1 + v2 + v3);
00322 
00323     features[0].value = f21;
00324     features[1].value = f22;
00325     features[2].value = f23;
00326     features[3].value = f24;
00327     features[4].value = f25;
00328     features[5].value = f26;
00329     features[6].value = f31;
00330     features[7].value = f32;
00331     features[8].value = f33;
00332     features[9].value = f34;
00333     features[10].value = f35;
00334     features[11].value = f36;
00335     features[12].value = f37;
00336     features[0].index = 1;
00337     features[1].index = 2;
00338     features[2].index = 3;
00339     features[3].index = 4;
00340     features[4].index = 5;
00341     features[5].index = 6;
00342     features[6].index = 7;
00343     features[7].index = 8;
00344     features[8].index = 9;
00345     features[9].index = 10;
00346     features[10].index = 11;
00347     features[11].index = 12;
00348     features[12].index = 13;
00349     features[13].index = -1;
00350     normlize_features(features);
00351     for (int i = 0; i < 13; ++i) {
00352       std::cout << features[i].value << ", ";
00353     }
00354     std::cout << "\n";
00355 
00356   }
00357 
00358 
00359 void EuclideanCluster::normlize_features(svm_node *features)
00360 {
00361   for (int i = 0; i < 13; ++i) {
00362     if (feature_max_[i] == feature_min_[i]) {
00363       continue;
00364     }
00365     if(features[i].value == feature_min_[i]){
00366       features[i].value = feature_lower_;
00367     }else if(features[i].value == feature_max_[i]){
00368       features[i].value = feature_upper_;
00369     }else{
00370       features[i].value = feature_lower_ + (feature_upper_ - feature_lower_)*
00371         (features[i].value - feature_min_[i])/
00372         (feature_max_[i] - feature_min_[i]);
00373     }
00374   }
00375 }
00376 
00377 //スケーリングバリューは今は直書きしてるけど余裕があれば読み込めるようにする
00378 void EuclideanCluster::read_scaling_parameters(std::string scaling_parameter_file)
00379 {
00380   //scaling_parameter_file = "/home/morita/Documents/dev/ros/tc2016_ws/src/TC2016_for_thirdrobot/target_obejct_detector/model/train.csv.range";
00381 
00382   std::ifstream ifs(scaling_parameter_file.c_str());
00383   std::string str;
00384   if (ifs.fail())
00385   {
00386       ROS_ERROR("failed to read scaling parameter file");
00387       return;
00388   }
00389 
00390   // first line
00391   if(!getline(ifs, str))
00392   {
00393       ROS_ERROR("failed to read first line on scaling parameter file");
00394       return;
00395   }
00396 
00397   // second line
00398   if(!getline(ifs, str))
00399   {
00400       ROS_ERROR("failed to read second line on scaling parameter file");
00401       return;
00402   }
00403 
00404   std::vector<std::string> splited = split(str, ' ');
00405 
00406   feature_lower_ = atof(splited[0].c_str());
00407   feature_upper_ = atof(splited[1].c_str());
00408 
00409   // after second line
00410   while(getline(ifs, str))
00411   {
00412     std::vector<std::string> splited = split(str, ' ');
00413 
00414     feature_min_.push_back(atof(splited[1].c_str()));
00415     feature_max_.push_back(atof(splited[2].c_str()));
00416   }
00417 }
00418 
00419 std::vector<std::string> EuclideanCluster::split(const std::string &s, char delim)
00420 {
00421     std::vector<std::string> elems;
00422     std::stringstream ss(s);
00423     std::string item;
00424     while (getline(ss, item, delim)) {
00425     if (!item.empty()) {
00426             elems.push_back(item);
00427         }
00428     }
00429     return elems;
00430 }


target_obejct_detector
Author(s): CIR-KIT
autogenerated on Thu Jun 6 2019 20:19:57