Skip to content

Commit 58b1436

Browse files
authored
Merge pull request #72 from AutoModality/AM-633/culvert_passageway
feat: moved dust filter from am_perception
2 parents 24ee229 + e87956f commit 58b1436

File tree

6 files changed

+351
-0
lines changed

6 files changed

+351
-0
lines changed

CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ find_package(catkin REQUIRED COMPONENTS
1818
std_msgs
1919
tf2
2020
tf2_ros
21+
pcl_conversions
2122
)
2223

2324
find_package(OpenCV REQUIRED)
@@ -44,6 +45,7 @@ catkin_package(
4445
std_msgs
4546
tf2
4647
tf2_ros
48+
pcl_conversions
4749
)
4850

4951
# TODO: why is the explicit eigen3 include
@@ -61,12 +63,14 @@ add_library(am_utils
6163
src/am_utils/am_onlinestatistics.cpp
6264
src/am_utils/am_operator_utils.cpp
6365
src/am_utils/am_statistics.cpp
66+
src/am_utils/dust_filter.cpp
6467
src/am_utils/cansocket.cpp
6568
src/am_utils/fcu_mode_type.cpp
6669
src/am_utils/flightplan_type.cpp
6770
src/am_utils/latency_wrapper.cpp
6871
src/am_utils/message_util.cpp
6972
src/am_utils/mission_cmd_type.cpp
73+
src/am_utils/am_pcl_utils.cpp
7074
src/am_utils/operator_msg_type.cpp
7175
src/vb_util_lib/control_util.cpp
7276
src/vb_util_lib/object_state.cpp

include/am_utils/am_pcl_utils.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#ifndef AM_UTILS_INCLUDE_AM_UTILS_AM_PCL_UTILS_H_
2+
#define AM_UTILS_INCLUDE_AM_UTILS_AM_PCL_UTILS_H_
3+
4+
#include <sensor_msgs/PointCloud2.h>
5+
#include <am_utils/point_types.h>
6+
7+
namespace am
8+
{
9+
10+
class AMPCLUtils
11+
{
12+
13+
public:
14+
static pcl::PointCloud<pcl::PointXYZIR>::ConstPtr convertToPointXYZIR(
15+
const sensor_msgs::PointCloud2::ConstPtr pc2,
16+
pcl::PointCloud<pcl::PointXYZIR>::Ptr &pcl);
17+
};
18+
19+
}
20+
21+
#endif /* AM_UTILS_INCLUDE_AM_UTILS_AM_PCL_UTILS_H_ */

include/am_utils/dust_filter.h

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#ifndef AM_UTILS_INCLUDE_AM_UTILS_DUST_FILTER_H_
2+
#define AM_UTILS_INCLUDE_AM_UTILS_DUST_FILTER_H_
3+
4+
#include <pcl_ros/point_cloud.h>
5+
6+
#include <am_utils/point_types.h>
7+
8+
namespace am
9+
{
10+
11+
class DustFilter
12+
{
13+
private:
14+
15+
ros::NodeHandle nh_;
16+
17+
ros::Publisher debug_pcl_pub_;
18+
19+
float range_threshold_m_;
20+
float max_range_m_;
21+
int min_neighbors_;
22+
std::string name_space_;
23+
24+
float inside_min_x_m_;
25+
float inside_max_x_m_;
26+
float inside_min_y_m_;
27+
float inside_max_y_m_;
28+
float inside_min_z_m_;
29+
float inside_max_z_m_;
30+
float outside_min_x_m_;
31+
float outside_max_x_m_;
32+
float outside_min_y_m_;
33+
float outside_max_y_m_;
34+
float outside_min_z_m_;
35+
float outside_max_z_m_;
36+
37+
bool isSetToNaN(pcl::PointXYZIR &point);
38+
void setNaN(pcl::PointXYZIR &point);
39+
void printInsideParams();
40+
void printOutsideParams();
41+
42+
public:
43+
DustFilter(ros::NodeHandle &nh, std::string name_space);
44+
~DustFilter();
45+
46+
int process(pcl::PointCloud<pcl::PointXYZIR> &pc);
47+
void getParams();
48+
void setInsideFilter(float min_x_m_, float max_x_m_, float min_y_m_, float max_y_m_, float min_z_m_, float max_z_m_);
49+
void setOutsideFilter(float min_x_m_, float max_x_m_, float min_y_m_, float max_y_m_, float min_z_m_, float max_z_m_);
50+
};
51+
52+
}
53+
54+
#endif /* AM_UTILS_INCLUDE_AM_UTILS_DUST_FILTER_H_ */

package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222
<depend>std_msgs</depend>
2323
<depend>tf2</depend>
2424
<depend>tf2_ros</depend>
25+
<depend>pcl_conversions</depend>
2526

2627
</package>

src/am_utils/am_pcl_utils.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include <ros/ros.h>
2+
3+
#include <am_utils/am_pcl_utils.h>
4+
#include <sensor_msgs/point_cloud2_iterator.h>
5+
#include <pcl_conversions/pcl_conversions.h>
6+
7+
namespace am
8+
{
9+
10+
pcl::PointCloud<pcl::PointXYZIR>::ConstPtr AMPCLUtils::convertToPointXYZIR(
11+
const sensor_msgs::PointCloud2::ConstPtr pc2, pcl::PointCloud<pcl::PointXYZIR>::Ptr &pcl)
12+
{
13+
pcl->header = pcl_conversions::toPCL(pc2->header);
14+
pcl->resize(pc2->height * pc2->width);
15+
pcl->height = pc2->height;
16+
pcl->width = pc2->width;
17+
int index = 0;
18+
for (sensor_msgs::PointCloud2ConstIterator<float> it(*pc2, "x"); it != it.end(); ++it) {
19+
float x = it[0];
20+
float y = it[1];
21+
float z = it[2];
22+
float intensity = it[4];
23+
pcl->points[index].x = x;
24+
pcl->points[index].y = y;
25+
pcl->points[index].z = z;
26+
pcl->points[index].intensity = intensity;
27+
pcl->points[index].range = std::sqrt(x * x + y * y + z * z);
28+
index++;
29+
}
30+
31+
return pcl;
32+
}
33+
34+
} // namespace
35+

src/am_utils/dust_filter.cpp

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
#include <ros/ros.h>
2+
3+
#include <pcl_conversions/pcl_conversions.h>
4+
#include <pcl_ros/point_cloud.h>
5+
6+
#include <am_utils/dust_filter.h>
7+
#include <am_utils/point_types.h>
8+
#include <vb_util_lib/frame_names.h>
9+
#include <vb_util_lib/topics.h>
10+
11+
#define DEFAULT_RANGE_THRESHHOLD_M (0.1)
12+
#define DEFAULT_MIN_NEIGHBORS (2)
13+
#define DEFAULT_MAX_RANGE_M (7.5)
14+
15+
namespace am
16+
{
17+
18+
DustFilter::DustFilter(ros::NodeHandle &nh, std::string name_space) : nh_(nh), name_space_(name_space)
19+
{
20+
getParams();
21+
22+
debug_pcl_pub_ = nh_.advertise<pcl::PointCloud<pcl::PointXYZIR>>("/debug/dust_filter/pcl", 10);
23+
}
24+
25+
DustFilter::~DustFilter()
26+
{
27+
}
28+
29+
void DustFilter::getParams()
30+
{
31+
static bool first_run = true;
32+
33+
nh_.param<float>(name_space_ + "/range_threshold_m", range_threshold_m_, DEFAULT_RANGE_THRESHHOLD_M);
34+
nh_.param<int>(name_space_ + "/min_neighbors", min_neighbors_, DEFAULT_MIN_NEIGHBORS);
35+
nh_.param<float>(name_space_ + "/max_range_m", max_range_m_, DEFAULT_MAX_RANGE_M);
36+
nh_.param<float>(name_space_ + "/inside_min_x_m", inside_min_x_m_, 0);
37+
nh_.param<float>(name_space_ + "/inside_max_x_m", inside_max_x_m_, 0);
38+
nh_.param<float>(name_space_ + "/inside_min_y_m", inside_min_y_m_, 0);
39+
nh_.param<float>(name_space_ + "/inside_max_y_m", inside_max_y_m_, 0);
40+
nh_.param<float>(name_space_ + "/inside_min_z_m", inside_min_z_m_, 0);
41+
nh_.param<float>(name_space_ + "/inside_max_z_m", inside_max_z_m_, 0);
42+
nh_.param<float>(name_space_ + "/outside_min_x_m", outside_min_x_m_, std::numeric_limits<double>::min());
43+
nh_.param<float>(name_space_ + "/outside_max_x_m", outside_max_x_m_, std::numeric_limits<double>::max());
44+
nh_.param<float>(name_space_ + "/outside_min_y_m", outside_min_y_m_, std::numeric_limits<double>::min());
45+
nh_.param<float>(name_space_ + "/outside_max_y_m", outside_max_y_m_, std::numeric_limits<double>::max());
46+
nh_.param<float>(name_space_ + "/outside_min_z_m", outside_min_z_m_, std::numeric_limits<double>::min());
47+
nh_.param<float>(name_space_ + "/outside_max_z_m", outside_max_z_m_, std::numeric_limits<double>::max());
48+
49+
50+
if (first_run)
51+
{
52+
first_run = false;
53+
ROS_INFO_STREAM(name_space_ + "/range_threshold_m = " << range_threshold_m_);
54+
ROS_INFO_STREAM(name_space_ + "/neighbors = " << min_neighbors_);
55+
printInsideParams();
56+
printOutsideParams();
57+
}
58+
}
59+
60+
void DustFilter::printInsideParams()
61+
{
62+
ROS_INFO_STREAM(name_space_ + "/inside_max_x_m = " << inside_max_x_m_);
63+
ROS_INFO_STREAM(name_space_ + "/inside_max_x_m = " << inside_max_x_m_);
64+
ROS_INFO_STREAM(name_space_ + "/inside_min_y_m = " << inside_min_y_m_);
65+
ROS_INFO_STREAM(name_space_ + "/inside_max_y_m = " << inside_max_y_m_);
66+
ROS_INFO_STREAM(name_space_ + "/inside_min_z_m = " << inside_min_z_m_);
67+
ROS_INFO_STREAM(name_space_ + "/inside_max_z_m = " << inside_max_z_m_);
68+
}
69+
70+
void DustFilter::printOutsideParams()
71+
{
72+
ROS_INFO_STREAM(name_space_ + "/outside_min_x_m = " << outside_min_x_m_);
73+
ROS_INFO_STREAM(name_space_ + "/outside_max_x_m = " << outside_max_x_m_);
74+
ROS_INFO_STREAM(name_space_ + "/outside_min_y_m = " << outside_min_y_m_);
75+
ROS_INFO_STREAM(name_space_ + "/outside_max_y_m = " << outside_max_y_m_);
76+
ROS_INFO_STREAM(name_space_ + "/outside_min_z_m = " << outside_min_z_m_);
77+
ROS_INFO_STREAM(name_space_ + "/outside_max_z_m = " << outside_max_z_m_);
78+
}
79+
80+
int DustFilter::process(pcl::PointCloud<pcl::PointXYZIR> &pcl)
81+
{
82+
bool nan_mask[pcl.width * pcl.width];
83+
84+
bool is_dense = pcl.is_dense;
85+
for (uint32_t width = 0; width < pcl.width; width++)
86+
{
87+
for (uint32_t height = 0; height < pcl.height; height++)
88+
{
89+
int index = width * pcl.height + height;
90+
pcl::PointXYZIR &point = pcl.points[index];
91+
92+
// if already nan, continue
93+
if(isSetToNaN(point))
94+
{
95+
nan_mask[index] = true;
96+
continue;
97+
}
98+
99+
// if beyond the max range, don't filter dust
100+
bool skip_dust_filter = false;
101+
if(point.range > max_range_m_)
102+
{
103+
skip_dust_filter = true;
104+
}
105+
106+
// filter anything close to the center
107+
if(point.x < inside_max_x_m_ && point.x > inside_min_x_m_ &&
108+
point.y < inside_max_y_m_ && point.y > inside_min_y_m_ &&
109+
point.z < inside_max_z_m_ && point.z > inside_min_z_m_)
110+
{
111+
nan_mask[index] = true;
112+
continue;
113+
}
114+
115+
// filter anything too far away
116+
if(point.x > outside_max_x_m_ || point.x < outside_min_x_m_ ||
117+
point.y > outside_max_y_m_ || point.y < outside_min_y_m_ ||
118+
point.z > outside_max_z_m_ || point.z < outside_min_z_m_)
119+
{
120+
nan_mask[index] = true;
121+
continue;
122+
}
123+
124+
if(!skip_dust_filter)
125+
{
126+
// filter points without neighbors
127+
// width wraps, height doesn't
128+
int neighbor_width_start = width - 1;
129+
neighbor_width_start = neighbor_width_start < 0 ? pcl.width + neighbor_width_start : neighbor_width_start;
130+
int neighbor_width_end = width + 2;
131+
neighbor_width_end = neighbor_width_end > pcl.width - 1 ? neighbor_width_end - pcl.width : neighbor_width_end;
132+
int neighbor_height_start = height == 0 ? height : height - 1;
133+
int neighbor_height_end = height == pcl.height - 1 ? height : height + 1;
134+
int neighbors = 0;
135+
int nw = neighbor_width_start;
136+
while(nw != neighbor_width_end)
137+
{
138+
for(int nh = neighbor_height_start; nh <= neighbor_height_end; nh++)
139+
{
140+
// don't compare to itself
141+
if(nh == height && nw == width)
142+
{
143+
continue;
144+
}
145+
int neighbor_index = nw * pcl.height + nh;
146+
pcl::PointXYZIR &neighbor_point = pcl.points[neighbor_index];
147+
if(std::abs(neighbor_point.range - point.range) < range_threshold_m_)
148+
{
149+
neighbors++;
150+
}
151+
}
152+
nw++;
153+
nw = nw > pcl.width - 1 ? nw - pcl.width : nw;
154+
}
155+
if(neighbors < min_neighbors_)
156+
{
157+
nan_mask[index] = true;
158+
is_dense = false;
159+
}
160+
else
161+
{
162+
nan_mask[index] = false;
163+
}
164+
}
165+
}
166+
167+
}
168+
169+
int points_removed = 0;
170+
for (uint32_t width = 0; width < pcl.width; width++)
171+
{
172+
for (uint32_t height = 0; height < pcl.height; height++)
173+
{
174+
int index = width * pcl.height + height;
175+
pcl::PointXYZIR &point = pcl.points[index];
176+
if(nan_mask[index])
177+
{
178+
setNaN(point);
179+
points_removed++;
180+
is_dense = false;
181+
}
182+
}
183+
}
184+
185+
pcl.is_dense = is_dense;
186+
187+
if (debug_pcl_pub_.getNumSubscribers() > 0)
188+
{
189+
debug_pcl_pub_.publish(pcl);
190+
}
191+
192+
return points_removed;
193+
}
194+
195+
bool DustFilter::isSetToNaN(pcl::PointXYZIR &point)
196+
{
197+
if (std::isnan(point.x) || std::isnan(point.y) || std::isnan(point.z) ||
198+
std::isnan(point.intensity) || std::isnan(point.intensity))
199+
{
200+
setNaN(point);
201+
return true;
202+
}
203+
return false;
204+
}
205+
206+
void DustFilter::setNaN(pcl::PointXYZIR &point)
207+
{
208+
point.x = std::nanf("");
209+
point.y = std::nanf("");
210+
point.z = std::nanf("");
211+
point.intensity = std::nanf("");
212+
point.range = std::nanf("");
213+
}
214+
215+
void DustFilter::setInsideFilter(float min_x_m_, float max_x_m_, float min_y_m_, float max_y_m_, float min_z_m_, float max_z_m_)
216+
{
217+
inside_min_x_m_ = min_x_m_;
218+
inside_max_x_m_ = max_x_m_;
219+
inside_min_y_m_ = min_y_m_;
220+
inside_max_y_m_ = max_y_m_;
221+
inside_min_z_m_ = min_z_m_;
222+
inside_max_z_m_ = max_z_m_;
223+
}
224+
225+
void DustFilter::setOutsideFilter(float min_x_m_, float max_x_m_, float min_y_m_, float max_y_m_, float min_z_m_, float max_z_m_)
226+
{
227+
outside_min_x_m_ = min_x_m_;
228+
outside_max_x_m_ = max_x_m_;
229+
outside_min_y_m_ = min_y_m_;
230+
outside_max_y_m_ = max_y_m_;
231+
outside_min_z_m_ = min_z_m_;
232+
outside_max_z_m_ = max_z_m_;
233+
}
234+
235+
} // namespace
236+

0 commit comments

Comments
 (0)