Skip to content

Commit 113ad51

Browse files
calculate visibility score in ring outlier filter
Signed-off-by: kyoichi-sugahara <kyoichi.sugahara@tier4.jp>
1 parent ea009b8 commit 113ad51

File tree

3 files changed

+150
-33
lines changed

3 files changed

+150
-33
lines changed

sensing/pointcloud_preprocessor/include/pointcloud_preprocessor/outlier_filter/ring_outlier_filter_nodelet.hpp

+23
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,18 @@
1919
#include "pointcloud_preprocessor/filter.hpp"
2020
#include "pointcloud_preprocessor/transform_info.hpp"
2121

22+
#include <image_transport/image_transport.hpp>
2223
#include <point_cloud_msg_wrapper/point_cloud_msg_wrapper.hpp>
2324

25+
#if __has_include(<cv_bridge/cv_bridge.hpp>)
26+
#include <cv_bridge/cv_bridge.hpp>
27+
#else
28+
#include <cv_bridge/cv_bridge.h>
29+
#endif
30+
2431
#include <memory>
32+
#include <string>
33+
#include <unordered_map>
2534
#include <utility>
2635
#include <vector>
2736

@@ -42,6 +51,9 @@ class RingOutlierFilterComponent : public pointcloud_preprocessor::Filter
4251
const PointCloud2ConstPtr & input, const IndicesPtr & indices, PointCloud2 & output,
4352
const TransformInfo & transform_info);
4453

54+
image_transport::Publisher image_pub_;
55+
rclcpp::Publisher<tier4_debug_msgs::msg::Float32Stamped>::SharedPtr visibility_pub_;
56+
4557
private:
4658
/** \brief publisher of excluded pointcloud for debug reason. **/
4759
rclcpp::Publisher<PointCloud2>::SharedPtr outlier_pointcloud_publisher_;
@@ -53,6 +65,16 @@ class RingOutlierFilterComponent : public pointcloud_preprocessor::Filter
5365
size_t max_points_num_per_ring_;
5466
bool publish_outlier_pointcloud_;
5567

68+
// for visibility score
69+
int noise_threshold_;
70+
int vertical_bins_;
71+
int horizontal_bins_;
72+
float max_azimuth_diff_;
73+
74+
float min_azimuth_deg_;
75+
float max_azimuth_deg_;
76+
float max_distance_;
77+
5678
/** \brief Parameter service callback result : needed to be hold */
5779
OnSetParametersCallbackHandle::SharedPtr set_param_res_;
5880

@@ -77,6 +99,7 @@ class RingOutlierFilterComponent : public pointcloud_preprocessor::Filter
7799
void setUpPointCloudFormat(
78100
const PointCloud2ConstPtr & input, PointCloud2 & formatted_points, size_t points_size,
79101
size_t num_fields);
102+
float calculateVisibilityScore(const PointCloud2 & input);
80103

81104
public:
82105
PCL_MAKE_ALIGNED_OPERATOR_NEW

sensing/pointcloud_preprocessor/package.xml

-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
<buildtool_depend>ament_cmake_auto</buildtool_depend>
2323
<buildtool_depend>autoware_cmake</buildtool_depend>
2424

25-
<depend>autoware_auto_geometry</depend>
2625
<depend>autoware_point_types</depend>
2726
<depend>cgal</depend>
2827
<depend>cv_bridge</depend>

sensing/pointcloud_preprocessor/src/outlier_filter/ring_outlier_filter_nodelet.cpp

+127-32
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@
1414

1515
#include "pointcloud_preprocessor/outlier_filter/ring_outlier_filter_nodelet.hpp"
1616

17-
#include "autoware_auto_geometry/common_3d.hpp"
17+
#include "autoware_point_types/types.hpp"
1818

1919
#include <sensor_msgs/point_cloud2_iterator.hpp>
2020

