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
00036 #include "jsk_pcl_ros/kinfu.h"
00037 #include <geometry_msgs/PoseStamped.h>
00038 #include "jsk_pcl_ros/pcl_conversion_util.h"
00039 #include <pcl/common/transforms.h>
00040 #include <cv_bridge/cv_bridge.h>
00041
00042 namespace jsk_pcl_ros
00043 {
00044 void Kinfu::subscribe()
00045 {
00046
00047 }
00048
00049 void Kinfu::unsubscribe()
00050 {
00051
00052 }
00053
00054 void Kinfu::onInit()
00055 {
00056 DiagnosticNodelet::onInit();
00057 initialized_ = false;
00058 tf_listener_ = TfListenerSingleton::getInstance();
00059 pnh_->param("parent_frame_id", parent_frame_id_, std::string("map"));
00060 pnh_->param("child_frame_id", child_frame_id_, std::string("odom"));
00061 pnh_->param("kinfu_origin_frame_id", kinfu_origin_frame_id_, std::string("kinfu_origin"));
00062 pcl::gpu::setDevice(0);
00063 pcl::gpu::printShortCudaDeviceInfo(0);
00064 volume_size_ = pcl::device::kinfuLS::VOLUME_SIZE;
00065 shift_distance_ = pcl::device::kinfuLS::DISTANCE_THRESHOLD;
00066 snapshot_rate_ = pcl::device::kinfuLS::SNAPSHOT_RATE;
00067 pub_pose_ = pnh_->advertise<geometry_msgs::PoseStamped>("output", 1);
00068 pub_cloud_ = pnh_->advertise<sensor_msgs::PointCloud2>("output/cloud", 1);
00069 sub_depth_image_.subscribe(*pnh_, "input/depth", 1);
00070 sub_color_image_.subscribe(*pnh_, "input/color", 1);
00071 sync_ = boost::make_shared<message_filters::Synchronizer<SyncPolicy> >(100);
00072 sync_->connectInput(sub_depth_image_, sub_color_image_);
00073 sync_->registerCallback(boost::bind(&Kinfu::callback, this, _1, _2));
00074 sub_info_ = pnh_->subscribe("input/info", 1, &Kinfu::infoCallback, this);
00075 }
00076
00077 void Kinfu::infoCallback(const sensor_msgs::CameraInfo::ConstPtr& info_msg)
00078 {
00079 boost::mutex::scoped_lock lock(mutex_);
00080 info_msg_ = info_msg;
00081 }
00082
00083 void Kinfu::callback(const sensor_msgs::Image::ConstPtr& depth_image,
00084 const sensor_msgs::Image::ConstPtr& rgb_image)
00085 {
00086 boost::mutex::scoped_lock lock(mutex_);
00087 if (!info_msg_) {
00088 JSK_NODELET_WARN("camera info is not yet ready");
00089 return;
00090 }
00091 if (!initialized_) {
00092 Eigen::Vector3f volume_size = Eigen::Vector3f::Constant (volume_size_);
00093
00094
00095 kinfu_ = new pcl::gpu::kinfuLS::KinfuTracker(volume_size,
00096 shift_distance_,
00097 info_msg_->height,
00098 info_msg_->width);
00099 kinfu_->setInitialCameraPose(Eigen::Affine3f::Identity());
00100 kinfu_->volume().setTsdfTruncDist (0.030f);
00101 kinfu_->setIcpCorespFilteringParams (0.1f, sin ( pcl::deg2rad(20.f) ));
00102 kinfu_->setCameraMovementThreshold(0.001f);
00103 kinfu_->setDepthIntrinsics (info_msg_->K[0], info_msg_->K[4], info_msg_->K[2], info_msg_->K[5]);
00104 initialized_ = true;
00105 initial_camera_pose_acquired_ = false;
00106 }
00107 if (kinfu_->icpIsLost()) {
00108 kinfu_->reset();
00109 JSK_NODELET_FATAL("kinfu is reset");
00110 }
00111
00112 if (!initial_camera_pose_acquired_) {
00113
00114 try {
00115
00116 tf::StampedTransform trans =
00117 lookupTransformWithDuration(tf_listener_,
00118 info_msg_->header.frame_id,
00119 child_frame_id_,
00120 depth_image->header.stamp,
00121 ros::Duration(1.0));
00122 tf::transformTFToEigen(trans, initial_camera_pose_);
00123 }
00124 catch (...) {
00125 JSK_NODELET_ERROR("Failed to lookup transform from %s to %s",
00126 child_frame_id_.c_str(),
00127 info_msg_->header.frame_id.c_str());
00128 return;
00129 }
00130 }
00131
00132 cv::Mat depth_m_image = cv_bridge::toCvShare(depth_image, "32FC1")->image;
00133 cv::Mat depth_mm_image = depth_m_image * 1000.0;
00134 cv::Mat depth_mm_sc_image;
00135 depth_mm_image.convertTo(depth_mm_sc_image, CV_16UC1);
00136 depth_device_.upload(&(depth_mm_sc_image.data[0]), depth_image->width * 2, depth_image->height, depth_image->width);
00137
00138
00139
00140 (*kinfu_)(depth_device_);
00141 Eigen::Affine3f camera_pose = kinfu_->getCameraPose();
00142 if (!initial_camera_pose_acquired_) {
00143 initial_kinfu_pose_ = camera_pose;
00144 initial_camera_pose_acquired_ = true;
00145 }
00146 else {
00147 Eigen::Affine3f K = initial_kinfu_pose_.inverse() * camera_pose;
00148
00149 try {
00150
00151 tf::StampedTransform trans =
00152 lookupTransformWithDuration(tf_listener_,
00153 depth_image->header.frame_id,
00154 child_frame_id_,
00155 depth_image->header.stamp,
00156 ros::Duration(0.1));
00157 Eigen::Affine3f odom_camera;
00158 tf::transformTFToEigen(trans, odom_camera);
00159 Eigen::Affine3f map = initial_camera_pose_ * K * odom_camera.inverse();
00160 tf::Transform map_odom_transform;
00161 tf::transformEigenToTF(map, map_odom_transform);
00162 tf_broadcaster_.sendTransform(tf::StampedTransform(
00163 map_odom_transform,
00164 depth_image->header.stamp,
00165 parent_frame_id_,
00166 child_frame_id_));
00167 tf::Transform kinfu_origin;
00168 Eigen::Affine3f inverse_camera_pose = camera_pose.inverse();
00169 tf::transformEigenToTF(inverse_camera_pose, kinfu_origin);
00170 tf_broadcaster_.sendTransform(tf::StampedTransform(
00171 kinfu_origin,
00172 depth_image->header.stamp,
00173 depth_image->header.frame_id,
00174 kinfu_origin_frame_id_));
00175 Eigen::Affine3f camera_diff = K.inverse();
00176 geometry_msgs::PoseStamped ros_camera_diff;
00177 tf::poseEigenToMsg(camera_diff, ros_camera_diff.pose);
00178 ros_camera_diff.header = depth_image->header;
00179 pub_pose_.publish(ros_camera_diff);
00180
00181
00182 pcl::gpu::DeviceArray<pcl::PointXYZ> extracted = kinfu_->volume().fetchCloud(cloud_buffer_device_);
00183 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
00184 pcl::PointCloud<pcl::PointXYZ>::Ptr transformed_cloud(new pcl::PointCloud<pcl::PointXYZ>);
00185 extracted.download (cloud->points);
00186 cloud->width = (int)cloud->points.size ();
00187 cloud->height = 1;
00188
00189 sensor_msgs::PointCloud2 ros_cloud;
00190 pcl::toROSMsg(*cloud, ros_cloud);
00191 ros_cloud.header.stamp = depth_image->header.stamp;
00192 ros_cloud.header.frame_id = kinfu_origin_frame_id_;
00193 pub_cloud_.publish(ros_cloud);
00194 }
00195 catch (...) {
00196 JSK_NODELET_ERROR("Failed to lookup transform from %s to %s",
00197 child_frame_id_.c_str(),
00198 depth_image->header.frame_id.c_str());
00199 return;
00200 }
00201 }
00202 }
00203
00204 }
00205
00206 #include <pluginlib/class_list_macros.h>
00207 PLUGINLIB_EXPORT_CLASS (jsk_pcl_ros::Kinfu,
00208 nodelet::Nodelet);