00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #define BOOST_PARAMETER_MAX_ARITY 7
00036
00037 #include <boost/thread/thread.hpp>
00038 #include <boost/filesystem.hpp>
00039
00040 #include <pcl/features/normal_3d.h>
00041 #include <pcl/io/obj_io.h>
00042
00043 #include <cv_bridge/cv_bridge.h>
00044 #include <jsk_recognition_msgs/TrackingStatus.h>
00045 #include <jsk_recognition_msgs/SaveMesh.h>
00046 #include <jsk_recognition_utils/pcl_ros_util.h>
00047 #include <sensor_msgs/fill_image.h>
00048 #include <sensor_msgs/image_encodings.h>
00049
00050 #include "jsk_pcl_ros/kinfu.h"
00051
00052 namespace enc = sensor_msgs::image_encodings;
00053
00054
00055 namespace pcl
00056 {
00057 void
00058 concatenateFields(PointCloud<PointXYZ>& cloud_xyz, PointCloud<RGB>& cloud_rgb, PointCloud<PointXYZRGB>& cloud)
00059 {
00060 if (cloud_xyz.points.size() != cloud_rgb.points.size())
00061 {
00062 std::cout << "Clouds being concatenated must have same size." << std::endl;
00063 return;
00064 }
00065 cloud.points.resize(cloud_xyz.points.size());
00066 for (size_t i = 0; i < cloud_xyz.points.size(); i++)
00067 {
00068 cloud.points[i].x = cloud_xyz.points[i].x;
00069 cloud.points[i].y = cloud_xyz.points[i].y;
00070 cloud.points[i].z = cloud_xyz.points[i].z;
00071 cloud.points[i].r = cloud_rgb.points[i].r;
00072 cloud.points[i].g = cloud_rgb.points[i].g;
00073 cloud.points[i].b = cloud_rgb.points[i].b;
00074 }
00075 cloud.width = cloud_xyz.width;
00076 cloud.height = cloud_xyz.height;
00077 }
00078 }
00079
00080 namespace jsk_pcl_ros
00081 {
00082 void
00083 Kinfu::onInit()
00084 {
00085 ConnectionBasedNodelet::onInit();
00086 always_subscribe_ = true;
00087
00088 pnh_->param("device", device_, 0);
00089 pnh_->param("auto_reset", auto_reset_, true);
00090 pnh_->param("integrate_color", integrate_color_, false);
00091 pnh_->param("slam", slam_, false);
00092 pnh_->param<std::string>("fixed_frame_id", fixed_frame_id_, "odom_init");
00093 pnh_->param("n_textures", n_textures_, -1);
00094
00095 srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> >(*pnh_);
00096 dynamic_reconfigure::Server<Config>::CallbackType f = boost::bind(&Kinfu::configCallback, this, _1, _2);
00097 srv_->setCallback(f);
00098
00099 tf_listener_.reset(new tf::TransformListener());
00100
00101 pub_camera_pose_ = advertise<geometry_msgs::PoseStamped>(*pnh_, "output", 1);
00102 pub_cloud_ = advertise<sensor_msgs::PointCloud2>(*pnh_, "output/cloud", 1);
00103 pub_depth_ = advertise<sensor_msgs::Image>(*pnh_, "output/depth", 1);
00104 pub_rendered_image_ = advertise<sensor_msgs::Image>(*pnh_, "output/rendered_image", 1);
00105 pub_status_ = advertise<jsk_recognition_msgs::TrackingStatus>(*pnh_, "output/status", 1);
00106
00107 srv_reset_ = pnh_->advertiseService("reset", &Kinfu::resetCallback, this);
00108 srv_save_mesh_ = pnh_->advertiseService("save_mesh", &Kinfu::saveMeshCallback, this);
00109 srv_save_mesh_with_context_ = pnh_->advertiseService(
00110 "save_mesh_with_context", &Kinfu::saveMeshWithContextCallback, this);
00111
00112 onInitPostProcess();
00113 }
00114
00115 void
00116 Kinfu::configCallback(Config& config, uint32_t level)
00117 {
00118 boost::mutex::scoped_lock lock(mutex_);
00119 save_dir_ = config.save_dir;
00120 }
00121
00122 void
00123 Kinfu::initKinfu(const sensor_msgs::CameraInfo::ConstPtr& caminfo_msg)
00124 {
00125 pcl::gpu::setDevice(device_);
00126 pcl::gpu::printShortCudaDeviceInfo(device_);
00127
00128
00129
00130 float vsz = pcl::device::kinfuLS::VOLUME_SIZE;
00131 float shift_distance = pcl::device::kinfuLS::DISTANCE_THRESHOLD;
00132 Eigen::Vector3f volume_size = Eigen::Vector3f::Constant(vsz);
00133 if (shift_distance > 2.5 * vsz)
00134 {
00135 NODELET_WARN("WARNING Shifting distance (%.2f) is very large compared to the volume size (%.2f).",
00136 shift_distance, vsz);
00137 }
00138
00139 kinfu_.reset(new pcl::gpu::kinfuLS::KinfuTracker(
00140 volume_size, shift_distance, caminfo_msg->height, caminfo_msg->width));
00141
00142 Eigen::Matrix3f R = Eigen::Matrix3f::Identity();
00143 Eigen::Vector3f t = volume_size * 0.5f - Eigen::Vector3f(0, 0, volume_size(2) / 2 * 1.2f);
00144
00145 Eigen::Affine3f pose = Eigen::Translation3f(t) * Eigen::AngleAxisf(R);
00146
00147 kinfu_->setInitialCameraPose(pose);
00148 kinfu_->volume().setTsdfTruncDist(0.030f);
00149 kinfu_->setIcpCorespFilteringParams(0.1f, sin(pcl::deg2rad(20.f)));
00150
00151 kinfu_->setCameraMovementThreshold(0.001f);
00152
00153 if (integrate_color_)
00154 {
00155 const int max_color_integration_weight = 2;
00156 kinfu_->initColorIntegration(max_color_integration_weight);
00157 }
00158 }
00159
00160 void
00161 Kinfu::subscribe()
00162 {
00163 int queue_size;
00164 pnh_->param("queue_size", queue_size, 10);
00165
00166 sub_camera_info_.subscribe(*pnh_, "input/camera_info", 1);
00167 sub_depth_.subscribe(*pnh_, "input/depth", 1);
00168 if (integrate_color_)
00169 {
00170 sub_color_.subscribe(*pnh_, "input/color", 1);
00171 sync_with_color_.reset(new message_filters::Synchronizer<SyncPolicyWithColor>(queue_size));
00172 sync_with_color_->connectInput(sub_camera_info_, sub_depth_, sub_color_);
00173 sync_with_color_->registerCallback(boost::bind(&Kinfu::update, this, _1, _2, _3));
00174 }
00175 else
00176 {
00177 sync_.reset(new message_filters::Synchronizer<SyncPolicy>(queue_size));
00178 sync_->connectInput(sub_camera_info_, sub_depth_);
00179 sync_->registerCallback(boost::bind(&Kinfu::update, this, _1, _2));
00180 }
00181 }
00182
00183 void
00184 Kinfu::unsubscribe()
00185 {
00186 }
00187
00188 void
00189 Kinfu::update(const sensor_msgs::CameraInfo::ConstPtr& caminfo_msg,
00190 const sensor_msgs::Image::ConstPtr& depth_msg)
00191 {
00192 update(caminfo_msg, depth_msg, sensor_msgs::ImageConstPtr());
00193 }
00194
00195 void
00196 Kinfu::update(const sensor_msgs::CameraInfo::ConstPtr& caminfo_msg,
00197 const sensor_msgs::Image::ConstPtr& depth_msg,
00198 const sensor_msgs::Image::ConstPtr& color_msg)
00199 {
00200 boost::mutex::scoped_lock lock(mutex_);
00201
00202 if ((depth_msg->height != caminfo_msg->height) || (depth_msg->width != caminfo_msg->width))
00203 {
00204 ROS_ERROR("Image size of input depth and camera info must be same. Depth: (%d, %d), Camera Info: (%d, %d)",
00205 depth_msg->height, depth_msg->width, caminfo_msg->height, caminfo_msg->width);
00206 return;
00207 }
00208 if (integrate_color_ && ((color_msg->height != caminfo_msg->height) || (color_msg->width != color_msg->width)))
00209 {
00210 ROS_ERROR("Image size of input color image and camera info must be same. Color: (%d, %d), Camera Info: (%d, %d)",
00211 color_msg->height, color_msg->width, caminfo_msg->height, caminfo_msg->width);
00212 return;
00213 }
00214
00215 if (!kinfu_)
00216 {
00217 initKinfu(caminfo_msg);
00218 }
00219
00220
00221 {
00222 kinfu_->setDepthIntrinsics(caminfo_msg->K[0], caminfo_msg->K[4],
00223 caminfo_msg->K[2], caminfo_msg->K[5]);
00224
00225
00226 cv::Mat depth;
00227 if (depth_msg->encoding == enc::TYPE_32FC1)
00228 {
00229 cv::Mat depth_32fc1 = cv_bridge::toCvShare(depth_msg, enc::TYPE_32FC1)->image;
00230 depth_32fc1 *= 1000.;
00231 depth_32fc1.convertTo(depth, CV_16UC1);
00232 }
00233 else if (depth_msg->encoding == enc::TYPE_16UC1)
00234 {
00235 depth = cv_bridge::toCvShare(depth_msg, enc::TYPE_16UC1)->image;
00236 }
00237 else
00238 {
00239 NODELET_FATAL("Unsupported depth image encoding: %s", depth_msg->encoding.c_str());
00240 return;
00241 }
00242
00243
00244 pcl::gpu::kinfuLS::KinfuTracker::DepthMap depth_device;
00245 depth_device.upload(&(depth.data[0]), depth.cols * 2, depth.rows, depth.cols);
00246
00247
00248 if (integrate_color_)
00249 {
00250
00251 colors_device_.upload(&(color_msg->data[0]), color_msg->step, color_msg->height, color_msg->width);
00252
00253 (*kinfu_)(depth_device, colors_device_);
00254 }
00255 else
00256 {
00257 (*kinfu_)(depth_device);
00258 }
00259 frame_idx_++;
00260 }
00261
00262 jsk_recognition_msgs::TrackingStatus status;
00263 status.header = caminfo_msg->header;
00264 if (kinfu_->icpIsLost())
00265 {
00266 NODELET_FATAL_THROTTLE(10, "Tracking by ICP in kinect fusion is lost. auto_reset: %d", auto_reset_);
00267 if (auto_reset_)
00268 {
00269 kinfu_.reset();
00270 frame_idx_ = 0;
00271 cameras_.clear();
00272 }
00273 status.is_lost = true;
00274 pub_status_.publish(status);
00275 return;
00276 }
00277 status.is_lost = false;
00278 pub_status_.publish(status);
00279
00280
00281 if (integrate_color_ && (frame_idx_ % pcl::device::kinfuLS::SNAPSHOT_RATE == 1))
00282 {
00283 cv::Mat texture = cv_bridge::toCvCopy(color_msg, color_msg->encoding)->image;
00284 if (color_msg->encoding == enc::RGB8)
00285 {
00286 cv::cvtColor(texture, texture, cv::COLOR_RGB2BGR);
00287 }
00288 textures_.push_back(texture);
00289
00290 pcl::TextureMapping<pcl::PointXYZ>::Camera camera;
00291 camera.pose = kinfu_->getCameraPose();
00292 camera.focal_length = caminfo_msg->K[0];
00293 camera.height = caminfo_msg->height;
00294 camera.width = caminfo_msg->width;
00295 cameras_.push_back(camera);
00296 }
00297
00298
00299 {
00300 Eigen::Affine3f camera_pose = kinfu_->getCameraPose();
00301
00302
00303 if (pub_camera_pose_.getNumSubscribers() > 0)
00304 {
00305 geometry_msgs::PoseStamped camera_pose_msg;
00306 tf::poseEigenToMsg(camera_pose, camera_pose_msg.pose);
00307 camera_pose_msg.header.stamp = caminfo_msg->header.stamp;
00308 camera_pose_msg.header.frame_id = "kinfu_origin";
00309 pub_camera_pose_.publish(camera_pose_msg);
00310 }
00311
00312 Eigen::Affine3f camera_to_kinfu_origin = camera_pose.inverse();
00313 tf::Transform tf_camera_to_kinfu_origin;
00314 tf::transformEigenToTF(camera_to_kinfu_origin, tf_camera_to_kinfu_origin);
00315 tf_camera_to_kinfu_origin.setRotation(tf_camera_to_kinfu_origin.getRotation().normalized());
00316 tf_broadcaster_.sendTransform(
00317 tf::StampedTransform(tf_camera_to_kinfu_origin, caminfo_msg->header.stamp,
00318 caminfo_msg->header.frame_id, "kinfu_origin"));
00319
00320 if (slam_)
00321 {
00322
00323 try
00324 {
00325 tf::StampedTransform tf_odom_to_camera;
00326 tf_listener_->lookupTransform(
00327 fixed_frame_id_, caminfo_msg->header.frame_id, ros::Time(0), tf_odom_to_camera);
00328 Eigen::Affine3f odom_to_camera;
00329 tf::transformTFToEigen(tf_odom_to_camera, odom_to_camera);
00330
00331 if (frame_idx_ == 1)
00332 {
00333 odom_init_to_kinfu_origin_ = odom_to_camera * camera_to_kinfu_origin;
00334 }
00335
00336 Eigen::Affine3f map_to_odom;
00337
00338 map_to_odom = odom_init_to_kinfu_origin_ * (odom_to_camera * camera_to_kinfu_origin).inverse();
00339 tf::StampedTransform tf_map_to_odom;
00340 tf::transformEigenToTF(map_to_odom, tf_map_to_odom);
00341 tf_map_to_odom.setRotation(tf_map_to_odom.getRotation().normalized());
00342 tf_broadcaster_.sendTransform(
00343 tf::StampedTransform(tf_map_to_odom, caminfo_msg->header.stamp, "map", fixed_frame_id_));
00344 }
00345 catch (tf::TransformException e)
00346 {
00347 NODELET_FATAL("%s", e.what());
00348 }
00349 }
00350 }
00351
00352
00353 if (pub_depth_.getNumSubscribers() > 0)
00354 {
00355 pcl::gpu::kinfuLS::KinfuTracker::DepthMap depth_gpu;
00356 Eigen::Affine3f camera_pose = kinfu_->getCameraPose();
00357 if (!raycaster_)
00358 {
00359 raycaster_ = pcl::gpu::kinfuLS::RayCaster::Ptr(
00360 new pcl::gpu::kinfuLS::RayCaster(
00361 kinfu_->rows(), kinfu_->cols(),
00362 caminfo_msg->K[0], caminfo_msg->K[4],
00363 caminfo_msg->K[2], caminfo_msg->K[5]));
00364 }
00365 raycaster_->run(kinfu_->volume(), camera_pose, kinfu_->getCyclicalBufferStructure());
00366 raycaster_->generateDepthImage(depth_gpu);
00367
00368 int cols;
00369 std::vector<unsigned short> data;
00370 depth_gpu.download(data, cols);
00371
00372 sensor_msgs::Image output_depth_msg;
00373 sensor_msgs::fillImage(output_depth_msg,
00374 enc::TYPE_16UC1,
00375 depth_gpu.rows(),
00376 depth_gpu.cols(),
00377 depth_gpu.cols() * 2,
00378 reinterpret_cast<unsigned short*>(&data[0]));
00379 output_depth_msg.header = caminfo_msg->header;
00380 pub_depth_.publish(output_depth_msg);
00381 }
00382
00383
00384 if (pub_rendered_image_.getNumSubscribers() > 0)
00385 {
00386 pcl::gpu::kinfuLS::KinfuTracker::View view_device;
00387 std::vector<pcl::gpu::kinfuLS::PixelRGB> view_host;
00388 kinfu_->getImage(view_device);
00389
00390 if (integrate_color_)
00391 {
00392 pcl::gpu::kinfuLS::paint3DView(colors_device_, view_device);
00393 }
00394
00395 int cols;
00396 view_device.download(view_host, cols);
00397
00398 sensor_msgs::Image rendered_image_msg;
00399 sensor_msgs::fillImage(rendered_image_msg,
00400 enc::RGB8,
00401 view_device.rows(),
00402 view_device.cols(),
00403 view_device.cols() * 3,
00404 reinterpret_cast<unsigned char*>(&view_host[0]));
00405 rendered_image_msg.header = caminfo_msg->header;
00406 pub_rendered_image_.publish(rendered_image_msg);
00407 }
00408
00409
00410 if (pub_cloud_.getNumSubscribers() > 0)
00411 {
00412 pcl::gpu::DeviceArray<pcl::PointXYZ> cloud_buffer_device;
00413 pcl::gpu::DeviceArray<pcl::PointXYZ> extracted = kinfu_->volume().fetchCloud(cloud_buffer_device);
00414
00415 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz(new pcl::PointCloud<pcl::PointXYZ>());
00416 extracted.download(cloud_xyz->points);
00417 cloud_xyz->width = static_cast<int>(cloud_xyz->points.size());
00418 cloud_xyz->height = 1;
00419
00420 sensor_msgs::PointCloud2 output_cloud_msg;
00421 if (integrate_color_)
00422 {
00423 pcl::gpu::DeviceArray<pcl::RGB> point_colors_device;
00424 kinfu_->colorVolume().fetchColors(extracted, point_colors_device);
00425
00426 pcl::PointCloud<pcl::RGB>::Ptr cloud_rgb(new pcl::PointCloud<pcl::RGB>());
00427 point_colors_device.download(cloud_rgb->points);
00428 cloud_rgb->width = static_cast<int>(cloud_rgb->points.size());
00429 cloud_rgb->height = 1;
00430
00431 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>());
00432 cloud->points.resize(cloud_xyz->width);
00433 pcl::concatenateFields(*cloud_xyz, *cloud_rgb, *cloud);
00434 pcl::toROSMsg(*cloud, output_cloud_msg);
00435 }
00436 else
00437 {
00438 pcl::toROSMsg(*cloud_xyz, output_cloud_msg);
00439 }
00440 output_cloud_msg.header.frame_id = "kinfu_origin";
00441 pub_cloud_.publish(output_cloud_msg);
00442 }
00443 }
00444
00445 bool
00446 Kinfu::resetCallback(std_srvs::Empty::Request& req, std_srvs::Empty::Response& res)
00447 {
00448 boost::mutex::scoped_lock lock(mutex_);
00449 kinfu_.reset();
00450 textures_.clear();
00451 cameras_.clear();
00452 NODELET_INFO("Reset kinect fusion by request.");
00453 return true;
00454 }
00455
00456 bool
00457 Kinfu::saveMeshWithContextCallback(
00458 jsk_recognition_msgs::SaveMesh::Request& req, jsk_recognition_msgs::SaveMesh::Response& res)
00459 {
00460 pcl::PolygonMesh polygon_mesh = createPolygonMesh(req.box, req.ground_frame_id);
00461
00462 boost::filesystem::path dir(integrate_color_ ? save_dir_ + "/textures" : save_dir_);
00463 if (boost::filesystem::create_directories(dir))
00464 {
00465 NODELET_INFO("Created save_dir: %s", save_dir_.c_str());
00466 }
00467
00468 std::string out_file = save_dir_ + "/mesh.obj";
00469 if (integrate_color_ && n_textures_ != 0)
00470 {
00471 pcl::TextureMesh texture_mesh;
00472 if (n_textures_ > 0)
00473 {
00474 std::vector<cv::Mat> textures(textures_.end() - n_textures_, textures_.end());
00475 pcl::texture_mapping::CameraVector cameras(cameras_.end() - n_textures_, cameras_.end());
00476 texture_mesh = convertToTextureMesh(polygon_mesh, textures, cameras);
00477 }
00478 else
00479 {
00480 texture_mesh = convertToTextureMesh(polygon_mesh, textures_, cameras_);
00481 }
00482 pcl::io::saveOBJFile(out_file, texture_mesh, 5);
00483 }
00484 else
00485 {
00486 pcl::io::saveOBJFile(out_file, polygon_mesh);
00487 }
00488 NODELET_INFO("Saved mesh file: %s", out_file.c_str());
00489 return true;
00490 }
00491
00492 bool
00493 Kinfu::saveMeshCallback(std_srvs::Empty::Request& req, std_srvs::Empty::Response& res)
00494 {
00495 pcl::PolygonMesh polygon_mesh = createPolygonMesh();
00496
00497 boost::filesystem::path dir(integrate_color_ ? save_dir_ + "/textures" : save_dir_);
00498 if (boost::filesystem::create_directories(dir))
00499 {
00500 NODELET_INFO("Created save_dir: %s", save_dir_.c_str());
00501 }
00502
00503 std::string out_file = save_dir_ + "/mesh.obj";
00504 if (integrate_color_ && n_textures_ != 0)
00505 {
00506 pcl::TextureMesh texture_mesh;
00507 if (n_textures_ > 0)
00508 {
00509 std::vector<cv::Mat> textures(textures_.end() - n_textures_, textures_.end());
00510 pcl::texture_mapping::CameraVector cameras(cameras_.end() - n_textures_, cameras_.end());
00511 texture_mesh = convertToTextureMesh(polygon_mesh, textures, cameras);
00512 }
00513 else
00514 {
00515 texture_mesh = convertToTextureMesh(polygon_mesh, textures_, cameras_);
00516 }
00517 pcl::io::saveOBJFile(out_file, texture_mesh, 5);
00518 }
00519 else
00520 {
00521 pcl::io::saveOBJFile(out_file, polygon_mesh);
00522 }
00523 NODELET_INFO("Saved mesh file: %s", out_file.c_str());
00524 return true;
00525 }
00526
00527 pcl::TextureMesh
00528 Kinfu::convertToTextureMesh(const pcl::PolygonMesh& triangles,
00529 const std::vector<cv::Mat> textures,
00530 pcl::texture_mapping::CameraVector cameras)
00531 {
00532 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
00533 pcl::fromPCLPointCloud2(triangles.cloud, *cloud);
00534
00535
00536 pcl::TextureMesh mesh;
00537 mesh.cloud = triangles.cloud;
00538 std::vector< pcl::Vertices> polygon_1;
00539
00540
00541 polygon_1.resize (triangles.polygons.size ());
00542 for(size_t i =0; i < triangles.polygons.size (); ++i)
00543 {
00544 polygon_1[i] = triangles.polygons[i];
00545 }
00546 mesh.tex_polygons.push_back(polygon_1);
00547 NODELET_INFO("Input mesh contains %lu faces, %lu vertices and %lu textures.",
00548 mesh.tex_polygons[0].size(), cloud->points.size(), cameras.size());
00549
00550
00551 mesh.tex_materials.resize(cameras.size () + 1);
00552 for(int i = 0 ; i <= cameras.size() ; ++i)
00553 {
00554 pcl::TexMaterial mesh_material;
00555 mesh_material.tex_Ka.r = 0.2f;
00556 mesh_material.tex_Ka.g = 0.2f;
00557 mesh_material.tex_Ka.b = 0.2f;
00558
00559 mesh_material.tex_Kd.r = 0.8f;
00560 mesh_material.tex_Kd.g = 0.8f;
00561 mesh_material.tex_Kd.b = 0.8f;
00562
00563 mesh_material.tex_Ks.r = 1.0f;
00564 mesh_material.tex_Ks.g = 1.0f;
00565 mesh_material.tex_Ks.b = 1.0f;
00566
00567 mesh_material.tex_d = 1.0f;
00568 mesh_material.tex_Ns = 75.0f;
00569 mesh_material.tex_illum = 2;
00570
00571 std::stringstream tex_name;
00572 tex_name << "material_" << i;
00573 tex_name >> mesh_material.tex_name;
00574
00575 if (i < cameras.size ())
00576 {
00577 std::stringstream ss;
00578 ss << "textures/" << i << ".jpg";
00579 std::string texture_file = ss.str();
00580 cv::imwrite(save_dir_ + "/" + texture_file, textures[i]);
00581 cameras[i].texture_file = texture_file;
00582 mesh_material.tex_file = texture_file;
00583 }
00584 else
00585 {
00586 std::string texture_file = "textures/occluded.jpg";
00587 cv::imwrite(save_dir_ + "/" + texture_file,
00588 cv::Mat::zeros(textures[0].rows, textures[0].cols, CV_8UC1));
00589 mesh_material.tex_file = texture_file;
00590 }
00591
00592 mesh.tex_materials[i] = mesh_material;
00593 }
00594
00595
00596 pcl::TextureMapping<pcl::PointXYZ> tm;
00597 tm.textureMeshwithMultipleCameras(mesh, cameras);
00598
00599
00600 pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> n;
00601 pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
00602 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
00603 tree->setInputCloud(cloud);
00604 n.setInputCloud(cloud);
00605 n.setSearchMethod(tree);
00606 n.setKSearch(20);
00607 n.compute(*normals);
00608 pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>);
00609 pcl::concatenateFields(*cloud, *normals, *cloud_with_normals);
00610 pcl::toPCLPointCloud2(*cloud_with_normals, mesh.cloud);
00611
00612 return mesh;
00613 }
00614
00615 pcl::PolygonMesh
00616 Kinfu::createPolygonMesh()
00617 {
00618
00619 if (!marching_cubes_)
00620 {
00621 marching_cubes_ = pcl::gpu::kinfuLS::MarchingCubes::Ptr(new pcl::gpu::kinfuLS::MarchingCubes());
00622 }
00623 pcl::gpu::DeviceArray<pcl::PointXYZ> triangles_buffer_device;
00624 pcl::gpu::DeviceArray<pcl::PointXYZ> triangles_device =
00625 marching_cubes_->run(kinfu_->volume(), triangles_buffer_device);
00626
00627 if (triangles_device.empty())
00628 {
00629 return pcl::PolygonMesh();
00630 }
00631
00632 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
00633 cloud->width = static_cast<int>(triangles_device.size());
00634 cloud->height = 1;
00635 cloud->header.frame_id = "kinfu_origin";
00636 triangles_device.download(cloud->points);
00637
00638 pcl::PolygonMesh mesh;
00639 pcl::toPCLPointCloud2(*cloud, mesh.cloud);
00640 mesh.polygons.resize(triangles_device.size() / 3);
00641 for (size_t i = 0; i < mesh.polygons.size(); ++i)
00642 {
00643 pcl::Vertices v;
00644 v.vertices.push_back(i*3+0);
00645 v.vertices.push_back(i*3+2);
00646 v.vertices.push_back(i*3+1);
00647 mesh.polygons[i] = v;
00648 }
00649 return mesh;
00650 }
00651
00652 pcl::PolygonMesh
00653 Kinfu::createPolygonMesh(const jsk_recognition_msgs::BoundingBox& box_msg, const std::string& ground_frame_id)
00654 {
00655
00656 if (!marching_cubes_)
00657 {
00658 marching_cubes_ = pcl::gpu::kinfuLS::MarchingCubes::Ptr(new pcl::gpu::kinfuLS::MarchingCubes());
00659 }
00660 pcl::gpu::DeviceArray<pcl::PointXYZ> triangles_buffer_device;
00661 pcl::gpu::DeviceArray<pcl::PointXYZ> triangles_device =
00662 marching_cubes_->run(kinfu_->volume(), triangles_buffer_device);
00663
00664 if (triangles_device.empty())
00665 {
00666 return pcl::PolygonMesh();
00667 }
00668
00669
00670 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>());
00671 cloud->width = static_cast<int>(triangles_device.size());
00672 cloud->height = 1;
00673 cloud->header.frame_id = "kinfu_origin";
00674 triangles_device.download(cloud->points);
00675
00676
00677 Eigen::Affine3f kinfu_origin_to_box = Eigen::Affine3f::Identity();
00678 if (box_msg.header.frame_id != "kinfu_origin")
00679 {
00680 tf::StampedTransform tf_kinfu_origin_to_box;
00681 tf_listener_->lookupTransform("kinfu_origin", box_msg.header.frame_id, ros::Time(0), tf_kinfu_origin_to_box);
00682 tf::transformTFToEigen(tf_kinfu_origin_to_box, kinfu_origin_to_box);
00683 }
00684
00685
00686 jsk_recognition_msgs::BoundingBox transformed_box_msg;
00687 transformed_box_msg.dimensions = box_msg.dimensions;
00688 Eigen::Affine3f box_pose;
00689 tf::poseMsgToEigen(box_msg.pose, box_pose);
00690 box_pose = kinfu_origin_to_box * box_pose;
00691 tf::poseEigenToMsg(box_pose, transformed_box_msg.pose);
00692 transformed_box_msg.header.frame_id = "kinfu_origin";
00693
00694
00695 std::vector<int> indices;
00696 jsk_recognition_utils::cropPointCloud<pcl::PointXYZ>(cloud, transformed_box_msg, &indices);
00697
00698
00699 pcl::PolygonMesh mesh;
00700 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in_box(new pcl::PointCloud<pcl::PointXYZ>());
00701 cloud_in_box->width = static_cast<int>(indices.size());
00702 cloud_in_box->height = 1;
00703 cloud_in_box->points.resize(indices.size());
00704 for (size_t i = 0; i < indices.size(); i++)
00705 {
00706 cloud_in_box->points[i] = cloud->points[indices[i]];
00707 if (indices[i] % 3 == 0 && (indices[i] + 1) == indices[i + 1] && (indices[i] + 2) == indices[i + 2])
00708 {
00709 pcl::Vertices v;
00710 v.vertices.push_back(i + 0);
00711 v.vertices.push_back(i + 2);
00712 v.vertices.push_back(i + 1);
00713 mesh.polygons.push_back(v);
00714 }
00715 }
00716
00717
00718 if (!ground_frame_id.empty())
00719 {
00720 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_ground_frame(new pcl::PointCloud<pcl::PointXYZ>());
00721 tf::StampedTransform tf_transform;
00722 tf_listener_->lookupTransform(ground_frame_id, "kinfu_origin", ros::Time(0), tf_transform);
00723 Eigen::Affine3f transform;
00724 tf::transformTFToEigen(tf_transform, transform);
00725 pcl::transformPointCloud(*cloud_in_box, *cloud_ground_frame, transform);
00726
00727 pcl::PointXYZ min_pt, max_pt;
00728 pcl::getMinMax3D(*cloud_ground_frame, min_pt, max_pt);
00729
00730 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_occluded(new pcl::PointCloud<pcl::PointXYZ>());
00731 for (size_t i = 0; i < cloud_ground_frame->points.size(); i++)
00732 {
00733 pcl::PointXYZ pt_visible = cloud_ground_frame->points[i];
00734 pcl::PointXYZ pt_occluded(pt_visible.x, pt_visible.y, min_pt.z);
00735 cloud_occluded->points.push_back(pt_occluded);
00736 if (i >= 3)
00737 {
00738 pcl::Vertices v;
00739 v.vertices.push_back(cloud_in_box->width + i - 2);
00740 v.vertices.push_back(cloud_in_box->width + i - 1);
00741 v.vertices.push_back(cloud_in_box->width + i - 0);
00742 mesh.polygons.push_back(v);
00743 }
00744 }
00745 cloud_occluded->width = cloud_occluded->points.size();
00746 cloud_occluded->height = 1;
00747 pcl::transformPointCloud(*cloud_occluded, *cloud_occluded, transform.inverse());
00748 *cloud_in_box = *cloud_in_box + *cloud_occluded;
00749 }
00750
00751 pcl::toPCLPointCloud2(*cloud_in_box, mesh.cloud);
00752 return mesh;
00753 }
00754 }
00755
00756 #include <pluginlib/class_list_macros.h>
00757 PLUGINLIB_EXPORT_CLASS(jsk_pcl_ros::Kinfu, nodelet::Nodelet);