21-
#include <pcl/search/pcl_search.h>
22-
2321
#include <algorithm>
2422
#include <vector>
2523
namespace pointcloud_preprocessor
2624
{
25+
using autoware_point_types::PointXYZIRADRT;
26+
2727
RingOutlierFilterComponent::RingOutlierFilterComponent(const rclcpp::NodeOptions & options)
2828
: Filter("RingOutlierFilter", options)
2929
{
@@ -35,6 +35,10 @@ RingOutlierFilterComponent::RingOutlierFilterComponent(const rclcpp::NodeOptions
3535
debug_publisher_ = std::make_unique<DebugPublisher>(this, "ring_outlier_filter");
3636
outlier_pointcloud_publisher_ =
3737
this->create_publisher<PointCloud2>("debug/ring_outlier_filter", 1);
38+
image_pub_ =
39+
image_transport::create_publisher(this, "ring_outlier_filter/debug/frequency_image");
40+
visibility_pub_ = create_publisher<tier4_debug_msgs::msg::Float32Stamped>(
41+
"ring_outlier_filter/debug/visibility", rclcpp::SensorDataQoS());
3842
stop_watch_ptr_->tic("cyclic_time");
3943
stop_watch_ptr_->tic("processing_time");
4044
}
@@ -50,6 +54,13 @@ RingOutlierFilterComponent::RingOutlierFilterComponent(const rclcpp::NodeOptions
5054
static_cast<size_t>(declare_parameter("max_points_num_per_ring", 4000));
5155
publish_outlier_pointcloud_ =
5256
static_cast<bool>(declare_parameter("publish_outlier_pointcloud", false));
57+
58+
min_azimuth_deg_ = static_cast<float>(declare_parameter("min_azimuth_deg", 0.0));
59+
max_azimuth_deg_ = static_cast<float>(declare_parameter("max_azimuth_deg", 360.0));
60+
max_distance_ = static_cast<float>(declare_parameter("max_distance", 12.0));
61+
vertical_bins_ = static_cast<int>(declare_parameter("vertical_bins", 128));
62+
horizontal_bins_ = static_cast<int>(declare_parameter("horizontal_bins", 36));
63+
noise_threshold_ = static_cast<int>(declare_parameter("noise_threshold", 2));
5364
}
5465

5566
using std::placeholders::_1;
@@ -73,13 +84,7 @@ void RingOutlierFilterComponent::faster_filter(
7384
output.data.resize(output.point_step * input->width);
7485
size_t output_size = 0;
7586

76-
// Set up the noise points cloud, if noise points are to be published.
77-
PointCloud2 outlier_points;
78-
size_t outlier_points_size = 0;
79-
if (publish_outlier_pointcloud_) {
80-
outlier_points.point_step = sizeof(PointXYZI);
81-
outlier_points.data.resize(outlier_points.point_step * input->width);
82-
}
87+
pcl::PointCloud<PointXYZIRADRT>::Ptr outlier_pcl(new pcl::PointCloud<PointXYZIRADRT>);
8388

8489
const auto ring_offset =
8590
input->fields.at(static_cast<size_t>(autoware_point_types::PointIndex::Ring)).offset;
@@ -89,6 +94,10 @@ void RingOutlierFilterComponent::faster_filter(
8994
input->fields.at(static_cast<size_t>(autoware_point_types::PointIndex::Distance)).offset;
9095
const auto intensity_offset =
9196
input->fields.at(static_cast<size_t>(autoware_point_types::PointIndex::Intensity)).offset;
97+
const auto return_type_offset =
98+
input->fields.at(static_cast<size_t>(autoware_point_types::PointIndex::ReturnType)).offset;
99+
const auto time_stamp_offset =
100+
input->fields.at(static_cast<size_t>(autoware_point_types::PointIndex::TimeStamp)).offset;
92101

93102
std::vector<std::vector<size_t>> ring2indices;
94103
ring2indices.reserve(max_rings_num_);
@@ -163,24 +172,32 @@ void RingOutlierFilterComponent::faster_filter(
163172
}
164173
} else if (publish_outlier_pointcloud_) {
165174
for (int i = walk_first_idx; i <= walk_last_idx; i++) {
166-
auto outlier_ptr =
167-
reinterpret_cast<PointXYZI *>(&outlier_points.data[outlier_points_size]);
175+
PointXYZIRADRT outlier_point;
168176
auto input_ptr =
169-
reinterpret_cast<const PointXYZI *>(&input->data[indices[walk_first_idx]]);
177+
reinterpret_cast<const PointXYZIRADRT *>(&input->data[indices[walk_first_idx]]);
170178
if (transform_info.need_transform) {
171179
Eigen::Vector4f p(input_ptr->x, input_ptr->y, input_ptr->z, 1);
172180
p = transform_info.eigen_transform * p;
173-
outlier_ptr->x = p[0];
174-
outlier_ptr->y = p[1];
175-
outlier_ptr->z = p[2];
181+
outlier_point.x = p[0];
182+
outlier_point.y = p[1];
183+
outlier_point.z = p[2];
176184
} else {
177-
*outlier_ptr = *input_ptr;
185+
outlier_point = *input_ptr;
178186
}
179-
const float & intensity = *reinterpret_cast<const float *>(
180-
&input->data[indices[walk_first_idx] + intensity_offset]);
181-
outlier_ptr->intensity = intensity;
182187

183-
outlier_points_size += outlier_points.point_step;
188+
outlier_point.intensity = *reinterpret_cast<const float *>(
189+
&input->data[indices[walk_first_idx] + intensity_offset]);
190+
outlier_point.ring = *reinterpret_cast<const uint16_t *>(
191+
&input->data[indices[walk_first_idx] + ring_offset]);
192+
outlier_point.azimuth = *reinterpret_cast<const float *>(
193+
&input->data[indices[walk_first_idx] + azimuth_offset]);
194+
outlier_point.distance = *reinterpret_cast<const float *>(
195+
&input->data[indices[walk_first_idx] + distance_offset]);
196+
outlier_point.return_type = *reinterpret_cast<const uint8_t *>(
197+
&input->data[indices[walk_first_idx] + return_type_offset]);
198+
outlier_point.time_stamp = *reinterpret_cast<const float *>(
199+
&input->data[indices[walk_first_idx] + time_stamp_offset]);
200+
outlier_pcl->push_back(outlier_point);
184201
}
185202
}
186203

@@ -213,30 +230,47 @@ void RingOutlierFilterComponent::faster_filter(
213230
}
214231
} else if (publish_outlier_pointcloud_) {
215232
for (int i = walk_first_idx; i < walk_last_idx; i++) {
216-
auto outlier_ptr = reinterpret_cast<PointXYZI *>(&outlier_points.data[outlier_points_size]);
217-
auto input_ptr = reinterpret_cast<const PointXYZI *>(&input->data[indices[i]]);
233+
PointXYZIRADRT outlier_point;
234+
235+
auto input_ptr = reinterpret_cast<const PointXYZIRADRT *>(&input->data[indices[i]]);
218236
if (transform_info.need_transform) {
219237
Eigen::Vector4f p(input_ptr->x, input_ptr->y, input_ptr->z, 1);
220238
p = transform_info.eigen_transform * p;
221-
outlier_ptr->x = p[0];
222-
outlier_ptr->y = p[1];
223-
outlier_ptr->z = p[2];
239+
outlier_point.x = p[0];
240+
outlier_point.y = p[1];
241+
outlier_point.z = p[2];
224242
} else {
225-
*outlier_ptr = *input_ptr;
243+
outlier_point = *input_ptr;
226244
}
227-
const float & intensity =
245+
outlier_point.intensity =
228246
*reinterpret_cast<const float *>(&input->data[indices[i] + intensity_offset]);
229-
outlier_ptr->intensity = intensity;
230-
outlier_points_size += outlier_points.point_step;
247+
outlier_point.ring =
248+
*reinterpret_cast<const uint16_t *>(&input->data[indices[i] + ring_offset]);
249+
outlier_point.azimuth =
250+
*reinterpret_cast<const float *>(&input->data[indices[i] + azimuth_offset]);
251+
outlier_point.distance =
252+
*reinterpret_cast<const float *>(&input->data[indices[i] + distance_offset]);
253+
outlier_point.return_type =
254+
*reinterpret_cast<const uint8_t *>(&input->data[indices[i] + return_type_offset]);
255+
outlier_point.time_stamp =
256+
*reinterpret_cast<const float *>(&input->data[indices[i] + time_stamp_offset]);
257+
outlier_pcl->push_back(outlier_point);
231258
}
232259
}
233260
}
234261

235262
setUpPointCloudFormat(input, output, output_size, /*num_fields=*/4);
236263

237264
if (publish_outlier_pointcloud_) {
238-
setUpPointCloudFormat(input, outlier_points, outlier_points_size, /*num_fields=*/4);
239-
outlier_pointcloud_publisher_->publish(outlier_points);
265+
PointCloud2 outlier;
266+
pcl::toROSMsg(*outlier_pcl, outlier);
267+
outlier.header = input->header;
268+
outlier_pointcloud_publisher_->publish(outlier);
269+
270+
tier4_debug_msgs::msg::Float32Stamped visibility_msg;
271+
visibility_msg.data = calculateVisibilityScore(outlier);
272+
visibility_msg.stamp = input->header.stamp;
273+
visibility_pub_->publish(visibility_msg);
240274
}
241275

242276
// add processing time for debug
@@ -288,6 +322,12 @@ rcl_interfaces::msg::SetParametersResult RingOutlierFilterComponent::paramCallba
288322
RCLCPP_DEBUG(
289323
get_logger(), "Setting new publish_outlier_pointcloud to: %d.", publish_outlier_pointcloud_);
290324
}
325+
if (get_param(p, "vertical_bins", vertical_bins_)) {
326+
RCLCPP_DEBUG(get_logger(), "Setting new vertical_bins to: %d.", vertical_bins_);
327+
}
328+
if (get_param(p, "max_azimuth_diff", max_azimuth_diff_)) {
329+
RCLCPP_DEBUG(get_logger(), "Setting new max_azimuth_diff to: %f.", max_azimuth_diff_);
330+
}
291331

