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 }