ar_kinect_extractobject.cpp
Go to the documentation of this file.
00001 
00036 #include <pcl/ModelCoefficients.h>
00037 #include <pcl/sample_consensus/method_types.h>
00038 #include <pcl/sample_consensus/model_types.h>
00039 #include <pcl/segmentation/sac_segmentation.h>
00040 #include <pcl/features/boundary.h>
00041 #include <pcl/features/integral_image_normal.h>
00042 #include <pcl/io/pcd_io.h>
00043 #include <pcl/common/transforms.h>
00044 #include <pcl/filters/extract_indices.h>
00045 #include <pcl/filters/passthrough.h>
00046 #include <pcl/registration/transformation_estimation_svd.h>
00047 #include <pcl/features/normal_3d.h>
00048 
00049 #include "ar_kinect/ar_kinect.h"
00050 
00051 using namespace std;
00052 
00053 
00054 #ifdef AR_BOUNDING_BOX
00055 // filter point that are outside a box, i.e. parallel to the main axes and defined by minp and maxp.
00056 template<class PointType>
00057 void cropBox(const pcl::PointCloud<PointType>& input, pcl::PointXYZ minp, pcl::PointXYZ maxp, pcl::PointCloud<PointType>& output) {
00058     //        pcl::PointIndicesPtr indicesPtr(new pcl::PointIndices);
00059     DBG(cout << "points in cloud: " << input.points.size() << endl;);
00060 
00061     pcl::PassThrough<PointType> passX;
00062     passX.setKeepOrganized(true);
00063     passX.setFilterFieldName("x");
00064     passX.setFilterLimits(minp.x,maxp.x);
00065 
00066     pcl::PassThrough<PointType> passY;
00067     passY.setKeepOrganized(true);
00068     passY.setFilterFieldName("y");
00069     passY.setFilterLimits(minp.y,maxp.y);
00070 
00071     pcl::PassThrough<PointType> passZ;
00072     passZ.setKeepOrganized(true);
00073     passZ.setFilterFieldName("z");
00074     passZ.setFilterLimits(minp.z,maxp.z);
00075 
00076     pcl::PointCloud<PointType> fX;
00077     pcl::PointCloud<PointType> fY;
00078     pcl::PointCloud<PointType> fZ;
00079 
00080     passX.setInputCloud(input.makeShared());
00081     passX.filter(fX);
00082     DBG(cout << "points left after x filter: " << fX.size() << endl;);
00083 
00084     passY.setInputCloud(fX.makeShared());
00085     passY.filter(fY);
00086     DBG(cout << "points left after y filter: " << fY.size() << endl;);
00087     passZ.setInputCloud(fY.makeShared());
00088     passZ.filter(fZ);
00089 
00090     output = fZ;
00091     DBG(cout << "points left after z filter: " << output.points.size() << endl;);
00092 }
00093 
00094 inline Eigen::Affine3f rosPoseToAffine(const geometry_msgs::PoseStamped& rosPose) {
00095     Eigen::Affine3f transform = Eigen::Affine3f::Identity();
00096 
00097     transform.translate(Eigen::Vector3f(rosPose.pose.position.x,
00098                 rosPose.pose.position.y,
00099                 rosPose.pose.position.z));
00100 
00101     transform.rotate(Eigen::Quaternionf(rosPose.pose.orientation.w,
00102                 rosPose.pose.orientation.x,
00103                 rosPose.pose.orientation.y,
00104                 rosPose.pose.orientation.z));
00105     return transform;
00106 }
00107 #endif
00108 
00109 void ARPublisher::extractObject(const sensor_msgs::PointCloud2ConstPtr& msg) {
00110 #ifdef AR_BOUNDING_BOX
00111     ros::Time now = msg->header.stamp;
00112 
00113     geometry_msgs::PoseStamped origin;
00114     origin.header.frame_id = ORIGIN;
00115     origin.header.stamp = now;
00116     origin.pose.orientation.w = 1.f;
00117 
00118     pcl::PointCloud<pcl::PointXYZRGB> pcloud_in;
00119     pcl::fromROSMsg(*msg, pcloud_in);
00120 
00121 
00122     // get transformations
00123     geometry_msgs::PoseStamped cameraToMarkerPose;
00124     if (!tf_.waitForTransform(TARGET, ORIGIN, now, ros::Duration(0.5))) {
00125         ROS_INFO("no transformation from %s to %s. waiting...", ORIGIN, TARGET);
00126         return;
00127     }
00128 
00129     tf_.transformPose(TARGET, origin, cameraToMarkerPose);
00130 
00131     DBG(cout << "transformation from camera to marker: " << cameraToMarkerPose << endl;);
00132     Eigen::Affine3f cameraToMarkerTransform = rosPoseToAffine(cameraToMarkerPose);
00133     Eigen::Affine3f markerToCameraTransform = cameraToMarkerTransform.inverse();
00134 
00135     ros::param::get("boxsize", boundingbox_size);
00136 
00137     DBG(cout << "boxsize: " << boundingbox_size << endl;);
00138 
00139     pcl::PointXYZ minp(-boundingbox_size,-boundingbox_size,.01);
00140     pcl::PointXYZ maxp(boundingbox_size,boundingbox_size,2*boundingbox_size+.01);
00141 
00142     pcl::PointCloud<pcl::PointXYZ> boundingboxpcl_marker_frame;
00143     boundingboxpcl_marker_frame.push_back(pcl::PointXYZ(minp.x,minp.y,minp.z));
00144     boundingboxpcl_marker_frame.push_back(pcl::PointXYZ(minp.x,maxp.y,minp.z));
00145     boundingboxpcl_marker_frame.push_back(pcl::PointXYZ(minp.x,minp.y,maxp.z));
00146     boundingboxpcl_marker_frame.push_back(pcl::PointXYZ(minp.x,maxp.y,maxp.z));
00147 
00148     boundingboxpcl_marker_frame.push_back(pcl::PointXYZ(maxp.x,minp.y,minp.z));
00149     boundingboxpcl_marker_frame.push_back(pcl::PointXYZ(maxp.x,maxp.y,minp.z));
00150     boundingboxpcl_marker_frame.push_back(pcl::PointXYZ(maxp.x,minp.y,maxp.z));
00151     boundingboxpcl_marker_frame.push_back(pcl::PointXYZ(maxp.x,maxp.y,maxp.z));
00152 
00153     boundingboxpcl_marker_frame.header.frame_id = TARGET;
00154 
00155     pcl::PointCloud<pcl::PointXYZ> boundingboxpcl_camera_frame;
00156     pcl::transformPointCloud(boundingboxpcl_marker_frame, boundingboxpcl_camera_frame, markerToCameraTransform);
00157 
00158 
00159     // filter cloud with transformed bounding box
00160     pcl::PointXYZ minp_transformed(FLT_MAX,FLT_MAX,FLT_MAX);
00161     pcl::PointXYZ maxp_transformed(FLT_MIN,FLT_MIN,FLT_MIN);
00162     for(pcl::PointCloud<pcl::PointXYZ>::iterator it = boundingboxpcl_camera_frame.begin(); it != boundingboxpcl_camera_frame.end(); ++it ) {
00163 
00164         DBG(cerr << "Point " << count++ << ": " << it->x << "\t" <<it->y << "\t" << it->z  << endl;);
00165 
00166         if(it->x < minp_transformed.x) {
00167             minp_transformed.x = it->x;
00168         }
00169         if (it->x > maxp_transformed.x) {
00170             maxp_transformed.x = it->x;
00171         }
00172 
00173         if (it->y < minp_transformed.y) {
00174             minp_transformed.y = it->y;
00175         }
00176         if (it->y > maxp_transformed.y) {
00177             maxp_transformed.y = it->y;
00178         }
00179 
00180         if (it->z < minp_transformed.z) {
00181             minp_transformed.z = it->z;
00182         }
00183         if (it->z > maxp_transformed.z) {
00184             maxp_transformed.z = it->z;
00185         }
00186     }
00187     DBG(cout << minp_transformed << ", " << maxp_transformed << endl;);
00188 
00189     pcl::PointCloud<pcl::PointXYZRGB> pcloud_prefiltered;
00190     cropBox<pcl::PointXYZRGB>(pcloud_in, minp_transformed, maxp_transformed, pcloud_prefiltered);
00191 
00192     DBG(cout << "filtered " << pcloud_prefiltered.size()  - pcloud_in.size() << ", left: " << pcloud_prefiltered.size() << endl;);        
00193 
00194 
00195     // transform prefiltered pointcloud into TARGET coordinate system
00196     pcl::PointCloud<pcl::PointXYZRGB> pcloud_prefiltered_transformed;
00197     pcl::transformPointCloud(pcloud_prefiltered, pcloud_prefiltered_transformed, cameraToMarkerTransform);
00198     pcloud_prefiltered_transformed.header.frame_id = TARGET;
00199     // filter it according to original bounding box
00200     pcl::PointCloud<pcl::PointXYZRGB> pcloud_filtered_transformed;
00201     cropBox<pcl::PointXYZRGB>(pcloud_prefiltered_transformed, minp, maxp, pcloud_filtered_transformed);
00202 
00203     pcl::PointCloud<pcl::PointXYZRGB> pcloud_result;
00204 
00205 #ifdef ACTIVATE_TABLE_FILTER
00206     // remove table surface
00207     // only remove surfaces in xz plane
00208     geometry_msgs::Vector3Stamped yvec_marker;
00209     yvec_marker.vector.x = 0;
00210     yvec_marker.vector.y = 1;
00211     yvec_marker.vector.z = 0;
00212     geometry_msgs::Vector3Stamped yvec_camera;
00213     yvec_marker.header.frame_id = TARGET;
00214     yvec_marker.header.stamp = now;
00215     listener.transformVector(ORIGIN, yvec_marker, yvec_camera);
00216     Eigen::Vector3f yvector_camera(yvec_camera.vector.x, yvec_camera.vector.y, yvec_camera.vector.z);
00217     DBG(cout << "y Vector: " << yvector_camera << endl;);
00218 
00219 
00220     pcl::ModelCoefficients coefficients;
00221     pcl::PointIndices::Ptr inliers (new pcl::PointIndices ());
00222     // Create the segmentation object
00223     pcl::SACSegmentation<pcl::PointXYZRGB> seg;
00224     seg.setAxis(yvector_camera);
00225     // Optional
00226     seg.setOptimizeCoefficients (false);
00227     // Mandatory
00228     seg.setModelType (pcl::SACMODEL_PLANE);
00229     seg.setMethodType (pcl::SAC_RANSAC);
00230 
00231     double randist = 0.01;
00232 
00233     ros::param::get("RANSAC_DISTANCE",randist);
00234 
00235     seg.setDistanceThreshold (randist);
00236 
00237     seg.setInputCloud (pcloud_filtered_transformed.makeShared());
00238     seg.segment (*inliers, coefficients);
00239     DBG(cout << "table points: " << inliers->get_indices_size() << endl;);
00240 
00241     pcl::ExtractIndices<pcl::PointXYZRGB> extractIndices;
00242     extractIndices.setInputCloud(pcloud_prefiltered.makeShared());
00243     extractIndices.setIndices(inliers);
00244     extractIndices.setNegative(true);
00245     extractIndices.filter(pcloud_result);
00246 
00247 
00248 #else
00249 
00250     // make sure there are valid points
00251     bool validdata = false;
00252     for(size_t i=0; i<pcloud_filtered_transformed.points.size(); i++) {
00253         if (!isnan(pcloud_filtered_transformed.points.at(i).x)) {
00254             validdata = true;
00255             break;
00256         }
00257     }
00258     if (!validdata) {
00259         ROS_WARN("no point cloud found inside the bounding box above the marker pattern.");
00260         return;
00261     }
00262 
00263     pcl::search::KdTree<pcl::PointXYZRGB>::Ptr flann (new pcl::search::KdTree<pcl::PointXYZRGB> ());
00264 
00265     cerr << "estimating normals" << endl;
00266     clock_t start = clock();
00267 
00268     pcl::PointCloud<pcl::Normal>::Ptr normals_cloud(new pcl::PointCloud<pcl::Normal>);
00269     pcl::NormalEstimation<pcl::PointXYZRGB, pcl::Normal> norm_est;
00270     norm_est.setSearchMethod(flann);
00271     norm_est.setInputCloud(pcloud_filtered_transformed.makeShared());
00272     norm_est.setRadiusSearch(0.01);
00273     norm_est.compute(*normals_cloud);
00274 
00275     cerr << (double)(clock() - start) / (double)CLOCKS_PER_SEC << " seconds needed for normal estimation" << endl;
00276 
00277     /*
00278     // filter out boundary points
00279     start = clock();
00280     pcl::BoundaryEstimation<pcl::PointXYZRGB, pcl::Normal, pcl::Boundary> boundary_est;
00281     pcl::BoundaryEstimation<pcl::PointXYZRGB, pcl::Normal, pcl::Boundary>::PointCloudOut boundary;
00282     boundary_est.setRadiusSearch(0.03);
00283     boundary_est.setInputNormals(normals_cloud);
00284 
00285     boundary_est.setSearchMethod(flann);
00286     boundary_est.setInputCloud(pcloud_filtered_transformed.makeShared());
00287 
00288     boundary_est.angle_threshold_ = CV_PI / 6;
00289     boundary_est.compute(boundary);
00290 
00291     for(int i = 0; i < boundary.size(); i++) {
00292         if (boundary.points[i].boundary_point == 0) {
00293             pcloud_result.push_back(pcloud_filtered_transformed.points.at(i));
00294         } else {
00295             pcl::PointXYZRGB pt = pcloud_filtered_transformed.points.at(i);
00296             pt.x = NAN;
00297             pt.y = NAN;
00298             pt.z = NAN;
00299             pcloud_result.push_back(pt);
00300         }
00301     }
00302 
00303 
00304     cerr << pcloud_filtered_transformed.size() << "\t" << pcloud_result.size() << endl;
00305     cerr << (double)(clock() - start) / (double)CLOCKS_PER_SEC << " seconds needed for normal filter" << endl;
00306 */
00307     pcloud_result = pcloud_filtered_transformed;
00308 #endif
00309 
00310     sensor_msgs::PointCloud2 result_msg;
00311 
00312     pcl::toROSMsg<pcl::PointXYZRGB>(pcloud_result, result_msg);
00313 
00314     result_msg.header.frame_id = TARGET;
00315     result_msg.header.stamp = now;
00316     result_pcl.publish(result_msg);
00317 
00318 #endif
00319 
00320 }


ar_bounding_box
Author(s): Andreas Koch
autogenerated on Sun Jan 5 2014 11:40:39