pcdfilter_pa_ros.cpp
Go to the documentation of this file.
1 /******************************************************************************
2 * *
3 * pcdfilter_pa_ros.cpp *
4 * ==================== *
5 * *
6 *******************************************************************************
7 * *
8 * github repository *
9 * https://github.com/TUC-ProAut/ros_pcdfilter *
10 * *
11 * Chair of Automation Technology, Technische Universität Chemnitz *
12 * https://www.tu-chemnitz.de/etit/proaut *
13 * *
14 *******************************************************************************
15 * *
16 * New BSD License *
17 * *
18 * Copyright (c) 2015-2018, Peter Weissig, Technische Universität Chemnitz *
19 * All rights reserved. *
20 * *
21 * Redistribution and use in source and binary forms, with or without *
22 * modification, are permitted provided that the following conditions are met: *
23 * * Redistributions of source code must retain the above copyright *
24 * notice, this list of conditions and the following disclaimer. *
25 * * Redistributions in binary form must reproduce the above copyright *
26 * notice, this list of conditions and the following disclaimer in the *
27 * documentation and/or other materials provided with the distribution. *
28 * * Neither the name of the Technische Universität Chemnitz nor the *
29 * names of its contributors may be used to endorse or promote products *
30 * derived from this software without specific prior written permission. *
31 * *
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" *
33 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE *
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE *
35 * ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY *
36 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES *
37 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR *
38 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER *
39 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT *
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY *
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH *
42 * DAMAGE. *
43 * *
44 ******************************************************************************/
45 
46 // local headers
48 
49 // ros headers
52 
53 //**************************[cPcdFilterPaRos]**********************************
55 }
56 
57 //**************************[~cPcdFilterPaRos]*********************************
59 }
60 
61 //**************************[convertCloud]*************************************
62 sensor_msgs::PointCloud2Ptr cPcdFilterPaRos::convertCloud (
63  const sensor_msgs::PointCloudConstPtr &msg) const {
64 
65  sensor_msgs::PointCloud2Ptr result(new sensor_msgs::PointCloud2);
67 
68  return result;
69 }
70 
71 //**************************[convertCloud]*************************************
72 sensor_msgs::PointCloud2Ptr cPcdFilterPaRos::convertCloud(
73  const sensor_msgs::LaserScanConstPtr &msg) const {
74 
76 
77  sensor_msgs::PointCloud2Ptr result (new sensor_msgs::PointCloud2);
78 
80  projector.projectLaser(*msg, *result, -1,
82  } else {
83  sensor_msgs::LaserScan msg_changed(*msg);
84 
85  for (int i = 0; i < msg_changed.ranges.size(); i++) {
86  if (std::isnan(msg_changed.ranges[i])) {
87  msg_changed.ranges[i] =
89  }
90  }
91 
92  projector.projectLaser(msg_changed, *result, -1,
94  }
95 
96  return result;
97 }
98 
99 //**************************[updateTf]*****************************************
101  const std::string base_frame, const ros::Time time) {
102 
103  bool result = filters_.update(tf_listener, base_frame, time,
104  params_.filters_);
105 
106  if (rosparams_.debugging_) {
107  for (int i = 0; i < params_.filters_.size(); i++) {
108  ROS_INFO("%s: updated filter[%d] (%s)",
109  ros::this_node::getName().data(), i,
110  params_.filters_[i].toString().data());
111  }
112  }
113 
114  return result;
115 }
116 
117 //**************************[updateTf]*****************************************
119  const tf::TransformListener &tf_listener) {
120 
121  if (pcd_buffered_msg_.use_count() < 1) {
122  params_.filters_.clear();
123  return false;
124  }
125  return updateTf(tf_listener, pcd_buffered_msg_->header.frame_id,
126  pcd_buffered_msg_->header.stamp);
127 }
128 
129 //**************************[filterCloud]**************************************
130 bool cPcdFilterPaRos::filterCloud(const sensor_msgs::PointCloud2ConstPtr &msg,
131  sensor_msgs::PointCloud2Ptr &result) {
132 
133  pcd_buffered_msg_ = msg;
134 
135  // convert pointcloud to opencv
137 
138  if (pcd_buffered_points_.rows == 0) {
139  ROS_WARN("%s: size of pointcloud after conversion to opencv is 0",
140  ros::this_node::getName().data());
141 
142  pcd_buffered_points_.release();
143  pcd_buffered_msg_.reset();
144  return false;
145  }
146 
147  // filter pointcloud
148  bool result_bool = filterCloud(result);
149 
151  pcd_buffered_points_.release();
152  pcd_buffered_msg_.reset();
153  }
154  return result_bool;
155 }
156 
157 //**************************[filterCloud]**************************************
158 bool cPcdFilterPaRos::filterCloud(sensor_msgs::PointCloud2Ptr &result) {
159 
160  if ((pcd_buffered_msg_.use_count() < 1) ||
161  (pcd_buffered_points_.empty())) {
162  return false;
163  }
164 
165  std::vector<bool> mask;
166  std::vector<int> count;
167 
168 
169  // filter pointcloud
170  count = pointcloudFilter(pcd_buffered_points_, mask);
171 
172  // apply mask
173  result = applyMasktoCloud(pcd_buffered_msg_, mask);
174 
175  if (rosparams_.debugging_) {
176  std::stringstream ss;
177  ss << "remaining points " << result->height << " (" <<
179  for (int i = 0; i < count.size(); i++) {
180  ss << " - " << count[i];
181  }
182  ss << ")";
183  ROS_INFO("%s: %s", ros::this_node::getName().data(), ss.str().data());
184  }
185 
186  return true;
187 }
188 
189 //**************************[convertCloudToOpencv]*****************************
191  const sensor_msgs::PointCloud2ConstPtr &msg,
192  const bool force_copy) const {
193 
194  // number of points
195  int count = msg->height * msg->width;
196  int point_step = msg->point_step;
197 
198  // copy info about the resulting columns (x,y,z, dummy)
199  int types[4] = {-1, -1, -1, -1};
200  int offsets[4] = {0, 0, 0, 0};
201  for (int i = 0; i < msg->fields.size(); i++) {
202  int position = 3;
203  if ((msg->fields[i].name == "x") || (msg->fields[i].name == "X")) {
204  position = 0;
205  }
206  if ((msg->fields[i].name == "y") || (msg->fields[i].name == "Y")) {
207  position = 1;
208  }
209  if ((msg->fields[i].name == "z") || (msg->fields[i].name == "Z")) {
210  position = 2;
211  }
212 
213  types[position] = msg->fields[i].datatype;
214  offsets[position] = msg->fields[i].offset ;
215  }
216  // check if all resulting columns (x,y,z) exist
217  for (int i = 0; i < 3; i++) {
218  if (types[i] < 0) {
219  return cv::Mat();
220  }
221  }
222 
223  // check if simple reassignment of data is possible (instead of copying)
224  bool simple_assign = true;
225  for (int i = 0; i < 3; i++) {
226  if ((types[0] != types[i]) || (offsets[i] != i * offsets[1])) {
227  simple_assign = false;
228  break;
229  }
230  }
231  if (simple_assign) {
232  if ((types[0] == sensor_msgs::PointField::FLOAT32) &&
233  (offsets[1] == 4)) {
234  cv::Mat result(count, 3, CV_32FC1,
235  const_cast<uint8_t*> (&(msg->data.front())), point_step);
236  if (force_copy) {
237  if (rosparams_.debugging_) {
238  ROS_INFO("%s: opencv - simple copy of pointcloud)",
239  ros::this_node::getName().data());
240  }
241  cv::Mat result_copy;
242  result.copyTo(result_copy);
243  return result_copy;
244  } else {
245  if (rosparams_.debugging_) {
246  ROS_INFO("%s: opencv - reassignment of pointcloud)",
247  ros::this_node::getName().data());
248  }
249  return result;
250  }
251  }
252  if ((types[0] == sensor_msgs::PointField::FLOAT64) &&
253  (offsets[1] == 8)) {
254  if (rosparams_.debugging_) {
255  ROS_INFO("%s: opencv - reassignment of pointcloud"
256  " + conversion", ros::this_node::getName().data());
257  }
258  cv::Mat result;
259  cv::Mat (count, 3, CV_64FC1,
260  const_cast<uint8_t*> (&(msg->data.front())),
261  point_step).convertTo(result, CV_32FC1);
262  return result;
263  }
264  }
265 
266  // copy data (and maybe change data_type)
267  if (rosparams_.debugging_) {
268  ROS_INFO("%s: opencv - complex copy of pointcloud",
269  ros::this_node::getName().data());
270  }
271  cv::Mat result(count, 3, CV_32FC1);
272  int current_pos = 0;
273  for (int i = 0; i < count; i++) {
274 
275  for (int j = 0; j < 3; j++) {
276  const void *ptr = &(msg->data[current_pos + offsets[j]]);
277  double value = -1;
278  switch (types[j]) {
279  case sensor_msgs::PointField::FLOAT64:
280  value = float(*((const double* ) ptr));
281  break;
282  case sensor_msgs::PointField::FLOAT32:
283  value = *((const float* ) ptr) ;
284  break;
285  case sensor_msgs::PointField::INT32:
286  value = float(*((const int32_t* ) ptr));
287  break;
288  case sensor_msgs::PointField::UINT32:
289  value = float(*((const uint32_t*) ptr));
290  break;
291  case sensor_msgs::PointField::INT16:
292  value = float(*((const int16_t* ) ptr));
293  break;
294  case sensor_msgs::PointField::UINT16:
295  value = float(*((const uint16_t*) ptr));
296  break;
297  case sensor_msgs::PointField::INT8:
298  value = float(*((const int8_t* ) ptr));
299  break;
300  case sensor_msgs::PointField::UINT8:
301  value = float(*((const uint8_t* ) ptr));
302  break;
303  }
304  result.at<double>(i,j) = value;
305  }
306  current_pos+= point_step;
307  }
308 
309  return result;
310 }
311 
312 //**************************[applyMasktoCloud]*********************************
313 sensor_msgs::PointCloud2Ptr cPcdFilterPaRos::applyMasktoCloud(
314  const sensor_msgs::PointCloud2ConstPtr cloud,
315  const std::vector<bool> mask) const {
316 
317  int point_step = cloud->point_step;
318 
319  int size_old = cloud->height * cloud->width;
320  if ((size_old == 0) && (point_step > 0)) {
321  size_old = cloud->data.size() / point_step;
322  }
323 
324  int size_new = mask.size() <= size_old ? mask.size() : size_old;
325  int count = 0;
326  for (int i = 0; i < size_new; i++) {
327  if (mask[i]) {count++;}
328  }
329  size_new = count;
330 
331 
332  sensor_msgs::PointCloud2Ptr result (new sensor_msgs::PointCloud2);
333  result->header.frame_id = cloud->header.frame_id;
334  result->header.stamp = cloud->header.stamp;
335  result->is_bigendian = cloud->is_bigendian;
336  result->is_dense = cloud->is_dense;
337  result->height = size_new;
338  result->width = 1;
339  result->point_step = cloud->point_step;
340  result->row_step = cloud->point_step;
341 
342  result->fields = cloud->fields;
343  result->data.resize(size_new * point_step);
344 
345  uint8_t *pos_new = &result->data[0];
346  const uint8_t *pos_old_base = &cloud->data[0];
347  for (int i = 0; i < size_old; i++) {
348  if (mask[i]) {
349  memcpy(pos_new, pos_old_base + i*point_step, point_step);
350  pos_new+= point_step;
351  }
352  }
353 
354  return result;
355 }
void projectLaser(const sensor_msgs::LaserScan &scan_in, sensor_msgs::PointCloud &cloud_out, double range_cutoff=-1.0, int channel_options=channel_option::Default)
std::vector< cPcdFilterPaFilter > filters_
internal filters for pointcloud
std::vector< int > pointcloudFilter(const cv::Mat &pointcloud, std::vector< bool > &mask) const
cv::Mat pcd_buffered_points_
ROSCPP_DECL const std::string & getName()
#define ROS_WARN(...)
cPcdFilterPaRosParameter rosparams_
ros specific parameter
bool debugging_
flag for extended output
bool updateTf(const tf::TransformListener &tf_listener, const std::string base_frame, const ros::Time time=ros::Time::now())
#define ROS_INFO(...)
sensor_msgs::PointCloud2Ptr convertCloud(const sensor_msgs::PointCloudConstPtr &msg) const
converts the given pointcloud to newer format
cPcdFilterPaRosFilters filters_
object for filter handling
const cv::Mat convertCloudToOpencv(const sensor_msgs::PointCloud2ConstPtr &msg, const bool force_copy=false) const
sensor_msgs::PointCloud2ConstPtr pcd_buffered_msg_
bool filterCloud(const sensor_msgs::PointCloud2ConstPtr &msg, sensor_msgs::PointCloud2Ptr &result)
filters the given pointcloud
static bool convertPointCloudToPointCloud2(const sensor_msgs::PointCloud &input, sensor_msgs::PointCloud2 &output)
bool update(const tf::TransformListener &tf_listener, const std::string base_frame, const ros::Time time, std::vector< cPcdFilterPaFilter > &result) const
~cPcdFilterPaRos()
default destructor
cPcdFilterPaRos()
default constructor
cPcdFilterPaParameter params_
specific parameter
Definition: pcdfilter_pa.h:78
sensor_msgs::PointCloud2Ptr applyMasktoCloud(const sensor_msgs::PointCloud2ConstPtr cloud, const std::vector< bool > mask) const


pcdfilter_pa
Author(s):
autogenerated on Fri Jun 7 2019 21:53:31