1 #define PCL_NO_PRECOMPILE 5 #include <pcl/point_types.h> 7 #include <pcl/point_cloud.h> 8 #include <pcl/visualization/pcl_visualizer.h> 9 #include <pcl/common/transforms.h> 10 #include <pcl/filters/passthrough.h> 11 #include <pcl/filters/voxel_grid.h> 12 #include <pcl/io/pcd_io.h> 13 #include <boost/lexical_cast.hpp> 22 geometry_msgs::TransformStamped bt;
23 bt.transform.rotation = msg.pose.orientation;
24 bt.transform.translation.x = msg.pose.position.x;
25 bt.transform.translation.y = msg.pose.position.y;
26 bt.transform.translation.z = msg.pose.position.z;
27 bt.header.stamp = msg.header.stamp;
28 bt.header.frame_id = msg.header.frame_id;
29 bt.child_frame_id =
"camera";
34 inline Eigen::Affine3f
toAffine(
const geometry_msgs::TransformStamped& tf_stamped)
36 const geometry_msgs::Vector3& t = tf_stamped.transform.translation;
37 const geometry_msgs::Quaternion& q = tf_stamped.transform.rotation;
39 Eigen::Affine3f result = Eigen::Affine3f::Identity();
40 result.translation() << t.x, t.y, t.z;
41 Eigen::Quaternionf rot(q.w, q.x, q.y, q.z);
48 void voxelGridFilter(
double size, pointcloud_t::Ptr input, pointcloud_t::Ptr& output)
50 if(size <= 0.0){ output = input; }
53 pcl::VoxelGrid<point_t> vgf;
54 vgf.setInputCloud(input);
55 vgf.setLeafSize(size, size, size);
62 pointcloud_t::Ptr
distanceFiltered(
double min,
double max,
const pointcloud_t::ConstPtr input)
65 if(min >= max){ *output = *input; }
68 pcl::PassThrough<point_t> pass;
69 pass.setInputCloud(input);
70 pass.setFilterFieldName(
"z");
71 pass.setFilterLimits(min, max);
79 double voxelgrid_size_save,
82 std::string output_filename,
85 : tf_buffer_(
ros::Duration(
std::numeric_limits<int>::max(), 0)),
88 voxelgrid_size_display_(voxelgrid_size_display),
89 voxelgrid_size_save_(voxelgrid_size_save),
90 min_distance_(min_distance),
91 max_distance_(max_distance),
92 output_filename_(output_filename),
93 keep_high_res_(keep_high_res),
95 viewer_(
"Roboception Cloud Viewer"),
96 viewer_thread_(
boost::ref(viewer_))
108 static int counter = 0;
110 ROS_INFO_THROTTLE(10,
"Received %d point cloud%s", counter, counter == 1 ?
"" :
"s");
111 double timestamp = pointcloud->header.stamp * 1e-6;
112 ROS_DEBUG(
"Storing cloud (%.3f)", timestamp);
118 if(transformation.matrix()(0,0) == transformation.matrix()(0,0))
120 pointcloud_t::Ptr transformed_cloud(
new pointcloud_t());
121 pcl::transformPointCloud(*cropped_cloud, *transformed_cloud, transformation);
128 ROS_INFO_ONCE(
"Change view to start displaying the clouds.");
132 ROS_INFO_THROTTLE(5,
"Cannot transform current point cloud: No poses were received yet. " 133 "Is Stereo INS or SLAM running?");
136 ROS_INFO_THROTTLE(5,
"Cannot transform current point cloud: Pose not (yet) received\n" 137 "Current cloud stamp: %.3f\n" 145 ROS_INFO(
"Received Trajectory with %zu poses", path->poses.size());
149 for(
size_t i = 0; i < path->poses.size(); ++i)
181 geometry_msgs::TransformStamped pose;
193 Eigen::Affine3f invalid_result;
194 invalid_result.matrix().setConstant(std::numeric_limits<double>::quiet_NaN());
195 return invalid_result;
201 ROS_INFO(
"(Re-)merging all stored clouds with latest poses.");
204 for(
size_t i = 0; i <
clouds_.size(); ++i)
207 double timestamp =
clouds_[i]->header.stamp * 1e-6;
209 if(transformation.matrix()(0,0) == transformation.matrix()(0,0))
213 pcl::transformPointCloud(*
clouds_[i], transformed_cloud, transformation);
214 *merged += transformed_cloud;
215 if(counter % 10 == 0){
ROS_INFO(
"Merged %d of %zu clouds.", counter,
clouds_.size()); }
217 else {
ROS_DEBUG(
"Skipped cloud at %.3f in merge, cannot get its position", timestamp); }
223 return voxel_filtered;
CloudAccumulator(double voxelgrid_size_display, double voxelgrid_size_save, double min_distance, double max_distance, std::string output_filename, bool keep_high_res, bool start_paused)
void trajectoryCallback(const nav_msgs::PathConstPtr &path)
Replace all saved camera poses by those in path.
bool pause_
Whether to ignore input data.
void poseCallback(const geometry_msgs::PoseStampedConstPtr ¤t_pose)
Saves camera pose.
ros::Time last_pose_stamp_
tf2_ros::Buffer tf_buffer_
Stores the history of poses and allows to interpolate.
#define ROS_INFO_ONCE(...)
bool setTransform(const geometry_msgs::TransformStamped &transform, const std::string &authority, bool is_static=false)
void pointCloudCallback(const pointcloud_t::ConstPtr &pointcloud)
For each cloud.
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
double voxelgrid_size_save_
Filter size for the saved cloud.
Eigen::Affine3f toAffine(const geometry_msgs::TransformStamped &tf_stamped)
pointcloud_t::Ptr display_cloud_
Cloud that is displayed.
std::string output_filename_
Where to save the cloud.
std::deque< pointcloud_t::Ptr > clouds_
Storage for later corraection and saving.
double voxelgrid_size_display_
Filter size for the display cloud.
pointcloud_t::Ptr distanceFiltered(double min, double max, const pointcloud_t::ConstPtr input)
Filter cloud along the optical axis (Z) Filter if min < max, otherwise copy (deep, not only the pointer)
double min_distance_
Discard points closer than this.
boost::mutex display_cloud_mutex_
boost::mutex tf_buffer_mutex_
Eigen::Affine3f lookupTransform(double timestamp)
void addCloudToViewer(const pointcloud_t::Ptr pointcloud)
Thread-safe addition/replacement of the cloud.
void updateCloudInViewer(const pointcloud_t::Ptr pointcloud)
Thread-safe update to the cloud.
double max_distance_
Discard points farther than this.
geometry_msgs::TransformStamped myPoseStampedMsgToTF(const geometry_msgs::PoseStamped &msg)
pointcloud_t::Ptr rebuildCloud()
For all saved clouds.
bool saveCloud(std_srvs::Empty::Request &req, std_srvs::Empty::Request &resp)
#define ROS_INFO_THROTTLE(rate,...)
void voxelGridFilter(double size, pointcloud_t::Ptr input, pointcloud_t::Ptr &output)
Filter if size >= 0, otherwise just copy the pointer.
virtual bool canTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &target_time, const ros::Duration timeout, std::string *errstr=NULL) const
size_t num_poses_
Keep track of pose count (to show a good error message)
bool togglePause(std_srvs::Empty::Request &req, std_srvs::Empty::Request &resp)
Toggle whether to ignore incoming data.
pcl::PointCloud< point_t > pointcloud_t
bool keep_high_res_
If false, do not store clouds. On save, save display cloud.