void PlaneSupportedCuboidEstimator::cloudCallback(
    const sensor_msgs::PointCloud2::ConstPtr& msg)
  {
    boost::mutex::scoped_lock lock(mutex_);
    NODELET_INFO("cloudCallback");
    if (!latest_polygon_msg_ || !latest_coefficients_msg_) {
      JSK_NODELET_WARN("Not yet polygon is available");
      return;
    }

    if (!tracker_) {
      NODELET_INFO("initTracker");
      // Update polygons_ vector
      polygons_.clear();
      for (size_t i = 0; i < latest_polygon_msg_->polygons.size(); i++) {
        Polygon::Ptr polygon = Polygon::fromROSMsgPtr(latest_polygon_msg_->polygons[i].polygon);
        polygons_.push_back(polygon);
      }
      // viewpoint
      tf::StampedTransform transform
        = lookupTransformWithDuration(tf_, sensor_frame_, msg->header.frame_id,
                                      ros::Time(0.0),
                                      ros::Duration(0.0));
      tf::vectorTFToEigen(transform.getOrigin(), viewpoint_);
      
      ParticleCloud::Ptr particles = initParticles();
      tracker_.reset(new pcl::tracking::ROSCollaborativeParticleFilterTracker<pcl::PointXYZ, pcl::tracking::ParticleCuboid>);
      tracker_->setCustomSampleFunc(boost::bind(&PlaneSupportedCuboidEstimator::sample, this, _1));
      tracker_->setLikelihoodFunc(boost::bind(&PlaneSupportedCuboidEstimator::likelihood, this, _1, _2));
      tracker_->setParticles(particles);
      tracker_->setParticleNum(particle_num_);
      support_plane_updated_ = false;
      // Publish histograms
      publishHistogram(particles, 0, pub_histogram_global_x_, msg->header);
      publishHistogram(particles, 1, pub_histogram_global_y_, msg->header);
      publishHistogram(particles, 2, pub_histogram_global_z_, msg->header);
      publishHistogram(particles, 3, pub_histogram_global_roll_, msg->header);
      publishHistogram(particles, 4, pub_histogram_global_pitch_, msg->header);
      publishHistogram(particles, 5, pub_histogram_global_yaw_, msg->header);
      publishHistogram(particles, 6, pub_histogram_dx_, msg->header);
      publishHistogram(particles, 7, pub_histogram_dy_, msg->header);
      publishHistogram(particles, 8, pub_histogram_dz_, msg->header);
      // Publish particles
      sensor_msgs::PointCloud2 ros_particles;
      pcl::toROSMsg(*particles, ros_particles);
      ros_particles.header = msg->header;
      pub_particles_.publish(ros_particles);
      
    }
    else {
      ParticleCloud::Ptr particles = tracker_->getParticles();
      Eigen::Vector4f center;
      pcl::compute3DCentroid(*particles, center);
      if (center.norm() > fast_cloud_threshold_) {
        estimate(msg);
      }
    }
  }
 std::vector<jsk_recognition_utils::ConvexPolygon::Ptr> SnapIt::createConvexes(
   const std::string& frame_id, const ros::Time& stamp,
   jsk_recognition_msgs::PolygonArray::ConstPtr polygons)
 {
   std::vector<jsk_recognition_utils::ConvexPolygon::Ptr> result;
   try
   {
     for (size_t i = 0; i < polygons->polygons.size(); i++) {
       geometry_msgs::PolygonStamped polygon = polygons->polygons[i];
       jsk_recognition_utils::Vertices vertices;
       
       tf::StampedTransform transform = lookupTransformWithDuration(
         tf_listener_,
         polygon.header.frame_id, frame_id, stamp, ros::Duration(5.0));
       for (size_t j = 0; j < polygon.polygon.points.size(); j++) {
         Eigen::Vector4d p;
         p[0] = polygon.polygon.points[j].x;
         p[1] = polygon.polygon.points[j].y;
         p[2] = polygon.polygon.points[j].z;
         p[3] = 1;
         Eigen::Affine3d eigen_transform;
         tf::transformTFToEigen(transform, eigen_transform);
         Eigen::Vector4d transformed_pointd = eigen_transform.inverse() * p;
         Eigen::Vector3f transformed_point;
         transformed_point[0] = transformed_pointd[0];
         transformed_point[1] = transformed_pointd[1];
         transformed_point[2] = transformed_pointd[2];
         vertices.push_back(transformed_point);
       }
       std::reverse(vertices.begin(), vertices.end());
       jsk_recognition_utils::ConvexPolygon::Ptr convex(new jsk_recognition_utils::ConvexPolygon(vertices));
       result.push_back(convex);
     }
   }
   catch (tf2::ConnectivityException &e)
   {
     JSK_NODELET_ERROR("Transform error: %s", e.what());
   }
   catch (tf2::InvalidArgumentException &e)
   {
     JSK_NODELET_ERROR("Transform error: %s", e.what());
   }
   catch (tf2::ExtrapolationException &e)
   {
     JSK_NODELET_ERROR("Transform error: %s", e.what());
   }
   return result;
 }
  void PointCloudLocalization::tfTimerCallback(
    const ros::TimerEvent& event)
  {
    boost::mutex::scoped_lock lock(tf_mutex_);
    try {
    ros::Time stamp = event.current_real;
    if (initialize_from_tf_ && first_time_) {
      // Update localize_transform_ to points initialize_tf
      tf::StampedTransform transform = lookupTransformWithDuration(
        tf_listener_,
        initialize_tf_, odom_frame_, stamp, ros::Duration(1.0));
      localize_transform_ = transform;

    }
    tf_broadcast_.sendTransform(tf::StampedTransform(localize_transform_,
                                                     stamp,
                                                     global_frame_,
                                                     odom_frame_));
    }
    catch (tf2::TransformException& e) {
      JSK_NODELET_FATAL("Failed to lookup transformation: %s", e.what());
    }
  }
  void PlaneSupportedCuboidEstimator::estimate(
    const sensor_msgs::PointCloud2::ConstPtr& msg)
  {
    // Update polygons_ vector
    polygons_.clear();
    for (size_t i = 0; i < latest_polygon_msg_->polygons.size(); i++) {
      Polygon::Ptr polygon = Polygon::fromROSMsgPtr(latest_polygon_msg_->polygons[i].polygon);
      polygon->decomposeToTriangles();
      polygons_.push_back(polygon);
    }
    
    try {
    // viewpoint
    tf::StampedTransform transform
      = lookupTransformWithDuration(tf_, sensor_frame_, msg->header.frame_id,
                                    ros::Time(0.0),
                                    ros::Duration(0.0));
    tf::vectorTFToEigen(transform.getOrigin(), viewpoint_);

    if (!tracker_) {
      NODELET_INFO("initTracker");
      pcl::PointCloud<pcl::tracking::ParticleCuboid>::Ptr particles = initParticles();
      tracker_.reset(new pcl::tracking::ROSCollaborativeParticleFilterTracker<pcl::PointXYZ, pcl::tracking::ParticleCuboid>);
      tracker_->setCustomSampleFunc(boost::bind(&PlaneSupportedCuboidEstimator::sample, this, _1));
      tracker_->setLikelihoodFunc(boost::bind(&PlaneSupportedCuboidEstimator::likelihood, this, _1, _2));
      tracker_->setParticles(particles);
      tracker_->setParticleNum(particle_num_);
    }
    else {
      pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
      pcl::fromROSMsg(*msg, *cloud);
      tracker_->setInputCloud(cloud);
      // Before call compute() method, we prepare candidate_cloud_ for
      // weight phase.
      candidate_cloud_.reset(new pcl::PointCloud<pcl::PointXYZ>);
      std::set<int> all_indices;
      for (size_t i = 0; i < latest_polygon_msg_->polygons.size(); i++) {
        Polygon::Ptr polygon = Polygon::fromROSMsgPtr(latest_polygon_msg_->polygons[i].polygon);
        pcl::ExtractPolygonalPrismData<pcl::PointXYZ> prism_extract;
        pcl::PointCloud<pcl::PointXYZ>::Ptr
          boundaries (new pcl::PointCloud<pcl::PointXYZ>);
        polygon->boundariesToPointCloud<pcl::PointXYZ>(*boundaries);
        boundaries->points.push_back(boundaries->points[0]);
        prism_extract.setInputCloud(cloud);
        prism_extract.setViewPoint(viewpoint_[0], viewpoint_[1], viewpoint_[2]);
        prism_extract.setHeightLimits(init_local_position_z_min_, init_local_position_z_max_);
        prism_extract.setInputPlanarHull(boundaries);
        pcl::PointIndices output_indices;
        prism_extract.segment(output_indices);
        for (size_t i = 0; i < output_indices.indices.size(); i++) {
          all_indices.insert(output_indices.indices[i]);
        }
      }
      pcl::ExtractIndices<pcl::PointXYZ> ex;
      ex.setInputCloud(cloud);
      pcl::PointIndices::Ptr indices (new pcl::PointIndices);
      indices->indices = std::vector<int>(all_indices.begin(), all_indices.end());
      ex.setIndices(indices);
      ex.filter(*candidate_cloud_);
      sensor_msgs::PointCloud2 ros_candidate_cloud;
      pcl::toROSMsg(*candidate_cloud_, ros_candidate_cloud);
      ros_candidate_cloud.header = msg->header;
      pub_candidate_cloud_.publish(ros_candidate_cloud);
      // check the number of candidate points
      if (candidate_cloud_->points.size() == 0) {
        JSK_NODELET_ERROR("No candidate cloud");
        return;
      }
      tree_.setInputCloud(candidate_cloud_);
      if (support_plane_updated_) {
        // Compute assignment between particles and polygons
        NODELET_INFO("polygon updated");
        updateParticlePolygonRelationship(tracker_->getParticles());
      }
      ROS_INFO("start tracker_->compute()");
      tracker_->compute();
      ROS_INFO("done tracker_->compute()");
      Particle result = tracker_->getResult();
      jsk_recognition_msgs::BoundingBoxArray box_array;
      box_array.header = msg->header;
      box_array.boxes.push_back(result.toBoundingBox());
      box_array.boxes[0].header = msg->header;
      pub_result_.publish(box_array);
    }
    support_plane_updated_ = false;
    ParticleCloud::Ptr particles = tracker_->getParticles();
    // Publish histograms
    publishHistogram(particles, 0, pub_histogram_global_x_, msg->header);
    publishHistogram(particles, 1, pub_histogram_global_y_, msg->header);
    publishHistogram(particles, 2, pub_histogram_global_z_, msg->header);
    publishHistogram(particles, 3, pub_histogram_global_roll_, msg->header);
    publishHistogram(particles, 4, pub_histogram_global_pitch_, msg->header);
    publishHistogram(particles, 5, pub_histogram_global_yaw_, msg->header);
    publishHistogram(particles, 6, pub_histogram_dx_, msg->header);
    publishHistogram(particles, 7, pub_histogram_dy_, msg->header);
    publishHistogram(particles, 8, pub_histogram_dz_, msg->header);
    // Publish particles
    sensor_msgs::PointCloud2 ros_particles;
    pcl::toROSMsg(*particles, ros_particles);
    ros_particles.header = msg->header;
    pub_particles_.publish(ros_particles);
    }
    catch (tf2::TransformException& e) {
      JSK_ROS_ERROR("tf exception");
    }
  }
  void PointCloudLocalization::cloudCallback(
    const sensor_msgs::PointCloud2::ConstPtr& cloud_msg)
  {
    vital_checker_->poke();
    boost::mutex::scoped_lock lock(mutex_);
    //JSK_NODELET_INFO("cloudCallback");
    latest_cloud_ = cloud_msg;
    if (localize_requested_){
      JSK_NODELET_INFO("localization is requested");
      try {
        pcl::PointCloud<pcl::PointNormal>::Ptr
          local_cloud (new pcl::PointCloud<pcl::PointNormal>);
        pcl::fromROSMsg(*latest_cloud_, *local_cloud);
        JSK_NODELET_INFO("waiting for tf transformation from %s tp %s",
                     latest_cloud_->header.frame_id.c_str(),
                     global_frame_.c_str());
        if (tf_listener_->waitForTransform(
              latest_cloud_->header.frame_id,
              global_frame_,
              latest_cloud_->header.stamp,
              ros::Duration(1.0))) {
          pcl::PointCloud<pcl::PointNormal>::Ptr
            input_cloud (new pcl::PointCloud<pcl::PointNormal>);
          if (use_normal_) {
            pcl_ros::transformPointCloudWithNormals(global_frame_,
                                                    *local_cloud,
                                                    *input_cloud,
                                                    *tf_listener_);
          }
          else {
            pcl_ros::transformPointCloud(global_frame_,
                                         *local_cloud,
                                         *input_cloud,
                                         *tf_listener_);
          }
          pcl::PointCloud<pcl::PointNormal>::Ptr
            input_downsampled_cloud (new pcl::PointCloud<pcl::PointNormal>);
          applyDownsampling(input_cloud, *input_downsampled_cloud);
          if (isFirstTime()) {
            all_cloud_ = input_downsampled_cloud;
            first_time_ = false;
          }
          else {
            // run ICP
            ros::ServiceClient client
              = pnh_->serviceClient<jsk_pcl_ros::ICPAlign>("icp_align");
            jsk_pcl_ros::ICPAlign icp_srv;

            if (clip_unseen_pointcloud_) {
              // Before running ICP, remove pointcloud where we cannot see
              // First, transform reference pointcloud, that is all_cloud_, into
              // sensor frame.
              // And after that, remove points which are x < 0.
              tf::StampedTransform global_sensor_tf_transform
                = lookupTransformWithDuration(
                  tf_listener_,
                  global_frame_,
                  sensor_frame_,
                  cloud_msg->header.stamp,
                  ros::Duration(1.0));
              Eigen::Affine3f global_sensor_transform;
              tf::transformTFToEigen(global_sensor_tf_transform,
                                     global_sensor_transform);
              pcl::PointCloud<pcl::PointNormal>::Ptr sensor_cloud
                (new pcl::PointCloud<pcl::PointNormal>);
              pcl::transformPointCloudWithNormals(
                *all_cloud_,
                *sensor_cloud,
                global_sensor_transform.inverse());
              // Remove negative-x points
              pcl::PassThrough<pcl::PointNormal> pass;
              pass.setInputCloud(sensor_cloud);
              pass.setFilterFieldName("x");
              pass.setFilterLimits(0.0, 100.0);
              pcl::PointCloud<pcl::PointNormal>::Ptr filtered_cloud
                (new pcl::PointCloud<pcl::PointNormal>);
              pass.filter(*filtered_cloud);
              JSK_NODELET_INFO("clipping: %lu -> %lu", sensor_cloud->points.size(), filtered_cloud->points.size());
              // Convert the pointcloud to global frame again
              pcl::PointCloud<pcl::PointNormal>::Ptr global_filtered_cloud
                (new pcl::PointCloud<pcl::PointNormal>);
              pcl::transformPointCloudWithNormals(
                *filtered_cloud,
                *global_filtered_cloud,
                global_sensor_transform);
              pcl::toROSMsg(*global_filtered_cloud,
                            icp_srv.request.target_cloud);
            }
            else {
              pcl::toROSMsg(*all_cloud_,
                            icp_srv.request.target_cloud);
            }
            pcl::toROSMsg(*input_downsampled_cloud,
                          icp_srv.request.reference_cloud);
            
            if (client.call(icp_srv)) {
              Eigen::Affine3f transform;
              tf::poseMsgToEigen(icp_srv.response.result.pose, transform);
              Eigen::Vector3f transform_pos(transform.translation());
              float roll, pitch, yaw;
              pcl::getEulerAngles(transform, roll, pitch, yaw);
              JSK_NODELET_INFO("aligned parameter --");
              JSK_NODELET_INFO("  - pos: [%f, %f, %f]",
                           transform_pos[0],
                           transform_pos[1],
                           transform_pos[2]);
              JSK_NODELET_INFO("  - rot: [%f, %f, %f]", roll, pitch, yaw);
              pcl::PointCloud<pcl::PointNormal>::Ptr
                transformed_input_cloud (new pcl::PointCloud<pcl::PointNormal>);
              if (use_normal_) {
                pcl::transformPointCloudWithNormals(*input_cloud,
                                                    *transformed_input_cloud,
                                                    transform);
              }
              else {
                pcl::transformPointCloud(*input_cloud,
                                         *transformed_input_cloud,
                                         transform);
              }
              pcl::PointCloud<pcl::PointNormal>::Ptr
                concatenated_cloud (new pcl::PointCloud<pcl::PointNormal>);
              *concatenated_cloud = *all_cloud_ + *transformed_input_cloud;
              // update *all_cloud
              applyDownsampling(concatenated_cloud, *all_cloud_);
              // update localize_transform_
              tf::Transform icp_transform;
              tf::transformEigenToTF(transform, icp_transform);
              {
                boost::mutex::scoped_lock tf_lock(tf_mutex_);
                localize_transform_ = localize_transform_ * icp_transform;
              }
            }
            else {
              JSK_NODELET_ERROR("Failed to call ~icp_align");
              return;
            }
          }
          localize_requested_ = false;
        }
        else {
          JSK_NODELET_WARN("No tf transformation is available");
        }
      }
      catch (tf2::ConnectivityException &e)
      {
        JSK_NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
        return;
      }
      catch (tf2::InvalidArgumentException &e)
      {
        JSK_NODELET_ERROR("[%s] Transform error: %s", __PRETTY_FUNCTION__, e.what());
        return;
      }
    }
  }