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 
00056 template<class PointType>
00057 void cropBox(const pcl::PointCloud<PointType>& input, pcl::PointXYZ minp, pcl::PointXYZ maxp, pcl::PointCloud<PointType>& output) {
00058     
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     
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     
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     
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     
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     
00207     
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     
00223     pcl::SACSegmentation<pcl::PointXYZRGB> seg;
00224     seg.setAxis(yvector_camera);
00225     
00226     seg.setOptimizeCoefficients (false);
00227     
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     
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 
00279 
00280 
00281 
00282 
00283 
00284 
00285 
00286 
00287 
00288 
00289 
00290 
00291 
00292 
00293 
00294 
00295 
00296 
00297 
00298 
00299 
00300 
00301 
00302 
00303 
00304 
00305 
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 }