292332
rcl_interfaces::msg::SetParametersResult result;
293333
result.successful = true;
@@ -319,6 +359,61 @@ void RingOutlierFilterComponent::setUpPointCloudFormat(
319359
"intensity", 1, sensor_msgs::msg::PointField::FLOAT32);
320360
}
321361

362+
float RingOutlierFilterComponent::calculateVisibilityScore(
363+
const sensor_msgs::msg::PointCloud2 & input)
364+
{
365+
pcl::PointCloud<PointXYZIRADRT>::Ptr input_cloud(new pcl::PointCloud<PointXYZIRADRT>);
366+
pcl::fromROSMsg(input, *input_cloud);
367+
368+
const uint32_t vertical_bins = vertical_bins_;
369+
const uint32_t horizontal_bins = horizontal_bins_;
370+
const float max_azimuth = max_azimuth_deg_ * 100.0;
371+
const float min_azimuth = min_azimuth_deg_ * 100.0;
372+
373+
const uint32_t horizontal_resolution =
374+
static_cast<uint32_t>((max_azimuth - min_azimuth) / horizontal_bins);
375+
376+
std::vector<pcl::PointCloud<PointXYZIRADRT>> ring_point_clouds(vertical_bins);
377+
cv::Mat frequency_image(cv::Size(horizontal_bins, vertical_bins), CV_8UC1, cv::Scalar(0));
378+
379+
// Split points into rings
380+
for (const auto & point : input_cloud->points) {
381+
ring_point_clouds.at(point.ring).push_back(point);
382+
}
383+
384+
// Calculate frequency for each bin in each ring
385+
for (const auto & ring_points : ring_point_clouds) {
386+
if (ring_points.empty()) continue;
387+
388+
const uint ring_id = ring_points.front().ring;
389+
std::vector<int> frequency_in_ring(horizontal_bins, 0);
390+
391+
for (const auto & point : ring_points.points) {
392+
if (point.azimuth < min_azimuth || point.azimuth >= max_azimuth) continue;
393+
if (point.distance >= max_distance_) continue;
394+
395+
const uint bin_index =
396+
static_cast<uint>((point.azimuth - min_azimuth) / horizontal_resolution);
397+
398+
frequency_in_ring[bin_index]++;
399+
frequency_in_ring[bin_index] =
400+
std::min(frequency_in_ring[bin_index], 255); // Ensure value is within uchar range
401+
402+
frequency_image.at<uchar>(ring_id, bin_index) =
403+
static_cast<uchar>(frequency_in_ring[bin_index]);
404+
}
405+
}
406+
407+
cv::Mat binary_image;
408+
cv::inRange(frequency_image, noise_threshold_, 255, binary_image);
409+
410+
const int num_pixels = cv::countNonZero(frequency_image);
411+
const float num_filled_pixels =
412+
static_cast<float>(num_pixels) / static_cast<float>(vertical_bins * horizontal_bins);
413+
414+
return 1.0f - num_filled_pixels;
415+
}
416+
322417
} // namespace pointcloud_preprocessor
323418

324419
#include <rclcpp_components/register_node_macro.hpp>

0 commit comments

Comments
 (0)