Skip to content

Commit 4388a51

Browse files
authored
feat(object_lanelet_filter, vector_map_inside_area_filter): cherry-pick unknown removal feature from awf (#1327)
* feat: add utils to handle z height filter Signed-off-by: yoshiri <yoshiyoshidetteiu@gmail.com> * feat: add test to utilities and fix code Signed-off-by: yoshiri <yoshiyoshidetteiu@gmail.com> * feat: add node param to filter by z Signed-off-by: yoshiri <yoshiyoshidetteiu@gmail.com> * feat: cherry-pick lanelet filter update Signed-off-by: yoshiri <yoshiyoshidetteiu@gmail.com> --------- Signed-off-by: yoshiri <yoshiyoshidetteiu@gmail.com>
1 parent a358cd2 commit 4388a51

16 files changed

+444
-51
lines changed

perception/detected_object_validation/config/object_lanelet_filter.param.yaml

+10
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,13 @@
99
MOTORCYCLE : false
1010
BICYCLE : false
1111
PEDESTRIAN : false
12+
13+
filter_settings:
14+
# polygon overlap based filter
15+
polygon_overlap_filter:
16+
enabled: true
17+
# velocity direction based filter
18+
lanelet_direction_filter:
19+
enabled: false
20+
velocity_yaw_threshold: 0.785398 # [rad] (45 deg)
21+
object_speed_threshold: 3.0 # [m/s]

perception/detected_object_validation/config/obstacle_pointcloud_based_validator.param.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@
1313
[800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0, 800.0]
1414

1515
using_2d_validator: false
16+
enable_debugger: false
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/**:
2+
ros__parameters:
3+
enable_debug: false

perception/detected_object_validation/include/detected_object_validation/detected_object_filter/object_lanelet_filter.hpp

+24-1
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717

1818
#include "detected_object_validation/utils/utils.hpp"
1919

20+
#include <lanelet2_extension/utility/utilities.hpp>
2021
#include <rclcpp/rclcpp.hpp>
2122
#include <tier4_autoware_utils/geometry/geometry.hpp>
23+
#include <tier4_autoware_utils/ros/debug_publisher.hpp>
2224

2325
#include <autoware_auto_mapping_msgs/msg/had_map_bin.hpp>
2426
#include <autoware_auto_perception_msgs/msg/detected_objects.hpp>
@@ -27,6 +29,7 @@
2729
#include <tf2_ros/buffer.h>
2830
#include <tf2_ros/transform_listener.h>
2931

32+
#include <memory>
3033
#include <string>
3134

3235
namespace object_lanelet_filter
@@ -48,6 +51,7 @@ class ObjectLaneletFilterNode : public rclcpp::Node
4851
rclcpp::Publisher<autoware_auto_perception_msgs::msg::DetectedObjects>::SharedPtr object_pub_;
4952
rclcpp::Subscription<autoware_auto_mapping_msgs::msg::HADMapBin>::SharedPtr map_sub_;
5053
rclcpp::Subscription<autoware_auto_perception_msgs::msg::DetectedObjects>::SharedPtr object_sub_;
54+
std::unique_ptr<tier4_autoware_utils::DebugPublisher> debug_publisher_{nullptr};
5155

5256
lanelet::LaneletMapPtr lanelet_map_ptr_;
5357
lanelet::ConstLanelets road_lanelets_;
@@ -58,11 +62,30 @@ class ObjectLaneletFilterNode : public rclcpp::Node
5862
tf2_ros::TransformListener tf_listener_;
5963

6064
utils::FilterTargetLabel filter_target_;
61-
65+
struct FilterSettings
66+
{
67+
bool polygon_overlap_filter;
68+
bool lanelet_direction_filter;
69+
double lanelet_direction_filter_velocity_yaw_threshold;
70+
double lanelet_direction_filter_object_speed_threshold;
71+
} filter_settings_;
72+
73+
bool filterObject(
74+
const autoware_auto_perception_msgs::msg::DetectedObject & transformed_object,
75+
const autoware_auto_perception_msgs::msg::DetectedObject & input_object,
76+
const lanelet::ConstLanelets & intersected_road_lanelets,
77+
const lanelet::ConstLanelets & intersected_shoulder_lanelets,
78+
autoware_auto_perception_msgs::msg::DetectedObjects & output_object_msg);
6279
LinearRing2d getConvexHull(const autoware_auto_perception_msgs::msg::DetectedObjects &);
6380
lanelet::ConstLanelets getIntersectedLanelets(
6481
const LinearRing2d &, const lanelet::ConstLanelets &);
82+
bool isObjectOverlapLanelets(
83+
const autoware_auto_perception_msgs::msg::DetectedObject & object,
84+
const lanelet::ConstLanelets & intersected_lanelets);
6585
bool isPolygonOverlapLanelets(const Polygon2d &, const lanelet::ConstLanelets &);
86+
bool isSameDirectionWithLanelets(
87+
const lanelet::ConstLanelets & lanelets,
88+
const autoware_auto_perception_msgs::msg::DetectedObject & object);
6689
geometry_msgs::msg::Polygon setFootprint(
6790
const autoware_auto_perception_msgs::msg::DetectedObject &);
6891
};

perception/detected_object_validation/include/detected_object_validation/detected_object_filter/object_position_filter.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <tf2_ros/buffer.h>
2727
#include <tf2_ros/transform_listener.h>
2828

29+
#include <memory>
2930
#include <string>
3031

3132
namespace object_position_filter

perception/detected_object_validation/launch/obstacle_pointcloud_based_validator.launch.xml

-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
<remap from="~/input/detected_objects" to="$(var input/detected_objects)"/>
1010
<remap from="~/input/obstacle_pointcloud" to="$(var input/obstacle_pointcloud)"/>
1111
<remap from="~/output/objects" to="$(var output/objects)"/>
12-
<param name="enable_debugger" value="false"/>
1312
<param from="$(var obstacle_pointcloud_based_validator_param_path)"/>
1413
</node>
1514
</launch>

perception/detected_object_validation/launch/occupancy_grid_based_validator.launch.xml

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
<arg name="input/occupancy_grid_map" default="/perception/object_recognition/detection/validation/occupancy_grid_based/single_frame_occupancy_grid_map"/>
88
<arg name="occupancy_grid_map_param_path" default="$(find-pkg-share probabilistic_occupancy_grid_map)/config/laserscan_based_occupancy_grid_map.param.yaml"/>
99
<arg name="occupancy_grid_map_updater_param_path" default="$(find-pkg-share probabilistic_occupancy_grid_map)/config/binary_bayes_filter_updater.param.yaml"/>
10+
<arg name="occupancy_grid_based_validator_param_path" default="$(find-pkg-share detected_object_validation)/config/occupancy_grid_based_validator_param_path.param.yaml"/>
1011

1112
<node pkg="probabilistic_occupancy_grid_map" exec="laserscan_based_occupancy_grid_map_node" name="single_frame_laserscan_occupancy_grid_map" output="screen">
1213
<remap from="~/input/laserscan" to="$(var input/laserscan)"/>
@@ -22,6 +23,6 @@
2223
<remap from="~/input/detected_objects" to="$(var input/detected_objects)"/>
2324
<remap from="~/input/occupancy_grid_map" to="$(var input/occupancy_grid_map)"/>
2425
<remap from="~/output/objects" to="$(var output/objects)"/>
25-
<param name="enable_debug" value="false"/>
26+
<param from="$(var occupancy_grid_based_validator_param_path)"/>
2627
</node>
2728
</launch>

perception/detected_object_validation/package.xml

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
<description>The ROS 2 detected_object_validation package</description>
77
<maintainer email="yukihiro.saito@tier4.jp">Yukihiro Saito</maintainer>
88
<maintainer email="shunsuke.miura@tier4.jp">Shunsuke Miura</maintainer>
9-
<maintainer email="dai.nguyen@tier4.jp">badai nguyen</maintainer>
9+
<maintainer email="dai.nguyen@tier4.jp">Dai Nguyen</maintainer>
10+
<maintainer email="shintaro.tomie@tier4.jp">Shintaro Tomie</maintainer>
11+
<maintainer email="yoshi.ri@tier4.jp">Yoshi RI</maintainer>
1012
<license>Apache License 2.0</license>
1113

1214
<buildtool_depend>ament_cmake_auto</buildtool_depend>

perception/detected_object_validation/src/object_lanelet_filter.cpp

+138-21
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ ObjectLaneletFilterNode::ObjectLaneletFilterNode(const rclcpp::NodeOptions & nod
4343
filter_target_.MOTORCYCLE = declare_parameter<bool>("filter_target_label.MOTORCYCLE", false);
4444
filter_target_.BICYCLE = declare_parameter<bool>("filter_target_label.BICYCLE", false);
4545
filter_target_.PEDESTRIAN = declare_parameter<bool>("filter_target_label.PEDESTRIAN", false);
46+
// Set filter settings
47+
filter_settings_.polygon_overlap_filter =
48+
declare_parameter<bool>("filter_settings.polygon_overlap_filter.enabled");
49+
filter_settings_.lanelet_direction_filter =
50+
declare_parameter<bool>("filter_settings.lanelet_direction_filter.enabled");
51+
filter_settings_.lanelet_direction_filter_velocity_yaw_threshold =
52+
declare_parameter<double>("filter_settings.lanelet_direction_filter.velocity_yaw_threshold");
53+
filter_settings_.lanelet_direction_filter_object_speed_threshold =
54+
declare_parameter<double>("filter_settings.lanelet_direction_filter.object_speed_threshold");
4655

4756
// Set publisher/subscriber
4857
map_sub_ = this->create_subscription<autoware_auto_mapping_msgs::msg::HADMapBin>(
@@ -52,6 +61,9 @@ ObjectLaneletFilterNode::ObjectLaneletFilterNode(const rclcpp::NodeOptions & nod
5261
"input/object", rclcpp::QoS{1}, std::bind(&ObjectLaneletFilterNode::objectCallback, this, _1));
5362
object_pub_ = this->create_publisher<autoware_auto_perception_msgs::msg::DetectedObjects>(
5463
"output/object", rclcpp::QoS{1});
64+
65+
debug_publisher_ =
66+
std::make_unique<tier4_autoware_utils::DebugPublisher>(this, "object_lanelet_filter");
5567
}
5668

5769
void ObjectLaneletFilterNode::mapCallback(
@@ -93,29 +105,65 @@ void ObjectLaneletFilterNode::objectCallback(
93105
lanelet::ConstLanelets intersected_shoulder_lanelets =
94106
getIntersectedLanelets(convex_hull, shoulder_lanelets_);
95107

96-
int index = 0;
97-
for (const auto & object : transformed_objects.objects) {
98-
const auto footprint = setFootprint(object);
99-
const auto & label = object.classification.front().label;
100-
if (filter_target_.isTarget(label)) {
101-
Polygon2d polygon;
102-
for (const auto & point : footprint.points) {
103-
const geometry_msgs::msg::Point32 point_transformed =
104-
tier4_autoware_utils::transformPoint(point, object.kinematics.pose_with_covariance.pose);
105-
polygon.outer().emplace_back(point_transformed.x, point_transformed.y);
106-
}
107-
polygon.outer().push_back(polygon.outer().front());
108-
if (isPolygonOverlapLanelets(polygon, intersected_road_lanelets)) {
109-
output_object_msg.objects.emplace_back(input_msg->objects.at(index));
110-
} else if (isPolygonOverlapLanelets(polygon, intersected_shoulder_lanelets)) {
111-
output_object_msg.objects.emplace_back(input_msg->objects.at(index));
112-
}
113-
} else {
114-
output_object_msg.objects.emplace_back(input_msg->objects.at(index));
115-
}
116-
++index;
108+
// filtering process
109+
for (size_t index = 0; index < transformed_objects.objects.size(); ++index) {
110+
const auto & transformed_object = transformed_objects.objects.at(index);
111+
const auto & input_object = input_msg->objects.at(index);
112+
filterObject(
113+
transformed_object, input_object, intersected_road_lanelets, intersected_shoulder_lanelets,
114+
output_object_msg);
117115
}
118116
object_pub_->publish(output_object_msg);
117+
118+
// Publish debug info
119+
const double pipeline_latency =
120+
std::chrono::duration<double, std::milli>(
121+
std::chrono::nanoseconds(
122+
(this->get_clock()->now() - output_object_msg.header.stamp).nanoseconds()))
123+
.count();
124+
debug_publisher_->publish<tier4_debug_msgs::msg::Float64Stamped>(
125+
"debug/pipeline_latency_ms", pipeline_latency);
126+
}
127+
128+
bool ObjectLaneletFilterNode::filterObject(
129+
const autoware_auto_perception_msgs::msg::DetectedObject & transformed_object,
130+
const autoware_auto_perception_msgs::msg::DetectedObject & input_object,
131+
const lanelet::ConstLanelets & intersected_road_lanelets,
132+
const lanelet::ConstLanelets & intersected_shoulder_lanelets,
133+
autoware_auto_perception_msgs::msg::DetectedObjects & output_object_msg)
134+
{
135+
const auto & label = transformed_object.classification.front().label;
136+
if (filter_target_.isTarget(label)) {
137+
bool filter_pass = true;
138+
// 1. is polygon overlap with road lanelets or shoulder lanelets
139+
if (filter_settings_.polygon_overlap_filter) {
140+
const bool is_polygon_overlap =
141+
isObjectOverlapLanelets(transformed_object, intersected_road_lanelets) ||
142+
isObjectOverlapLanelets(transformed_object, intersected_shoulder_lanelets);
143+
filter_pass = filter_pass && is_polygon_overlap;
144+
}
145+
146+
// 2. check if objects velocity is the same with the lanelet direction
147+
const bool orientation_not_available =
148+
transformed_object.kinematics.orientation_availability ==
149+
autoware_auto_perception_msgs::msg::TrackedObjectKinematics::UNAVAILABLE;
150+
if (filter_settings_.lanelet_direction_filter && !orientation_not_available) {
151+
const bool is_same_direction =
152+
isSameDirectionWithLanelets(intersected_road_lanelets, transformed_object) ||
153+
isSameDirectionWithLanelets(intersected_shoulder_lanelets, transformed_object);
154+
filter_pass = filter_pass && is_same_direction;
155+
}
156+
157+
// push back to output object
158+
if (filter_pass) {
159+
output_object_msg.objects.emplace_back(input_object);
160+
return true;
161+
}
162+
} else {
163+
output_object_msg.objects.emplace_back(input_object);
164+
return true;
165+
}
166+
return false;
119167
}
120168

121169
geometry_msgs::msg::Polygon ObjectLaneletFilterNode::setFootprint(
@@ -176,6 +224,39 @@ lanelet::ConstLanelets ObjectLaneletFilterNode::getIntersectedLanelets(
176224
return intersected_lanelets;
177225
}
178226

227+
bool ObjectLaneletFilterNode::isObjectOverlapLanelets(
228+
const autoware_auto_perception_msgs::msg::DetectedObject & object,
229+
const lanelet::ConstLanelets & intersected_lanelets)
230+
{
231+
// if has bounding box, use polygon overlap
232+
if (object.shape.type != autoware_auto_perception_msgs::msg::Shape::POLYGON) {
233+
Polygon2d polygon;
234+
const auto footprint = setFootprint(object);
235+
for (const auto & point : footprint.points) {
236+
const geometry_msgs::msg::Point32 point_transformed =
237+
tier4_autoware_utils::transformPoint(point, object.kinematics.pose_with_covariance.pose);
238+
polygon.outer().emplace_back(point_transformed.x, point_transformed.y);
239+
}
240+
polygon.outer().push_back(polygon.outer().front());
241+
return isPolygonOverlapLanelets(polygon, intersected_lanelets);
242+
} else {
243+
// if object do not have bounding box, check each footprint is inside polygon
244+
for (const auto & point : object.shape.footprint.points) {
245+
const geometry_msgs::msg::Point32 point_transformed =
246+
tier4_autoware_utils::transformPoint(point, object.kinematics.pose_with_covariance.pose);
247+
geometry_msgs::msg::Pose point2d;
248+
point2d.position.x = point_transformed.x;
249+
point2d.position.y = point_transformed.y;
250+
for (const auto & lanelet : intersected_lanelets) {
251+
if (lanelet::utils::isInLanelet(point2d, lanelet, 0.0)) {
252+
return true;
253+
}
254+
}
255+
}
256+
return false;
257+
}
258+
}
259+
179260
bool ObjectLaneletFilterNode::isPolygonOverlapLanelets(
180261
const Polygon2d & polygon, const lanelet::ConstLanelets & intersected_lanelets)
181262
{
@@ -187,6 +268,42 @@ bool ObjectLaneletFilterNode::isPolygonOverlapLanelets(
187268
return false;
188269
}
189270

271+
bool ObjectLaneletFilterNode::isSameDirectionWithLanelets(
272+
const lanelet::ConstLanelets & lanelets,
273+
const autoware_auto_perception_msgs::msg::DetectedObject & object)
274+
{
275+
const double object_yaw = tf2::getYaw(object.kinematics.pose_with_covariance.pose.orientation);
276+
const double object_velocity_norm = std::hypot(
277+
object.kinematics.twist_with_covariance.twist.linear.x,
278+
object.kinematics.twist_with_covariance.twist.linear.y);
279+
const double object_velocity_yaw = std::atan2(
280+
object.kinematics.twist_with_covariance.twist.linear.y,
281+
object.kinematics.twist_with_covariance.twist.linear.x) +
282+
object_yaw;
283+
284+
if (object_velocity_norm < filter_settings_.lanelet_direction_filter_object_speed_threshold) {
285+
return true;
286+
}
287+
for (const auto & lanelet : lanelets) {
288+
const bool is_in_lanelet =
289+
lanelet::utils::isInLanelet(object.kinematics.pose_with_covariance.pose, lanelet, 0.0);
290+
if (!is_in_lanelet) {
291+
continue;
292+
}
293+
const double lane_yaw = lanelet::utils::getLaneletAngle(
294+
lanelet, object.kinematics.pose_with_covariance.pose.position);
295+
const double delta_yaw = object_velocity_yaw - lane_yaw;
296+
const double normalized_delta_yaw = tier4_autoware_utils::normalizeRadian(delta_yaw);
297+
const double abs_norm_delta_yaw = std::fabs(normalized_delta_yaw);
298+
299+
if (abs_norm_delta_yaw < filter_settings_.lanelet_direction_filter_velocity_yaw_threshold) {
300+
return true;
301+
}
302+
}
303+
304+
return false;
305+
}
306+
190307
} // namespace object_lanelet_filter
191308

192309
#include <rclcpp_components/register_node_macro.hpp>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2024 TIER IV, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "detected_object_validation/utils/utils.hpp"
16+
17+
#include <autoware_auto_perception_msgs/msg/object_classification.hpp>
18+
19+
#include <gtest/gtest.h>
20+
21+
using AutowareLabel = autoware_auto_perception_msgs::msg::ObjectClassification;
22+
23+
utils::FilterTargetLabel createFilterTargetAll()
24+
{
25+
utils::FilterTargetLabel filter;
26+
filter.UNKNOWN = true;
27+
filter.CAR = true;
28+
filter.TRUCK = true;
29+
filter.BUS = true;
30+
filter.TRAILER = true;
31+
filter.MOTORCYCLE = true;
32+
filter.BICYCLE = true;
33+
filter.PEDESTRIAN = true;
34+
return filter;
35+
}
36+
37+
utils::FilterTargetLabel createFilterTargetVehicle()
38+
{
39+
utils::FilterTargetLabel filter;
40+
filter.UNKNOWN = false;
41+
filter.CAR = true;
42+
filter.TRUCK = true;
43+
filter.BUS = true;
44+
filter.TRAILER = true;
45+
filter.MOTORCYCLE = false;
46+
filter.BICYCLE = false;
47+
filter.PEDESTRIAN = false;
48+
return filter;
49+
}
50+
51+
TEST(IsTargetTest, AllTarget)
52+
{
53+
auto filter = createFilterTargetAll();
54+
auto label = AutowareLabel::CAR;
55+
EXPECT_TRUE(filter.isTarget(label));
56+
}
57+
58+
TEST(IsTargetTest, VehicleTarget)
59+
{
60+
auto filter = createFilterTargetVehicle();
61+
62+
auto car_label = AutowareLabel::CAR;
63+
EXPECT_TRUE(filter.isTarget(car_label));
64+
65+
auto unknown_label = AutowareLabel::UNKNOWN;
66+
EXPECT_FALSE(filter.isTarget(unknown_label));
67+
}

0 commit comments

Comments
 (0)