ClusterDetector.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2009 by Ulrich Friedrich Klank <klank@in.tum.de>
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 3 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 /*
00018  * Copyright (c) 2009 Radu Bogdan Rusu <rusu -=- cs.tum.edu>
00019  *
00020  * All rights reserved.
00021  *
00022  * Redistribution and use in source and binary forms, with or without
00023  * modification, are permitted provided that the following conditions are met:
00024  *
00025  *     * Redistributions of source code must retain the above copyright
00026  *       notice, this list of conditions and the following disclaimer.
00027  *     * Redistributions in binary form must reproduce the above copyright
00028  *       notice, this list of conditions and the following disclaimer in the
00029  *       documentation and/or other materials provided with the distribution.
00030  *
00031  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00032  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00033  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00034  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00035  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00036  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00037  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00038  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00039  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00040  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00041  * POSSIBILITY OF SUCH DAMAGE.
00042  *
00043  * $Id: plane_clusters.cpp 17089 2009-06-15 18:52:12Z veedee $
00044  *
00045  */
00046 #define BOOST_THREAD
00047 
00048 #include "ClusterDetector.h"
00049 #include "SegmentPrototype.h"
00050 #include "XMLTag.h"
00051 #include "SwissRangerReading.h"
00052 #include "BoostUtils.h"
00053 
00054 
00055 // Sample Consensus
00056 #include <point_cloud_mapping/sample_consensus/sac.h>
00057 #include <point_cloud_mapping/sample_consensus/msac.h>
00058 #include <point_cloud_mapping/sample_consensus/ransac.h>
00059 #include <point_cloud_mapping/sample_consensus/sac_model_plane.h>
00060 
00061 #include <angles/angles.h>
00062 
00063 // Kd Tree
00064 #include <point_cloud_mapping/kdtree/kdtree_ann.h>
00065 
00066 // Cloud geometry
00067 #include <point_cloud_mapping/geometry/angles.h>
00068 #include <point_cloud_mapping/geometry/areas.h>
00069 #include <point_cloud_mapping/geometry/point.h>
00070 #include <point_cloud_mapping/geometry/distances.h>
00071 #include <point_cloud_mapping/geometry/nearest.h>
00072 #include <point_cloud_mapping/geometry/transforms.h>
00073 #include <point_cloud_mapping/geometry/statistics.h>
00074 
00075 #include <sys/time.h>
00076 
00077 
00078 
00079 //#include <utilities/yarp_communication.h>
00080 
00081 #define SR_COLS 176
00082 #define SR_ROWS 144
00083 #define DEBUG 1
00084 
00085 #define XML_ATTRIBUTE_SR4LO "sr_loid"
00086 #define XML_ATTRIBUTE_PTULO "ptu_loid"
00087 
00088 using namespace cop;
00089 
00090 using namespace std;
00091 using namespace ros;
00092 //using namespace std_msgs;
00093 using namespace sensor_msgs;
00094 using namespace geometry_msgs;
00095 
00096 // Comparison operator for a vector of vectors
00097 bool
00098   compareRegions (const std::vector<int> &a, const std::vector<int> &b)
00099 {
00100   return (a.size () < b.size ());
00101 }
00102 
00103   class PlaneClusterResult
00104   {
00105     public:
00106     class ObjectOnTable
00107     {
00108 
00109      public:
00110       std::vector<double> cov33;
00111       geometry_msgs::Point32 center;
00112 
00113     };
00114 
00115     public:
00116     double a;
00117     double b;
00118     double c;
00119     double d;
00120     geometry_msgs::Point32 pcenter;
00121     std::vector<ObjectOnTable> oclusters;
00122   };
00123 
00124 
00125 class PlaneClustersSR
00126 {
00127   public:
00128 
00129     // ROS messages
00130     PointCloud cloud_in_trans_;
00131 
00132     PointCloud cloud_down_;
00133     Point leaf_width_;
00134     PointCloud cloud_annotated_;
00135     Point32 axis_;
00136 
00137     // Parameters
00138     string input_cloud_topic_;
00139     int k_;
00140     double max_z_;
00141     int clusters_min_pts_;
00142 
00143     int object_cluster_min_pts_;
00144     double object_cluster_tolerance_;
00145 
00146     bool need_cloud_data_;
00147 
00148     double sac_distance_threshold_, eps_angle_;
00149 
00150     double delta_z_, object_min_dist_from_table_;
00151 
00152     double min_angle_, max_angle_;
00153 
00154 
00155     int downsample_factor_;
00156 
00157     boost::mutex m_mutexUsage;
00159     PlaneClustersSR (XMLTag* tag)
00160     {
00161       // 0.198669 0 0.980067 0 0 -1 0 0 0.980067 0 -0.198669 0 0 0 0 1
00162       axis_.x = 0; axis_.y = 0; axis_.z = 1;
00163 
00164       downsample_factor_ = 4; // Use every nth point
00165       k_ = 2;                  // 5 k-neighbors by default
00166       max_z_ = 0.03;
00167 
00168       eps_angle_ = 15.0;       // 15 degrees
00169       eps_angle_ = angles::from_degrees (eps_angle_);          // convert to radians
00170 
00171       clusters_min_pts_ = 10;  // 10 points
00172 
00173       object_cluster_tolerance_ = 0.07;   // 7cm between two objects
00174       object_cluster_min_pts_ = 30;         // 30 points per object cluster
00175 
00176       delta_z_ = 0.03;                              // consider objects starting at 3cm from the table
00177       object_min_dist_from_table_ = 0.1; // objects which have their support more 10cm from the table will not be considered
00178 
00179       min_angle_ = 10.0;
00180       max_angle_ = 170.0;
00181       // This should be set to whatever the leaf_width factor is in the downsampler
00182       sac_distance_threshold_ = 0.03;     // 3 cm
00183     }
00184 
00186    void
00187       updateParametersFromServer ()
00188     {
00189      /* nh_.getParam ("~input_cloud_topic", input_cloud_topic_);
00190       nh_.getParam ("~downsample_factor", downsample_factor_);*/
00191     }
00192 
00194 
00199     inline double
00200       getRGB (float r, float g, float b)
00201     {
00202       int res = (int(r * 255) << 16) | (int(g*255) << 8) | int(b*255);
00203       double rgb = *(float*)(&res);
00204       return (rgb);
00205     }
00206 
00207 
00208     void cloud_trans (unsigned long swissranger_jlo_id, unsigned long ptu_base_jlo_id,  Point32& viewpoint_cloud, const PointCloud& cloud_in)
00209     {
00210        RelPose* pose = RelPoseFactory::GetRelPose(swissranger_jlo_id, ptu_base_jlo_id);
00211 
00212        if(pose == NULL)
00213        {
00214           RelPose* pose1 = RelPoseFactory::GetRelPose("/sr4");
00215           RelPose* pose2 = RelPoseFactory::GetRelPose("/base_link");
00216           if(pose1 && pose2)
00217           {
00218             pose = RelPoseFactory::GetRelPose(pose1->m_uniqueID, pose2->m_uniqueID);
00219             RelPoseFactory::FreeRelPose(&pose1);
00220             RelPoseFactory::FreeRelPose(&pose2);
00221           }
00222           if(pose == NULL)
00223            throw "Cloud trans not possible: Location not clear";
00224        }
00225        Matrix m = pose->GetMatrix(0);
00226 
00227        RelPoseFactory::FreeRelPose(&pose);
00228 
00229        Matrix m_tmp = m;
00230        cloud_in_trans_.points.clear();
00231        if(cloud_in.points.size() == 0 || cloud_in.points.size() > 1000000000)
00232           throw "Error in pointcloud, failed check 0 =< num_points < 1000000000";
00233        for(size_t i = 0; i < cloud_in.points.size(); i++)
00234        {
00235          ColumnVector v(4);
00236          v <<  cloud_in.points[i].x <<  cloud_in.points[i].y <<  cloud_in.points[i].z << 1;
00237          ColumnVector a = m_tmp*v;
00238          Point32 pt;
00239          pt.x = a.element(0);
00240          pt.y = a.element(1);
00241          pt.z = a.element(2);
00242          cloud_in_trans_.points.push_back(pt);
00243        }
00244        cloud_in_trans_.channels.clear();
00245        for(size_t channels = 0 ; channels < cloud_in.channels.size(); channels++)
00246        {
00247 
00248          cloud_in_trans_.channels.push_back(ChannelFloat32());
00249          cloud_in_trans_.channels[channels].name = cloud_in.channels[channels].name;
00250          for(size_t points = 0; points < cloud_in.channels[channels].values.size(); points++)
00251          {
00252            cloud_in_trans_.channels[channels].values.push_back(
00253            cloud_in.channels[channels].values[points]);
00254          }
00255        }
00256        ColumnVector vp(4);
00257        vp <<  viewpoint_cloud.x <<  viewpoint_cloud.y << viewpoint_cloud.z << 1;
00258        ColumnVector ap = m_tmp*vp;
00259        viewpoint_cloud.x = ap.element(0);
00260        viewpoint_cloud.y = ap.element(1);
00261        viewpoint_cloud.z = ap.element(2);
00262    }
00263 
00265     bool
00266       plane_clusters_service (PlaneClusterResult &resp, int swissranger_jlo_id, int ptu_base_jlo_id, const PointCloud& cloud, bool parallel)
00267     {
00268       printf("plane_clusters_service::lock!\n");
00269       m_mutexUsage.lock();
00270       try
00271       {
00272         /*ROS_INFO ("Service request initiated.");
00273         updateParametersFromServer ();*/
00274         Point32 vp;
00275         vp.x = vp.y = vp.z = 0.0;
00276         cloud_trans(swissranger_jlo_id, ptu_base_jlo_id, vp, cloud);
00277         if(!detectTable (cloud_in_trans_, resp, vp, parallel))
00278         {
00279           printf("plane_clusters_service::unlock!\n");
00280 
00281           m_mutexUsage.unlock();
00282           return false;
00283         }
00284         ROS_INFO ("Service request terminated.");
00285         printf("plane_clusters_service::lock!\n");
00286         m_mutexUsage.unlock();
00287         return (true);
00288       }
00289       catch(const char text)
00290       {
00291        printf("plane_clusters_service::lock!\n");
00292        m_mutexUsage.unlock();
00293         throw text;
00294       }
00295     }
00296 
00297 
00299     bool
00300       detectTable (const PointCloud &cloud, PlaneClusterResult &resp,  Point32 viewpoint_cloud,bool parallel)
00301     {
00302       ros::Time ts = ros::Time::now ();
00303       bool assuming_ar4 = true;
00304       // Create a downsampled representation of the cloud
00305       cloud_down_.header = cloud.header;
00306 
00307       // Estimate point normals and copy the relevant data
00308       try
00309       {
00310 
00311        if (abs((int)cloud.points.size() - SR_COLS*SR_ROWS) < 30)
00312        {
00313          cloud_geometry::nearest::computeOrganizedPointCloudNormalsWithFiltering (cloud_down_, cloud, k_, downsample_factor_, SR_COLS, SR_ROWS, max_z_, min_angle_, max_angle_, viewpoint_cloud);
00314        }
00315        else
00316        {
00317          assuming_ar4 = false;
00318          geometry_msgs::PointStamped view;
00319          view.point.x = viewpoint_cloud.x;
00320          view.point.y = viewpoint_cloud.y;
00321          view.point.z = viewpoint_cloud.z;
00322          cloud_down_.points = cloud.points;
00323          cloud_geometry::nearest::computePointCloudNormals(cloud_down_, k_,  view);
00324        }
00325       }
00326       catch(std::out_of_range ex)
00327       {
00328         throw "Extraction failed";
00329       }
00330 
00331       // ---[ Select points whose normals are perpendicular to the Z-axis
00332       vector<int> indices_z;
00333       if(parallel)
00334       {
00335         cloud_geometry::getPointIndicesAxisParallelNormals (cloud_down_, 0, 1, 2, eps_angle_, axis_, indices_z);
00336       }
00337       else
00338       {
00339         cloud_geometry::getPointIndicesAxisPerpendicularNormals( cloud_down_, 0, 1, 2, eps_angle_, axis_, indices_z);
00340       }
00341 #ifdef DEBUG
00342       ROS_INFO ("Number of points with normals parallel to Z: %d.", (int)indices_z.size ());
00343 #endif
00344       if(indices_z.size () < 10)
00345       {
00346        if(parallel)
00347        {
00348          cloud_geometry::getPointIndicesAxisParallelNormals (cloud_down_, 0, 1, 2, eps_angle_*2, axis_, indices_z);
00349        }
00350        else
00351        {
00352          cloud_geometry::getPointIndicesAxisPerpendicularNormals( cloud_down_, 0, 1, 2, eps_angle_*2, axis_, indices_z);
00353        }
00354 #ifdef DEBUG
00355        ROS_INFO ("Number of points with normals parallel to Z in second try: %d. with axis (%f %f %f )", (int)indices_z.size (), axis_.x, axis_.y, axis_.z);
00356 #endif
00357       }
00358       if(indices_z.size () < 10)
00359          return false;
00360       // Find the best plane in this cluster (later, we can optimize and process more clusters individually)
00361       vector<int> inliers_down;
00362       vector<double> coeff;
00363       printf("fitSACPlane \n");
00364       fitSACPlane (&cloud_down_, indices_z, inliers_down, coeff, viewpoint_cloud, sac_distance_threshold_);
00365 
00366       printf("end fitSACPlane \n");
00367       // Filter the original pointcloud data with the same min/max angle for jump edges
00368       PointCloud cloud_filtered;// = cloud;
00369       if (assuming_ar4)
00370       {
00371         cloud_geometry::nearest::filterJumpEdges (cloud, cloud_filtered, 1, SR_COLS, SR_ROWS, min_angle_, max_angle_, viewpoint_cloud);
00372       }
00373       else
00374       {
00375         cloud_filtered = cloud;
00376         cloud_filtered.points = cloud.points;
00377       }
00378       // Refine plane
00379       vector<int> inliers (cloud_filtered.points.size ());
00380       int j = 0;
00381       for (unsigned int i = 0; i < cloud_filtered.points.size (); i++)
00382       {
00383         double dist_to_plane = cloud_geometry::distances::pointToPlaneDistance (cloud_filtered.points[i], coeff);
00384         if (dist_to_plane < sac_distance_threshold_)
00385           inliers[j++] = i;
00386       }
00387       inliers.resize (j);
00388 
00389       // Obtain the bounding 2D polygon of the table
00390       Polygon table;
00391       printf("convexHull2D  \n");
00392       cloud_geometry::areas::convexHull2D (cloud_down_, inliers_down, coeff, table);
00393 #ifdef DEBUG
00394       /*PolygonalMap pmap;
00395       pmap.header = cloud.header;
00396       pmap.polygons.resize (1);
00397       pmap.polygons[0] = table;
00398       pmap_pub_.publish (pmap);*/
00399 #endif
00400 
00401       // Find the object clusters supported by the table
00402       Point32 min_p, max_p;
00403       printf("getMinMax \n");
00404       cloud_geometry::statistics::getMinMax (cloud_filtered, inliers, min_p, max_p);
00405       vector<int> object_inliers;
00406       printf("findObjectClusters \n");
00407       findObjectClusters (cloud_filtered, coeff, table, axis_, min_p, max_p, object_inliers, resp);
00408 
00409 #ifdef DEBUG
00410       // Send the table
00411       //cloud_clusters_pub_.publish (cloud_annotated_);
00412       //cloud_geometry::getPointCloud (cloud_filtered, object_inliers, cloud_annotated_);
00413 
00414 
00415       // Send the clusters
00416       //cloud_geometry::getPointCloud (cloud_down_, indices_z, cloud_annotated_);   // downsampled version
00417       /*cloud_geometry::getPointCloud (cloud_down_, inliers_down, cloud_annotated_);*/   // downsampled version
00418       //cloud_geometry::getPointCloud (cloud_filtered, inliers, cloud_annotated_);              // full version
00419       /*cloud_table_pub_.publish (cloud_annotated_);*/
00420 #endif
00421       ROS_INFO ("Results estimated in %g xseconds.", (ros::Time::now () - ts).toSec ());
00422       // Copy the plane parameters back in the response
00423       resp.a = coeff[0]; resp.b = coeff[1]; resp.c = coeff[2]; resp.d = coeff[3];
00424       cloud_geometry::nearest::computeCentroid (cloud_filtered, inliers, resp.pcenter);
00425 
00426       return true;
00427     }
00428 
00430     void
00431       findObjectClusters (const PointCloud &cloud, const vector<double> &coeff, const Polygon &table,
00432                           const Point32 &axis, const Point32 &min_p, const Point32 &max_p, vector<int> &object_indices, PlaneClusterResult &resp)
00433     {
00434       int nr_p = 0;
00435       Point32 pt;
00436       object_indices.resize (cloud.points.size ());
00437 
00438       // Iterate over the entire cloud to extract the object clusters
00439       for (unsigned int i = 0; i < cloud.points.size (); i++)
00440       {
00441         // Select all the points in the given bounds - check all axes
00442         if ( axis.x == 1 && ( cloud.points.at (i).y < min_p.y || cloud.points.at (i).y > max_p.y || cloud.points.at (i).z < min_p.z || cloud.points.at (i).z > max_p.z ) )
00443           continue;
00444 
00445         else if ( axis.y == 1 && ( cloud.points.at (i).x < min_p.x || cloud.points.at (i).x > max_p.x || cloud.points.at (i).z < min_p.z || cloud.points.at (i).z > max_p.z ) )
00446           continue;
00447 
00448         else if ( axis.z == 1 && ( cloud.points.at (i).x < min_p.x || cloud.points.at (i).x > max_p.x || cloud.points.at (i).y < min_p.y || cloud.points.at (i).y > max_p.y ) )
00449           continue;
00450 
00451         // Calculate the distance from the point to the plane
00452         double dist_to_plane = coeff.at (0) * cloud.points.at (i).x +
00453                                coeff.at (1) * cloud.points.at (i).y +
00454                                coeff.at (2) * cloud.points.at (i).z +
00455                                coeff.at (3) * 1;
00456         // Calculate the projection of the point on the plane
00457         pt.x = cloud.points.at (i).x - dist_to_plane * coeff.at (0);
00458         pt.y = cloud.points.at (i).y - dist_to_plane * coeff.at (1);
00459         pt.z = cloud.points.at (i).z - dist_to_plane * coeff.at (2);
00460 
00461         if (dist_to_plane > delta_z_ && cloud_geometry::areas::isPointIn2DPolygon (pt, table))
00462         {
00463           object_indices[nr_p] = i;
00464           nr_p++;
00465         }
00466       }
00467       object_indices.resize (nr_p);
00468 
00469       // Find the clusters
00470       nr_p = 0;
00471       vector<vector<int> > object_clusters;
00472       cloud_geometry::nearest::extractEuclideanClusters (cloud, object_indices, object_cluster_tolerance_,
00473                                                          object_clusters, -1, -1, -1, -1, object_cluster_min_pts_);
00474 
00475 #ifdef DEBUG
00476         int total_nr_pts = 0;
00477         for (unsigned int i = 0; i < object_clusters.size (); i++)
00478           total_nr_pts += object_clusters[i].size ();
00479 
00480         cloud_annotated_.header = cloud.header;
00481         cloud_annotated_.points.resize (total_nr_pts);
00482         cloud_annotated_.channels.resize (1);
00483         cloud_annotated_.channels[0].name = "rgb";
00484         cloud_annotated_.channels[0].values.resize (total_nr_pts);
00485         ROS_INFO ("Number of clusters found: %d", (int)object_clusters.size ());
00486 #endif
00487 
00488       Point32 min_p_cluster, max_p_cluster;
00489 
00490       resp.oclusters.resize (object_clusters.size ());
00491       for (unsigned int i = 0; i < object_clusters.size (); i++)
00492       {
00493 #ifdef DEBUG
00494         float rgb = getRGB (rand () / (RAND_MAX + 1.0), rand () / (RAND_MAX + 1.0), rand () / (RAND_MAX + 1.0));
00495 #endif
00496         vector<int> object_idx = object_clusters.at (i);
00497 
00498         // Check whether this object cluster is supported by the table or just flying through thin air
00499         cloud_geometry::statistics::getMinMax (cloud, object_idx, min_p_cluster, max_p_cluster);
00500         // Select all the points in the given bounds - check all axes
00501         if ( axis.x == 1 && ( min_p_cluster.x > max_p.x + object_min_dist_from_table_ ) )
00502           continue;
00503         if ( axis.y == 1 && ( min_p_cluster.y > max_p.y + object_min_dist_from_table_ ) )
00504           continue;
00505         if ( axis.z == 1 && ( min_p_cluster.z > max_p.z + object_min_dist_from_table_ ) )
00506           continue;
00507 
00508         // Process this cluster and extract the centroid and the bounds
00509         for (unsigned int j = 0; j < object_idx.size (); j++)
00510         {
00511           object_indices[nr_p] = object_idx.at (j);
00512 #ifdef DEBUG
00513             cloud_annotated_.points[nr_p] = cloud.points.at (object_idx.at (j));
00514             cloud_annotated_.channels[0].values[nr_p] = rgb;
00515 #endif
00516           nr_p++;
00517         }
00518         cloud_geometry::nearest::computeCentroid (cloud, object_idx, resp.oclusters[i].center);
00519         resp.oclusters[i].cov33.clear();
00520         for(unsigned int l = 0; l < 9; l++)
00521         {
00522           resp.oclusters[i].cov33.push_back(0.0);
00523         }
00524 
00525         for(unsigned int k = 0; k < object_idx.size (); k++)
00526         {
00527             Point32 p = cloud.points.at (object_idx.at (k));
00528             p.x = p.x - resp.oclusters[i].center.x;
00529             p.y = p.y - resp.oclusters[i].center.y;
00530             p.z = p.z - resp.oclusters[i].center.z;
00531             resp.oclusters[i].cov33[0] += p.x*p.x;
00532             resp.oclusters[i].cov33[1] += p.y*p.x;
00533             resp.oclusters[i].cov33[2] += p.z*p.x;
00534             resp.oclusters[i].cov33[3] += p.x*p.y;
00535             resp.oclusters[i].cov33[4] += p.y*p.y;
00536             resp.oclusters[i].cov33[5] += p.z*p.y;
00537             resp.oclusters[i].cov33[6] += p.x*p.z;
00538             resp.oclusters[i].cov33[7] += p.y*p.z;
00539             resp.oclusters[i].cov33[8] += p.z*p.z;
00540         }
00541         for(unsigned int t = 0; t < resp.oclusters[i].cov33.size(); t++)
00542         {
00543           resp.oclusters[i].cov33[t] /= object_idx.size ();
00544           if(resp.oclusters[i].cov33[t] <= 0.0)
00545             resp.oclusters[i].cov33[t] = 0.000000001;
00546         }
00547         /*cloud_geometry::statistics::getMinMax (cloud, object_idx, resp.oclusters[i].min_bound, resp.oclusters[i].max_bound);*/
00548       }
00549       object_indices.resize (nr_p);
00550 #ifdef DEBUG
00551         cloud_annotated_.points.resize (nr_p);
00552         cloud_annotated_.channels[0].values.resize (nr_p);
00553 #endif
00554     }
00555 
00556 
00558     bool
00559       fitSACPlane (PointCloud *points, vector<int> &indices, vector<int> &inliers, vector<double> &coeff,
00560                    const Point32 &viewpoint_cloud, double dist_thresh)
00561     {
00562       if ((int)indices.size () < clusters_min_pts_)
00563       {
00564         inliers.resize (0);
00565         coeff.resize (0);
00566         return (false);
00567       }
00568 
00569       // Create and initialize the SAC model
00570       sample_consensus::SACModelPlane *model = new sample_consensus::SACModelPlane ();
00571       sample_consensus::SAC *sac             = new sample_consensus::MSAC (model, sac_distance_threshold_);
00572       sac->setMaxIterations (200);
00573       sac->setProbability (0.99);
00574       model->setDataSet (points, indices);
00575 
00576       // Search for the best plane
00577       if (sac->computeModel ())
00578       {
00579         if ((int)sac->getInliers ().size () < clusters_min_pts_)
00580         {
00581           //ROS_ERROR ("fitSACPlane: Inliers.size (%d) < sac_min_points_per_model (%d)!", sac->getInliers ().size (), sac_min_points_per_model_);
00582           inliers.resize (0);
00583           coeff.resize (0);
00584           return (false);
00585         }
00586 
00587         sac->computeCoefficients (coeff);     // Compute the model coefficients
00588         sac->refineCoefficients (coeff);      // Refine them using least-squares
00589         model->selectWithinDistance (coeff, dist_thresh, inliers);
00590 
00591         cloud_geometry::angles::flipNormalTowardsViewpoint (coeff, points->points.at (inliers[0]), viewpoint_cloud);
00592 
00593         // Project the inliers onto the model
00594         model->projectPointsInPlace (inliers, coeff);
00595       }
00596       delete model;
00597       delete sac;
00598       return (true);
00599     }
00600 };
00601 
00602 PlaneClustersSR* s_planeCluster = NULL;
00603 
00604 ClusterDetector::ClusterDetector(int srid, int ptuid) :
00605   m_swissranger_jlo_id(srid),
00606   m_ptu_jlo_id(ptuid)
00607 {
00608   if(s_planeCluster == NULL)
00609     s_planeCluster = new PlaneClustersSR(NULL);
00610 }
00611 
00612 ClusterDetector::ClusterDetector()
00613 {
00614 }
00615 
00616 void ClusterDetector::SetData(XMLTag* tag)
00617 {
00618   if(s_planeCluster == NULL)
00619     s_planeCluster = new PlaneClustersSR(tag);
00620 
00621 
00622   if(tag != NULL)
00623   {
00624       m_swissranger_jlo_id = tag->GetPropertyInt(XML_ATTRIBUTE_SR4LO, 0);
00625       if(m_swissranger_jlo_id == 0)
00626       {
00627         std::string name = tag->GetProperty(XML_ATTRIBUTE_SR4LO, "/sr4");
00628         RelPose* pose = RelPoseFactory::GetRelPose(name);
00629         if(pose == NULL)
00630           m_swissranger_jlo_id = 1;
00631         else
00632         {
00633           printf("Read Clusterdetector with %ld as camera position (%s)\n", pose->m_uniqueID, name.c_str());
00634           m_swissranger_jlo_id =pose->m_uniqueID;
00635           RelPoseFactory::FreeRelPose(&pose);
00636         }
00637       }
00638       m_ptu_jlo_id = tag->GetPropertyInt(XML_ATTRIBUTE_PTULO, 0);
00639       if(m_ptu_jlo_id == 0)
00640       {
00641         std::string name = tag->GetProperty(XML_ATTRIBUTE_PTULO, "/base_link");
00642         RelPose* pose = RelPoseFactory::GetRelPose(name);
00643         if(pose == NULL)
00644           m_ptu_jlo_id = 1;
00645         else
00646         {
00647           m_ptu_jlo_id =pose->m_uniqueID;
00648           RelPoseFactory::FreeRelPose(&pose);
00649         }
00650       }
00651   }
00652 }
00653 
00654 
00655 ClusterDetector::~ClusterDetector()
00656 {
00657   delete s_planeCluster;
00658   s_planeCluster = NULL;
00659 }
00660 
00661 std::vector<RelPose*> ClusterDetector::Perform(std::vector<Sensor*> sensors, RelPose* pose, Signature& object, int &numOfObjects, double& qualityMeasure)
00662 {
00663   std::vector<RelPose*> results;
00664     //Calibration* calib = &cam[0]->m_calibration;
00665   SegmentPrototype* proto = (SegmentPrototype*)object.GetElement(0, DESCRIPTOR_SEGMPROTO);
00666   printf("ClusterDetector::Perform: Got SegmentPrototype\n");
00667   for(std::vector<Sensor*>::const_iterator it = sensors.begin(); it != sensors.end(); it++)
00668   {
00669     if((*it)->GetName().compare(XML_NODE_SWISSRANGER) == 0)
00670     {
00671       try
00672       {
00673         results = Inner(*it, proto, numOfObjects, qualityMeasure);
00674       }
00675       catch (const char* text )
00676       {
00677          printf("Error in ClusterDetector: %s\n", text);
00678       }
00679       break;
00680     }
00681   }
00682   /*TODO plane clusters*/
00683   return results;
00684 }
00685 
00686 
00687 
00688 inline void normalize(double &a,double &b, double &c)
00689 {
00690   double norm = sqrt(a*a + b*b + c*c);
00691   a /= norm;
00692   b /= norm;
00693   c /= norm;
00694 }
00695 
00696 inline double scalarproduct(const double &a,const double &b, const double &c, const double &d, const double &e, const double &f)
00697 {
00698   return a * d + b* e + c*f;
00699 }
00700 
00701 inline void CrossProduct_l(const double b_x, const double b_y,const double b_z,const double c_x,const double c_y,const double c_z,double &a_x,double &a_y,double &a_z)
00702 {
00703     a_x = b_y*c_z - b_z*c_y;
00704     a_y = b_z*c_x - b_x*c_z;
00705     a_z = b_x*c_y - b_y*c_x;
00706 }
00707 
00708 bool ClusterDetector::CallStaticPlaneClusterExtractor(Sensor* sensor, PlaneClusterResult* response, int ptu_jlo_id, bool parallel)
00709 {
00710   if(s_planeCluster == NULL)
00711     s_planeCluster = new PlaneClustersSR(NULL);
00712   SwissRangerReading* reading = (SwissRangerReading*)sensor->GetReading(-1);
00713   try
00714   {
00715     bool b =  s_planeCluster->plane_clusters_service(*response, reading->m_relPose->m_uniqueID, ptu_jlo_id, reading->m_image, parallel);
00716     reading->Free();
00717     return b;
00718   }
00719   catch(const char* text)
00720   {
00721     printf("Error in ClusterDetector: %s\n", text);
00722   }
00723   return false;
00724 }
00725 
00726 std::vector<RelPose*> ClusterDetector::Inner(Sensor* sens, SegmentPrototype* obj_descr, int &numOfObjects, double& qualityMeasure)
00727 {
00728   std::vector<RelPose*> results;
00729   PlaneClusterResult response;
00730   qualityMeasure = 0.0;
00731   bool parallel = true;
00732   unsigned long ref_frame = m_ptu_jlo_id;
00733 
00734   if(obj_descr != NULL)
00735   {
00736     ref_frame = obj_descr->GetFrameId();
00737     parallel = obj_descr->m_parallel;
00738   }
00739 
00740   if(!CallStaticPlaneClusterExtractor(sens, &response, ref_frame, parallel))
00741   {
00742     return results;
00743   }
00744 
00745   double a = response.a;
00746   double b = response.b;
00747   double c = response.c;
00748   double s = response.d;
00749   std::vector<PlaneClusterResult::ObjectOnTable> &vec = response.oclusters;
00750   printf("Got plane equation %f x + %f y + %f z + %f = 0\n", a,b,c,s);
00751    /*Norm v1*/
00752   normalize(a,b,c);
00753 
00754   /*Init v2*/
00755   double d,e,f,g,h,i;
00756   if (a == b && a == c)
00757   {
00758      d = 1; e = 0; f = 0;
00759   }
00760   else
00761   {
00762     d = b; e = a; f = c;
00763   }
00764   /*Orthogonalize v2*/
00765   double tmp = scalarproduct(a,b,c,d,e,f);
00766   d = d - tmp * a;
00767   e = e - tmp * b;
00768   f = f - tmp * c;
00769 
00770   /*Norma v2*/
00771   normalize(d,e,f);
00772 
00773   /*Create v3*/
00774 
00775   CrossProduct_l(a,b,c,d,e,f, g,h,i);
00783   if(vec.size() == 0)
00784   {
00785    /* printf("No Clusters found, adding a meaningless cluster");
00786         PlaneClusterResult::ObjectOnTable on;
00787      on.center.x = pcenter.x;
00788      on.center.y = pcenter.y;
00789      on.center.z = pcenter.z;
00790 
00791      on.min_bound.x = pcenter.x - 0.5;
00792      on.min_bound.y = pcenter.y - 0.3;
00793      on.min_bound.z = pcenter.z - 0.2;
00794 
00795      on.max_bound.x = pcenter.x + 0.5;
00796      on.max_bound.y = pcenter.y + 0.3;
00797      on.max_bound.z = pcenter.z + 0.2;
00798      vec.push_back(on);*/
00799   }
00800   printf("Creating a pose for every cluster\n");
00801   double prob = 1.0;
00802   RelPose* ptu = RelPoseFactory::FRelPose(ref_frame);
00803 
00804   for(size_t x = 0; x < vec.size(); x++)
00805   {
00806     prob = prob * 0.9;
00807     printf("a: %f , b: %f , c: %f\n", a, b, c);
00808     const geometry_msgs::Point32 &center = vec[x].center;
00809     Matrix rotmat(4,4);
00810 
00811     rotmat << d << g << a << center.x
00812            << e << h << b << center.y
00813            << f << i << c << center.z
00814            << 0 << 0 << 0 << 1;
00815 
00816     cout <<  "Matrix from plane_clusters:" << endl << rotmat << endl;
00817     Matrix cov (6,6);
00818     if(vec[x].cov33.size() < 9)
00819     {
00820       ROS_ERROR("Error detectin Clusters: size of cov33 (%ld) smaller than expected: 9\n", vec[x].cov33.size());
00821     }
00822     else
00823     {
00824     /*double covz = max(fabs(center.z - max_bound.z), fabs(center.z - min_bound.z ));*/
00825     /*Fill covariance with the cluster size and hardcoded full rotation in normal direction */
00826      if(parallel)
00827      {
00828 /*      cout << sqrt(vec[x].cov33[0]) << sqrt(vec[x].cov33[1]) << sqrt(vec[x].cov33[2]) << 0   << 0   << 0<< endl;
00829       cout << sqrt(vec[x].cov33[3]) << sqrt(vec[x].cov33[4]) << sqrt(vec[x].cov33[5]) <<  0  << 0   << 0<< endl;
00830       cout << sqrt(vec[x].cov33[6]) << sqrt(vec[x].cov33[7]) << sqrt(vec[x].cov33[8]) << 0   << 0   << 0<< endl;
00831       cout <<0    << 0    << 0    <<  ((obj_descr == NULL) ? 0.2 : obj_descr->m_covRotX) << 0   << 0<< endl;
00832       cout <<0    << 0    << 0    << 0   << ((obj_descr == NULL) ? 0.2 :obj_descr->m_covRotY) << 0<< endl;
00833       cout <<0    << 0    << 0    << 0   << 0   << ((obj_descr == NULL) ? 0.8 :obj_descr->m_covRotZ)<< endl;*/
00834 
00835       cov << sqrt(vec[x].cov33[0]) << sqrt(vec[x].cov33[1]) << sqrt(vec[x].cov33[2]) << 0   << 0   << 0
00836          << sqrt(vec[x].cov33[3]) << sqrt(vec[x].cov33[4]) << sqrt(vec[x].cov33[5]) <<  0  << 0   << 0
00837          << sqrt(vec[x].cov33[6]) << sqrt(vec[x].cov33[7]) << sqrt(vec[x].cov33[8]) << 0   << 0   << 0
00838          <<0    << 0    << 0    <<  ((obj_descr == NULL) ? 0.2 : obj_descr->m_covRotX) << 0   << 0
00839          <<0    << 0    << 0    << 0   << ((obj_descr == NULL) ? 0.2 :obj_descr->m_covRotY) << 0
00840          <<0    << 0    << 0    << 0   << 0   << ((obj_descr == NULL) ? 0.8 :obj_descr->m_covRotZ);
00841      }
00842      else
00843      {
00844        cov << sqrt(vec[x].cov33[3]) << vec[x].cov33[4] << vec[x].cov33[5] << 0  << 0   << 0
00845          << vec[x].cov33[0] << vec[x].cov33[1] << vec[x].cov33[2] << 0  << 0   << 0
00846          << vec[x].cov33[6] << vec[x].cov33[7] << vec[x].cov33[8] << 0   << 0   << 0
00847          <<0    << 0    << 0    << ((obj_descr == NULL) ? 0.2 :obj_descr->m_covRotY) << 0   << 0
00848          <<0    << 0    << 0    << 0   << ((obj_descr == NULL) ? 0.2 :obj_descr->m_covRotX) << 0
00849          <<0    << 0    << 0    << 0   << 0   << ((obj_descr == NULL) ? 0.8 :obj_descr->m_covRotZ);
00850       }
00851 
00852       cout << "Cov from pc: "<< endl <<  cov << endl;
00853       RelPose* pose_temp = RelPoseFactory::FRelPose(ptu, rotmat, cov);
00854       double temp_qual = min(1.0, max(0.0, fabs((sqrt(vec[x].cov33[4])*sqrt(vec[x].cov33[0])*sqrt(vec[x].cov33[8]))) * 500 ));
00855       if(x == 0)
00856        qualityMeasure =temp_qual;
00857 
00858       if(pose_temp == NULL)
00859         continue;
00860       pose_temp->m_qualityMeasure = temp_qual;
00861       results.push_back(pose_temp);
00862     }
00863   }
00864   RelPoseFactory::FreeRelPose(&ptu);
00865   return results;
00866 }
00867 
00868 double ClusterDetector::CheckSignature(const Signature& object, const std::vector<Sensor*> &sensors)
00869 {
00870   for(std::vector<Sensor*>::const_iterator it = sensors.begin(); it != sensors.end(); it++)
00871   {
00872     if((*it)->GetName().compare(XML_NODE_SWISSRANGER) == 0)
00873     {
00874       if(object.GetElement(0, DESCRIPTOR_SEGMPROTO) != NULL )
00875         return 0.1;
00876       else
00877         return 0.0;
00878     }
00879   }
00880   return 0.0;
00881 }
00882 
00883 
00884 bool ClusterDetector::TrackingPossible(const Reading& img, const Signature& sig, RelPose* pose)
00885 {
00886     return false;
00887 }
00888 
00889 XMLTag* ClusterDetector::Save()
00890 {
00891     XMLTag* tag = new XMLTag(XML_NODE_CLUSTERDETECTOR);
00892     tag->AddProperty(XML_ATTRIBUTE_SR4LO, m_swissranger_jlo_id);
00893     tag->AddProperty(XML_ATTRIBUTE_PTULO, m_ptu_jlo_id);
00894     return tag;
00895 }
00896 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


cop_sr4_plugins
Author(s): U. Klank
autogenerated on Thu May 23 2013 09:52:16