diff --git a/launch/tier4_perception_launch/launch/traffic_light_recognition/traffic_light.launch.xml b/launch/tier4_perception_launch/launch/traffic_light_recognition/traffic_light.launch.xml
index 9e63832f5e522..ea50101719d65 100644
--- a/launch/tier4_perception_launch/launch/traffic_light_recognition/traffic_light.launch.xml
+++ b/launch/tier4_perception_launch/launch/traffic_light_recognition/traffic_light.launch.xml
@@ -2,30 +2,62 @@
-
-
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
-
-
-
@@ -33,13 +65,21 @@
-
-
-
-
+
+
+
+
-
+
+
+
+
+
+
+
+
+
diff --git a/launch/tier4_perception_launch/launch/traffic_light_recognition/traffic_light_node_container.launch.py b/launch/tier4_perception_launch/launch/traffic_light_recognition/traffic_light_node_container.launch.py
index a3fd412577e1f..964008dafa5cd 100644
--- a/launch/tier4_perception_launch/launch/traffic_light_recognition/traffic_light_node_container.launch.py
+++ b/launch/tier4_perception_launch/launch/traffic_light_recognition/traffic_light_node_container.launch.py
@@ -35,38 +35,39 @@ def add_launch_arg(name: str, default_value=None, description=None):
DeclareLaunchArgument(name, default_value=default_value, description=description)
)
- ssd_fine_detector_share_dir = get_package_share_directory("traffic_light_ssd_fine_detector")
+ fine_detector_share_dir = get_package_share_directory("traffic_light_fine_detector")
classifier_share_dir = get_package_share_directory("traffic_light_classifier")
add_launch_arg("enable_image_decompressor", "True")
add_launch_arg("enable_fine_detection", "True")
add_launch_arg("input/image", "/sensing/camera/traffic_light/image_raw")
- # traffic_light_ssd_fine_detector
+ # traffic_light_fine_detector
add_launch_arg(
- "onnx_file", os.path.join(ssd_fine_detector_share_dir, "data", "mb2-ssd-lite-tlr.onnx")
+ "fine_detector_model_path",
+ os.path.join(fine_detector_share_dir, "data", "tlr_yolox_s.onnx"),
)
add_launch_arg(
- "label_file", os.path.join(ssd_fine_detector_share_dir, "data", "voc_labels_tl.txt")
+ "fine_detector_label_path",
+ os.path.join(fine_detector_share_dir, "data", "tlr_labels.txt"),
)
- add_launch_arg("dnn_header_type", "pytorch")
- add_launch_arg("fine_detector_precision", "FP32")
- add_launch_arg("score_thresh", "0.7")
- add_launch_arg("max_batch_size", "8")
+ add_launch_arg("fine_detector_precision", "fp16")
+ add_launch_arg("fine_detector_score_thresh", "0.3")
+ add_launch_arg("fine_detector_nms_thresh", "0.65")
+
add_launch_arg("approximate_sync", "False")
- add_launch_arg("mean", "[0.5, 0.5, 0.5]")
- add_launch_arg("std", "[0.5, 0.5, 0.5]")
# traffic_light_classifier
add_launch_arg("classifier_type", "1")
add_launch_arg(
- "model_file_path",
- os.path.join(classifier_share_dir, "data", "traffic_light_classifier_mobilenetv2.onnx"),
+ "classifier_model_path",
+ os.path.join(classifier_share_dir, "data", "traffic_light_classifier_efficientNet_b1.onnx"),
+ )
+ add_launch_arg(
+ "classifier_label_path", os.path.join(classifier_share_dir, "data", "lamp_labels.txt")
)
- add_launch_arg("label_file_path", os.path.join(classifier_share_dir, "data", "lamp_labels.txt"))
- add_launch_arg("precision", "fp16")
- add_launch_arg("input_c", "3")
- add_launch_arg("input_h", "224")
- add_launch_arg("input_w", "224")
+ add_launch_arg("classifier_precision", "fp16")
+ add_launch_arg("classifier_mean", "[123.675, 116.28, 103.53]")
+ add_launch_arg("classifier_std", "[58.395, 57.12, 57.375]")
add_launch_arg("use_crosswalk_traffic_light_estimator", "True")
add_launch_arg("use_intra_process", "False")
@@ -80,7 +81,7 @@ def create_parameter_dict(*args):
container = ComposableNodeContainer(
name="traffic_light_node_container",
- namespace="/perception/traffic_light_recognition",
+ namespace="",
package="rclcpp_components",
executable=LaunchConfiguration("container_executable"),
composable_node_descriptions=[
@@ -92,12 +93,11 @@ def create_parameter_dict(*args):
create_parameter_dict(
"approximate_sync",
"classifier_type",
- "model_file_path",
- "label_file_path",
- "precision",
- "input_c",
- "input_h",
- "input_w",
+ "classifier_model_path",
+ "classifier_label_path",
+ "classifier_precision",
+ "classifier_mean",
+ "classifier_std",
)
],
remappings=[
@@ -195,28 +195,25 @@ def create_parameter_dict(*args):
condition=IfCondition(LaunchConfiguration("enable_image_decompressor")),
)
- ssd_fine_detector_param = create_parameter_dict(
- "onnx_file",
- "label_file",
- "dnn_header_type",
- "score_thresh",
- "max_batch_size",
- "approximate_sync",
- "mean",
- "std",
+ fine_detector_param = create_parameter_dict(
+ "fine_detector_model_path",
+ "fine_detector_label_path",
+ "fine_detector_precision",
+ "fine_detector_score_thresh",
+ "fine_detector_nms_thresh",
)
- ssd_fine_detector_param["mode"] = LaunchConfiguration("fine_detector_precision")
fine_detector_loader = LoadComposableNodes(
composable_node_descriptions=[
ComposableNode(
- package="traffic_light_ssd_fine_detector",
- plugin="traffic_light::TrafficLightSSDFineDetectorNodelet",
- name="traffic_light_ssd_fine_detector",
- parameters=[ssd_fine_detector_param],
+ package="traffic_light_fine_detector",
+ plugin="traffic_light::TrafficLightFineDetectorNodelet",
+ name="traffic_light_fine_detector",
+ parameters=[fine_detector_param],
remappings=[
("~/input/image", LaunchConfiguration("input/image")),
("~/input/rois", "rough/rois"),
+ ("~/expect/rois", "expect/rois"),
("~/output/rois", "rois"),
],
extra_arguments=[
diff --git a/launch/tier4_planning_launch/launch/scenario_planning/lane_driving/motion_planning/motion_planning.launch.py b/launch/tier4_planning_launch/launch/scenario_planning/lane_driving/motion_planning/motion_planning.launch.py
index d491e14bcf3e4..94461c1748439 100644
--- a/launch/tier4_planning_launch/launch/scenario_planning/lane_driving/motion_planning/motion_planning.launch.py
+++ b/launch/tier4_planning_launch/launch/scenario_planning/lane_driving/motion_planning/motion_planning.launch.py
@@ -108,7 +108,6 @@ def launch_setup(context, *args, **kwargs):
parameters=[
obstacle_velocity_limiter_param,
vehicle_info_param,
- {"obstacles.dynamic_source": "static_only"},
],
extra_arguments=[{"use_intra_process_comms": LaunchConfiguration("use_intra_process")}],
)
diff --git a/localization/yabloc/README.md b/localization/yabloc/README.md
index 34d6c70453c6c..f80dcfc88cf2e 100644
--- a/localization/yabloc/README.md
+++ b/localization/yabloc/README.md
@@ -4,6 +4,10 @@
[![thumbnail](docs/yabloc_thumbnail.jpg)](https://youtu.be/Eaf6r_BNFfk)
+It estimates position by matching road surface markings extracted from images with a vector map.
+Point cloud maps and LiDAR are not required.
+YabLoc enables users localize vehicles that are not equipped with LiDAR and in environments where point cloud maps are not available.
+
## Packages
- [yabloc_common](yabloc_common/README.md)
@@ -13,8 +17,8 @@
## How to launch YabLoc instead of NDT
-When launching autoware, if you set `localization_mode:=yabloc` as an argument, YabLoc will be launched instead of NDT.
-By default, `localization_mode` is `ndt`.
+When launching autoware, if you set `localization_mode:=camera` as an argument, YabLoc will be launched instead of NDT.
+By default, `localization_mode` is `lidar`.
A sample command to run YabLoc is as follows
@@ -23,9 +27,58 @@ ros2 launch autoware_launch logging_simulator.launch.xml \
map_path:=$HOME/autoware_map/sample-map-rosbag\
vehicle_model:=sample_vehicle \
sensor_model:=sample_sensor_kit \
- localization_mode:=yabloc
+ localization_mode:=camera
```
## Architecture
![node_diagram](docs/yabloc_architecture.drawio.svg)
+
+## Principle
+
+The diagram below illustrates the basic principle of YabLoc.
+It extracts road surface markings by extracting the line segments using the road area obtained from graph-based segmentation.
+The red line at the center-top of the diagram represents the line segments identified as road surface markings.
+YabLoc transforms these segments for each particle and determines the particle's weight by comparing them with the cost map generated from Lanelet2.
+
+![principle](docs/yabloc_principle.png)
+
+## Visualization
+
+### Core visualization topics
+
+These topics are not visualized by default.
+
+
+
+| index | topic name | description |
+| ----- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| 1 | `/localization/yabloc/pf/predicted_particle_marker` | particle distribution of particle filter. Red particles are probable candidate. |
+| 2 | `/localization/yabloc/pf/scored_cloud` | 3D projected line segments. the color indicates how well they match the map. |
+| 3 | `/localization/yabloc/image_processing/lanelet2_overlay_image` | overlay of lanelet2 (yellow lines) onto image based on estimated pose. If they match well with the actual road markings, it means that the localization performs well. |
+
+### Image topics for debug
+
+These topics are not visualized by default.
+
+
+
+| index | topic name | description |
+| ----- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
+| 1 | `/localization/yabloc/pf/cost_map_image` | cost map made from lanelet2 |
+| 2 | `/localization/yabloc/pf/match_image` | projected line segments |
+| 3 | `/localization/yabloc/image_processing/image_with_colored_line_segment` | classified line segments. green line segments are used in particle correction |
+| 4 | `/localization/yabloc/image_processing/lanelet2_overlay_image` | overlay of lanelet2 |
+| 5 | `/localization/yabloc/image_processing/segmented_image` | graph based segmentation result |
+
+## Limitation
+
+- Running YabLoc and NDT simultaneously is not supported.
+ - This is because running both at the same time may be computationally too expensive.
+ - Also, in most cases, NDT is superior to YabLoc, so there is less benefit to running them at the same time.
+- It does not estimate roll and pitch, therefore some of the perception nodes may not work well.
+- It does not support multiple cameras now. But it will in the future.
+- In places where there are few road surface markings, such as intersections, the estimation heavily relies on GNSS, IMU, and vehicle's wheel odometry.
+- If the road boundary or road surface markings are not included in the Lanelet2, the estimation is likely to fail.
+- The sample rosbag provided in the autoware tutorial does not include images, so it is not possible to run YabLoc with it.
+ - If you want to test the functionality of YabLoc, the sample test data provided in this [PR](https://github.com/autowarefoundation/autoware.universe/pull/3946) is useful.
diff --git a/localization/yabloc/docs/yabloc_image_description.png b/localization/yabloc/docs/yabloc_image_description.png
new file mode 100644
index 0000000000000..d76977535d306
Binary files /dev/null and b/localization/yabloc/docs/yabloc_image_description.png differ
diff --git a/localization/yabloc/docs/yabloc_principle.png b/localization/yabloc/docs/yabloc_principle.png
new file mode 100644
index 0000000000000..0d7a8294babed
Binary files /dev/null and b/localization/yabloc/docs/yabloc_principle.png differ
diff --git a/localization/yabloc/docs/yabloc_rviz_description.png b/localization/yabloc/docs/yabloc_rviz_description.png
new file mode 100644
index 0000000000000..bd931b139f93b
Binary files /dev/null and b/localization/yabloc/docs/yabloc_rviz_description.png differ
diff --git a/perception/crosswalk_traffic_light_estimator/README.md b/perception/crosswalk_traffic_light_estimator/README.md
index 54d7c561e05c2..e23b454905081 100644
--- a/perception/crosswalk_traffic_light_estimator/README.md
+++ b/perception/crosswalk_traffic_light_estimator/README.md
@@ -8,17 +8,17 @@
### Input
-| Name | Type | Description |
-| ------------------------------------ | -------------------------------------------------------- | ------------------ |
-| `~/input/vector_map` | `autoware_auto_mapping_msgs::msg::HADMapBin` | vector map |
-| `~/input/route` | `autoware_planning_msgs::msg::LaneletRoute` | route |
-| `~/input/classified/traffic_signals` | `autoware_auto_perception_msgs::msg::TrafficSignalArray` | classified signals |
+| Name | Type | Description |
+| ------------------------------------ | ------------------------------------------------ | ------------------ |
+| `~/input/vector_map` | `autoware_auto_mapping_msgs::msg::HADMapBin` | vector map |
+| `~/input/route` | `autoware_planning_msgs::msg::LaneletRoute` | route |
+| `~/input/classified/traffic_signals` | `tier4_perception_msgs::msg::TrafficSignalArray` | classified signals |
### Output
-| Name | Type | Description |
-| -------------------------- | -------------------------------------------------------- | --------------------------------------------------------- |
-| `~/output/traffic_signals` | `autoware_auto_perception_msgs::msg::TrafficSignalArray` | output that contains estimated pedestrian traffic signals |
+| Name | Type | Description |
+| -------------------------- | ------------------------------------------------ | --------------------------------------------------------- |
+| `~/output/traffic_signals` | `tier4_perception_msgs::msg::TrafficSignalArray` | output that contains estimated pedestrian traffic signals |
## Parameters
diff --git a/perception/crosswalk_traffic_light_estimator/include/crosswalk_traffic_light_estimator/node.hpp b/perception/crosswalk_traffic_light_estimator/include/crosswalk_traffic_light_estimator/node.hpp
index 852e99ff7ba54..0850436851e6a 100644
--- a/perception/crosswalk_traffic_light_estimator/include/crosswalk_traffic_light_estimator/node.hpp
+++ b/perception/crosswalk_traffic_light_estimator/include/crosswalk_traffic_light_estimator/node.hpp
@@ -22,11 +22,11 @@
#include
#include
-#include
-#include
-#include
#include
#include
+#include
+#include
+#include
#include
#include
@@ -43,13 +43,13 @@ namespace traffic_light
{
using autoware_auto_mapping_msgs::msg::HADMapBin;
-using autoware_auto_perception_msgs::msg::TrafficLight;
-using autoware_auto_perception_msgs::msg::TrafficSignal;
-using autoware_auto_perception_msgs::msg::TrafficSignalArray;
using autoware_planning_msgs::msg::LaneletRoute;
using tier4_autoware_utils::DebugPublisher;
using tier4_autoware_utils::StopWatch;
using tier4_debug_msgs::msg::Float64Stamped;
+using tier4_perception_msgs::msg::TrafficLightElement;
+using tier4_perception_msgs::msg::TrafficSignal;
+using tier4_perception_msgs::msg::TrafficSignalArray;
using TrafficSignalAndTime = std::pair;
using TrafficLightIdMap = std::unordered_map;
diff --git a/perception/crosswalk_traffic_light_estimator/package.xml b/perception/crosswalk_traffic_light_estimator/package.xml
index 1a3b90f617f4e..435ecf6e6fa3d 100644
--- a/perception/crosswalk_traffic_light_estimator/package.xml
+++ b/perception/crosswalk_traffic_light_estimator/package.xml
@@ -11,13 +11,13 @@
autoware_cmake
autoware_auto_mapping_msgs
- autoware_auto_perception_msgs
autoware_auto_planning_msgs
autoware_planning_msgs
lanelet2_extension
rclcpp
rclcpp_components
tier4_autoware_utils
+ tier4_perception_msgs
ament_lint_auto
autoware_lint_common
diff --git a/perception/crosswalk_traffic_light_estimator/src/node.cpp b/perception/crosswalk_traffic_light_estimator/src/node.cpp
index 8400a1708e6af..55d272cb71cfe 100644
--- a/perception/crosswalk_traffic_light_estimator/src/node.cpp
+++ b/perception/crosswalk_traffic_light_estimator/src/node.cpp
@@ -160,7 +160,7 @@ void CrosswalkTrafficLightEstimatorNode::onTrafficLightArray(
TrafficLightIdMap traffic_light_id_map;
for (const auto & traffic_signal : msg->signals) {
- traffic_light_id_map[traffic_signal.map_primitive_id] =
+ traffic_light_id_map[traffic_signal.traffic_light_id] =
std::pair(traffic_signal, get_clock()->now());
}
@@ -185,17 +185,17 @@ void CrosswalkTrafficLightEstimatorNode::updateLastDetectedSignal(
const TrafficLightIdMap & traffic_light_id_map)
{
for (const auto & input_traffic_signal : traffic_light_id_map) {
- const auto & lights = input_traffic_signal.second.first.lights;
+ const auto & elements = input_traffic_signal.second.first.elements;
- if (lights.empty()) {
+ if (elements.empty()) {
continue;
}
- if (lights.front().color == TrafficLight::UNKNOWN) {
+ if (elements.front().color == TrafficLightElement::UNKNOWN) {
continue;
}
- const auto & id = input_traffic_signal.second.first.map_primitive_id;
+ const auto & id = input_traffic_signal.second.first.traffic_light_id;
if (last_detect_color_.count(id) == 0) {
last_detect_color_.insert(std::make_pair(id, input_traffic_signal.second));
@@ -207,7 +207,7 @@ void CrosswalkTrafficLightEstimatorNode::updateLastDetectedSignal(
std::vector erase_id_list;
for (auto & last_traffic_signal : last_detect_color_) {
- const auto & id = last_traffic_signal.second.first.map_primitive_id;
+ const auto & id = last_traffic_signal.second.first.traffic_light_id;
if (traffic_light_id_map.count(id) == 0) {
// hold signal recognition results for [last_detect_color_hold_time_] seconds.
@@ -233,11 +233,11 @@ void CrosswalkTrafficLightEstimatorNode::setCrosswalkTrafficSignal(
const auto ll_traffic_light = static_cast(traffic_light);
TrafficSignal output_traffic_signal;
- TrafficLight output_traffic_light;
+ TrafficLightElement output_traffic_light;
output_traffic_light.color = color;
output_traffic_light.confidence = 1.0;
- output_traffic_signal.lights.push_back(output_traffic_light);
- output_traffic_signal.map_primitive_id = ll_traffic_light.id();
+ output_traffic_signal.elements.push_back(output_traffic_light);
+ output_traffic_signal.traffic_light_id = ll_traffic_light.id();
msg.signals.push_back(output_traffic_signal);
}
}
@@ -265,13 +265,14 @@ lanelet::ConstLanelets CrosswalkTrafficLightEstimatorNode::getNonRedLanelets(
continue;
}
- const auto current_is_not_red = current_detected_signal
- ? current_detected_signal.get() == TrafficLight::GREEN ||
- current_detected_signal.get() == TrafficLight::AMBER
- : true;
+ const auto current_is_not_red =
+ current_detected_signal ? current_detected_signal.get() == TrafficLightElement::GREEN ||
+ current_detected_signal.get() == TrafficLightElement::AMBER
+ : true;
const auto current_is_unknown_or_none =
- current_detected_signal ? current_detected_signal.get() == TrafficLight::UNKNOWN : true;
+ current_detected_signal ? current_detected_signal.get() == TrafficLightElement::UNKNOWN
+ : true;
const auto last_detected_signal =
getHighestConfidenceTrafficSignal(traffic_lights_for_vehicle, last_detect_color_);
@@ -281,8 +282,8 @@ lanelet::ConstLanelets CrosswalkTrafficLightEstimatorNode::getNonRedLanelets(
}
const auto was_not_red = current_is_unknown_or_none &&
- (last_detected_signal.get() == TrafficLight::GREEN ||
- last_detected_signal.get() == TrafficLight::AMBER) &&
+ (last_detected_signal.get() == TrafficLightElement::GREEN ||
+ last_detected_signal.get() == TrafficLightElement::AMBER) &&
use_last_detect_color_;
if (!current_is_not_red && !was_not_red) {
@@ -323,12 +324,13 @@ uint8_t CrosswalkTrafficLightEstimatorNode::estimateCrosswalkTrafficSignal(
}
if (has_straight_non_red_lane || has_related_non_red_tl) {
- return TrafficLight::RED;
+ return TrafficLightElement::RED;
}
const auto has_merge_lane = hasMergeLane(non_red_lanelets, routing_graph_ptr_);
- return !has_merge_lane && has_left_non_red_lane && has_right_non_red_lane ? TrafficLight::RED
- : TrafficLight::UNKNOWN;
+ return !has_merge_lane && has_left_non_red_lane && has_right_non_red_lane
+ ? TrafficLightElement::RED
+ : TrafficLightElement::UNKNOWN;
}
boost::optional CrosswalkTrafficLightEstimatorNode::getHighestConfidenceTrafficSignal(
@@ -348,13 +350,13 @@ boost::optional CrosswalkTrafficLightEstimatorNode::getHighestConfidenc
continue;
}
- const auto & lights = traffic_light_id_map.at(id).first.lights;
- if (lights.empty()) {
+ const auto & elements = traffic_light_id_map.at(id).first.elements;
+ if (elements.empty()) {
continue;
}
- const auto & color = lights.front().color;
- const auto & confidence = lights.front().confidence;
+ const auto & color = elements.front().color;
+ const auto & confidence = elements.front().confidence;
if (confidence < highest_confidence) {
continue;
}
diff --git a/perception/traffic_light_classifier/CMakeLists.txt b/perception/traffic_light_classifier/CMakeLists.txt
index e125abc7b435a..aeea36ecde047 100644
--- a/perception/traffic_light_classifier/CMakeLists.txt
+++ b/perception/traffic_light_classifier/CMakeLists.txt
@@ -84,14 +84,14 @@ function(download FILE_NAME FILE_HASH)
else()
message(STATUS "diff ${FILE_NAME}")
message(STATUS "File hash changes. Downloading now ...")
- file(DOWNLOAD https://awf.ml.dev.web.auto/perception/models/${FILE_NAME} ${FILE_PATH} STATUS DOWNLOAD_STATUS TIMEOUT 300)
+ file(DOWNLOAD https://awf.ml.dev.web.auto/perception/models/traffic_light_classifier/v1/${FILE_NAME} ${FILE_PATH} STATUS DOWNLOAD_STATUS TIMEOUT 300)
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
list(GET DOWNLOAD_STATUS 1 ERROR_MESSAGE)
endif()
else()
message(STATUS "not found ${FILE_NAME}")
message(STATUS "File doesn't exists. Downloading now ...")
- file(DOWNLOAD https://awf.ml.dev.web.auto/perception/models/${FILE_NAME} ${FILE_PATH} STATUS DOWNLOAD_STATUS TIMEOUT 300)
+ file(DOWNLOAD https://awf.ml.dev.web.auto/perception/models/traffic_light_classifier/v1/${FILE_NAME} ${FILE_PATH} STATUS DOWNLOAD_STATUS TIMEOUT 300)
list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
list(GET DOWNLOAD_STATUS 1 ERROR_MESSAGE)
endif()
@@ -101,8 +101,9 @@ function(download FILE_NAME FILE_HASH)
message(FATAL_ERROR "Error occurred during download: ${ERROR_MESSAGE}")
endif()
endfunction()
-download(traffic_light_classifier_mobilenetv2.onnx 7dc31c696b0400ddfc2cc5521586fa51)
-download(lamp_labels.txt 20167c8e9a1f9d2ec7b0b0088c4100f0)
+download(traffic_light_classifier_mobilenetv2.onnx caa51f2080aa2df943e4f884c41898eb)
+download(traffic_light_classifier_efficientNet_b1.onnx 82baba4fcf1abe0c040cd55005e34510)
+download(lamp_labels.txt 4b2cf910d97d05d464e7c26901af3d4c)
find_package(ament_cmake_auto REQUIRED)
ament_auto_find_build_dependencies()
@@ -113,15 +114,16 @@ if(TRT_AVAIL AND CUDA_AVAIL AND CUDNN_AVAIL)
add_definitions(-DENABLE_GPU)
include_directories(
- utils
${OpenCV_INCLUDE_DIRS}
${CUDA_INCLUDE_DIRS}
)
- ament_auto_add_library(libutils SHARED
- utils/trt_common.cpp
+ ament_auto_add_library(traffic_light_classifier_nodelet SHARED
+ src/color_classifier.cpp
+ src/cnn_classifier.cpp
+ src/nodelet.cpp
)
- target_link_libraries(libutils
+ target_link_libraries(traffic_light_classifier_nodelet
${OpenCV_LIBRARIES}
${NVINFER}
${NVONNXPARSER}
@@ -131,16 +133,6 @@ if(TRT_AVAIL AND CUDA_AVAIL AND CUDNN_AVAIL)
${CUDNN_LIBRARY}
stdc++fs
)
-
- ament_auto_add_library(traffic_light_classifier_nodelet SHARED
- src/color_classifier.cpp
- src/cnn_classifier.cpp
- src/nodelet.cpp
- )
- target_link_libraries(traffic_light_classifier_nodelet
- libutils
- ${OpenCV_LIBRARIES}
- )
rclcpp_components_register_node(traffic_light_classifier_nodelet
PLUGIN "traffic_light::TrafficLightClassifierNodelet"
EXECUTABLE traffic_light_classifier_node
@@ -153,7 +145,14 @@ if(TRT_AVAIL AND CUDA_AVAIL AND CUDNN_AVAIL)
src/single_image_debug_inference_node.cpp
)
target_link_libraries(single_image_debug_inference_node
- libutils
+ ${OpenCV_LIBRARIES}
+ ${NVINFER}
+ ${NVONNXPARSER}
+ ${NVINFER_PLUGIN}
+ ${CUDA_LIBRARIES}
+ ${CUBLAS_LIBRARIES}
+ ${CUDNN_LIBRARY}
+ stdc++fs
opencv_core
opencv_highgui
)
diff --git a/perception/traffic_light_classifier/README.md b/perception/traffic_light_classifier/README.md
index 0935a451862e1..e2faf1633d331 100644
--- a/perception/traffic_light_classifier/README.md
+++ b/perception/traffic_light_classifier/README.md
@@ -8,8 +8,14 @@ traffic_light_classifier is a package for classifying traffic light labels using
### cnn_classifier
-Traffic light labels are classified by MobileNetV2.
-Totally 37600 (26300 for training, 6800 for evaluation and 4500 for test) TIER IV internal images of Japanese traffic lights were used for fine-tuning.
+Traffic light labels are classified by EfficientNet-b1 or MobiletNet-v2.
+Totally 83400 (58600 for training, 14800 for evaluation and 10000 for test) TIER IV internal images of Japanese traffic lights were used for fine-tuning.
+The information of the models is listed here:
+
+| Name | Input Size | Test Accuracy |
+| --------------- | ---------- | ------------- |
+| EfficientNet-b1 | 128 x 128 | 99.76% |
+| MobileNet-v2 | 224 x 224 | 99.81% |
### hsv_classifier
@@ -30,17 +36,17 @@ These colors and shapes are assigned to the message as follows:
### Input
-| Name | Type | Description |
-| --------------- | ---------------------------------------------------------- | ---------------------- |
-| `~/input/image` | `sensor_msgs::msg::Image` | input image |
-| `~/input/rois` | `autoware_auto_perception_msgs::msg::TrafficLightRoiArray` | rois of traffic lights |
+| Name | Type | Description |
+| --------------- | -------------------------------------------------- | ---------------------- |
+| `~/input/image` | `sensor_msgs::msg::Image` | input image |
+| `~/input/rois` | `tier4_perception_msgs::msg::TrafficLightRoiArray` | rois of traffic lights |
### Output
-| Name | Type | Description |
-| -------------------------- | -------------------------------------------------------- | ------------------- |
-| `~/output/traffic_signals` | `autoware_auto_perception_msgs::msg::TrafficSignalArray` | classified signals |
-| `~/output/debug/image` | `sensor_msgs::msg::Image` | image for debugging |
+| Name | Type | Description |
+| -------------------------- | ------------------------------------------------ | ------------------- |
+| `~/output/traffic_signals` | `tier4_perception_msgs::msg::TrafficSignalArray` | classified signals |
+| `~/output/debug/image` | `sensor_msgs::msg::Image` | image for debugging |
## Parameters
@@ -54,19 +60,14 @@ These colors and shapes are assigned to the message as follows:
#### cnn_classifier
-| Name | Type | Description |
-| ----------------- | ------ | ------------------------------------------------- |
-| `model_file_path` | str | path to the model file |
-| `label_file_path` | str | path to the label file |
-| `precision` | str | TensorRT precision, `fp16` or `int8` |
-| `input_c` | str | the channel size of an input image |
-| `input_h` | str | the height of an input image |
-| `input_w` | str | the width of an input image |
-| `input_name` | str | the name of neural network's input layer |
-| `output_name` | str | the name of neural network's output name |
-| `mean` | double | mean values for image normalization |
-| `std` | double | std values for image normalization |
-| `build_only` | bool | shutdown node after TensorRT engine file is built |
+| Name | Type | Description |
+| ----------------------- | --------------- | ------------------------------------ |
+| `classifier_label_path` | str | path to the model file |
+| `classifier_model_path` | str | path to the label file |
+| `classifier_precision` | str | TensorRT precision, `fp16` or `int8` |
+| `classifier_mean` | vector\ | 3-channel input image mean |
+| `classifier_std` | vector\ | 3-channel input image std |
+| `apply_softmax` | bool | whether or not apply softmax |
#### hsv_classifier
@@ -93,10 +94,10 @@ These colors and shapes are assigned to the message as follows:
## Customization of CNN model
-Currently, in Autoware, [MobileNetV2](https://arxiv.org/abs/1801.04381v3) is used as CNN classifier by default. The corresponding onnx file is `data/traffic_light_classifier_mobilenetv2.onnx`(This file will be downloaded during the build process).
+Currently, in Autoware, [MobileNetV2](https://arxiv.org/abs/1801.04381v3) and [EfficientNet-b1](https://arxiv.org/abs/1905.11946v5) are provided.
+The corresponding onnx files are `data/traffic_light_classifier_mobilenetv2.onnx` and `data/traffic_light_classifier_efficientNet_b1.onnx` (These files will be downloaded during the build process).
Also, you can apply the following models shown as below, for example.
-- [EfficientNet](https://arxiv.org/abs/1905.11946v5)
- [ResNet](https://openaccess.thecvf.com/content_cvpr_2016/html/He_Deep_Residual_Learning_CVPR_2016_paper.html)
- [MobileNetV3](https://arxiv.org/abs/1905.02244)
...
@@ -153,7 +154,7 @@ python3 pytorch2onnx.py YOUR_CONFIG.py ...
```
After obtaining your onnx model, update parameters defined in the launch file (e.g. `model_file_path`, `label_file_path`, `input_h`, `input_w`...).
-Note that, we only support labels defined in [autoware_auto_perception_msgs::msg::TrafficLight](https://github.com/tier4/autoware_auto_msgs/blob/tier4/main/autoware_auto_perception_msgs/msg/TrafficLight.idl).
+Note that, we only support labels defined in [tier4_perception_msgs::msg::TrafficLightElement](https://github.com/tier4/tier4_autoware_msgs/blob/tier4/universe/tier4_perception_msgs/msg/traffic_light/TrafficLightElement.msg).
## Assumptions / Known limits
@@ -191,6 +192,8 @@ Example:
[1] M. Sandler, A. Howard, M. Zhu, A. Zhmoginov and L. Chen, "MobileNetV2: Inverted Residuals and Linear Bottlenecks," 2018 IEEE/CVF Conference on Computer Vision and Pattern Recognition, Salt Lake City, UT, 2018, pp. 4510-4520, doi: 10.1109/CVPR.2018.00474.
+[2] Tan, Mingxing, and Quoc Le. "Efficientnet: Rethinking model scaling for convolutional neural networks." International conference on machine learning. PMLR, 2019.
+
## (Optional) Future extensions / Unimplemented parts
@@ -17,17 +16,9 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/perception/traffic_light_classifier/package.xml b/perception/traffic_light_classifier/package.xml
index 2f7b07962a23b..89129cf0fe9d4 100644
--- a/perception/traffic_light_classifier/package.xml
+++ b/perception/traffic_light_classifier/package.xml
@@ -9,10 +9,11 @@
Apache License 2.0
ament_cmake_auto
- autoware_cmake
wget
- autoware_auto_perception_msgs
+ autoware_cmake
+
+ cuda_utils
cv_bridge
image_transport
libboost-filesystem-dev
@@ -20,6 +21,8 @@
rclcpp
rclcpp_components
sensor_msgs
+ tensorrt_common
+ tier4_perception_msgs
ament_cmake
diff --git a/perception/traffic_light_classifier/src/cnn_classifier.cpp b/perception/traffic_light_classifier/src/cnn_classifier.cpp
index 621466206ac01..45ef5f94af146 100644
--- a/perception/traffic_light_classifier/src/cnn_classifier.cpp
+++ b/perception/traffic_light_classifier/src/cnn_classifier.cpp
@@ -1,4 +1,4 @@
-// Copyright 2020 Tier IV, Inc.
+// Copyright 2023 TIER IV, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -33,23 +33,41 @@ CNNClassifier::CNNClassifier(rclcpp::Node * node_ptr) : node_ptr_(node_ptr)
std::string precision;
std::string label_file_path;
std::string model_file_path;
- precision = node_ptr_->declare_parameter("precision", "fp16");
- label_file_path = node_ptr_->declare_parameter("label_file_path", "labels.txt");
- model_file_path = node_ptr_->declare_parameter("model_file_path", "model.onnx");
- input_c_ = node_ptr_->declare_parameter("input_c", 3);
- input_h_ = node_ptr_->declare_parameter("input_h", 224);
- input_w_ = node_ptr_->declare_parameter("input_w", 224);
- mean_ = node_ptr_->declare_parameter("mean", std::vector({0.242, 0.193, 0.201}));
- std_ = node_ptr_->declare_parameter("std", std::vector({1.0, 1.0, 1.0}));
- std::string input_name = node_ptr_->declare_parameter("input_name", std::string("input_0"));
- std::string output_name = node_ptr_->declare_parameter("output_name", std::string("output_0"));
- apply_softmax_ = node_ptr_->declare_parameter("apply_softmax", true);
+ precision = node_ptr_->declare_parameter("classifier_precision", "fp16");
+ label_file_path = node_ptr_->declare_parameter("classifier_label_path", "labels.txt");
+ model_file_path = node_ptr_->declare_parameter("classifier_model_path", "model.onnx");
+ apply_softmax_ = node_ptr_->declare_parameter("apply_softmax", false);
+ mean_ =
+ node_ptr->declare_parameter("classifier_mean", std::vector{123.675, 116.28, 103.53});
+ std_ = node_ptr->declare_parameter("classifier_std", std::vector{58.395, 57.12, 57.375});
+ if (mean_.size() != 3 || std_.size() != 3) {
+ RCLCPP_ERROR(node_ptr->get_logger(), "classifier_mean and classifier_std must be of size 3");
+ return;
+ }
readLabelfile(label_file_path, labels_);
- trt_ = std::make_shared(model_file_path, precision, input_name, output_name);
- trt_->setup();
+ tensorrt_common::BatchConfig batch_config{1, 1, 1};
+ size_t max_workspace_size = 1 << 30;
+ trt_common_ = std::make_unique(
+ model_file_path, precision, nullptr, batch_config, max_workspace_size);
+ trt_common_->setup();
+ if (!trt_common_->isInitialized()) {
+ return;
+ }
+ const auto input_dims = trt_common_->getBindingDimensions(0);
+ if (input_dims.nbDims != 4) {
+ RCLCPP_ERROR(node_ptr_->get_logger(), "Model input dimension must be 4!");
+ }
+ batch_size_ = input_dims.d[0];
+ input_c_ = input_dims.d[1];
+ input_h_ = input_dims.d[2];
+ input_w_ = input_dims.d[3];
+ num_input_ = batch_size_ * input_c_ * input_h_ * input_w_;
+ const auto output_dims = trt_common_->getBindingDimensions(1);
+ num_output_ =
+ std::accumulate(output_dims.d, output_dims.d + output_dims.nbDims, 1, std::multiplies());
if (node_ptr_->declare_parameter("build_only", false)) {
RCLCPP_INFO(node_ptr_->get_logger(), "TensorRT engine is built and shutdown node.");
rclcpp::shutdown();
@@ -57,36 +75,33 @@ CNNClassifier::CNNClassifier(rclcpp::Node * node_ptr) : node_ptr_(node_ptr)
}
bool CNNClassifier::getTrafficSignal(
- const cv::Mat & input_image, autoware_auto_perception_msgs::msg::TrafficSignal & traffic_signal)
+ const cv::Mat & input_image, tier4_perception_msgs::msg::TrafficSignal & traffic_signal)
{
- if (!trt_->isInitialized()) {
+ if (!trt_common_->isInitialized()) {
RCLCPP_WARN(node_ptr_->get_logger(), "failed to init tensorrt");
return false;
}
- int num_input = trt_->getNumInput();
- int num_output = trt_->getNumOutput();
-
- std::vector input_data_host(num_input);
+ std::vector input_data_host(num_input_);
cv::Mat image = input_image.clone();
preProcess(image, input_data_host, true);
- auto input_data_device = Tn::make_unique(num_input);
+ auto input_data_device = cuda_utils::make_unique(num_input_);
cudaMemcpy(
- input_data_device.get(), input_data_host.data(), num_input * sizeof(float),
+ input_data_device.get(), input_data_host.data(), num_input_ * sizeof(float),
cudaMemcpyHostToDevice);
- auto output_data_device = Tn::make_unique(num_output);
+ auto output_data_device = cuda_utils::make_unique(num_output_);
// do inference
std::vector bindings = {input_data_device.get(), output_data_device.get()};
- trt_->context_->executeV2(bindings.data());
+ trt_common_->enqueueV2(bindings.data(), *stream_, nullptr);
- std::vector output_data_host(num_output);
+ std::vector output_data_host(num_output_);
cudaMemcpy(
- output_data_host.data(), output_data_device.get(), num_output * sizeof(float),
+ output_data_host.data(), output_data_device.get(), num_output_ * sizeof(float),
cudaMemcpyDeviceToHost);
postProcess(output_data_host, traffic_signal, apply_softmax_);
@@ -101,17 +116,17 @@ bool CNNClassifier::getTrafficSignal(
}
void CNNClassifier::outputDebugImage(
- cv::Mat & debug_image, const autoware_auto_perception_msgs::msg::TrafficSignal & traffic_signal)
+ cv::Mat & debug_image, const tier4_perception_msgs::msg::TrafficSignal & traffic_signal)
{
float probability;
std::string label;
- for (std::size_t i = 0; i < traffic_signal.lights.size(); i++) {
- auto light = traffic_signal.lights.at(i);
+ for (std::size_t i = 0; i < traffic_signal.elements.size(); i++) {
+ auto light = traffic_signal.elements.at(i);
const auto light_label = state2label_[light.color] + "-" + state2label_[light.shape];
label += light_label;
// all lamp confidence are the same
probability = light.confidence;
- if (i < traffic_signal.lights.size() - 1) {
+ if (i < traffic_signal.elements.size() - 1) {
label += ",";
}
}
@@ -134,11 +149,13 @@ void CNNClassifier::outputDebugImage(
void CNNClassifier::preProcess(cv::Mat & image, std::vector & input_tensor, bool normalize)
{
- /* normalize */
- /* ((channel[0] / 255) - mean[0]) / std[0] */
-
- // cv::cvtColor(image, image, cv::COLOR_BGR2RGB, 3);
- cv::resize(image, image, cv::Size(input_w_, input_h_));
+ const float scale =
+ std::min(static_cast(input_w_) / image.cols, static_cast(input_h_) / image.rows);
+ const auto scale_size = cv::Size(image.cols * scale, image.rows * scale);
+ cv::resize(image, image, scale_size, 0, 0, cv::INTER_CUBIC);
+ const auto bottom = input_h_ - image.rows;
+ const auto right = input_w_ - image.cols;
+ copyMakeBorder(image, image, 0, bottom, 0, right, cv::BORDER_CONSTANT, {0, 0, 0});
const size_t strides_cv[3] = {
static_cast(input_w_ * input_c_), static_cast(input_c_), 1};
@@ -151,8 +168,7 @@ void CNNClassifier::preProcess(cv::Mat & image, std::vector & input_tenso
const size_t offset_cv = i * strides_cv[0] + j * strides_cv[1] + k * strides_cv[2];
const size_t offset = k * strides[0] + i * strides[1] + j * strides[2];
if (normalize) {
- input_tensor[offset] =
- ((static_cast(image.data[offset_cv]) / 255) - mean_[k]) / std_[k];
+ input_tensor[offset] = (static_cast(image.data[offset_cv]) - mean_[k]) / std_[k];
} else {
input_tensor[offset] = static_cast(image.data[offset_cv]);
}
@@ -162,19 +178,14 @@ void CNNClassifier::preProcess(cv::Mat & image, std::vector & input_tenso
}
bool CNNClassifier::postProcess(
- std::vector & output_tensor,
- autoware_auto_perception_msgs::msg::TrafficSignal & traffic_signal, bool apply_softmax)
+ std::vector & output_tensor, tier4_perception_msgs::msg::TrafficSignal & traffic_signal,
+ bool apply_softmax)
{
std::vector probs;
- int num_output = trt_->getNumOutput();
if (apply_softmax) {
- calcSoftmax(output_tensor, probs, num_output);
+ calcSoftmax(output_tensor, probs, num_output_);
}
- std::vector sorted_indices = argsort(output_tensor, num_output);
-
- // ROS_INFO("label: %s, score: %.2f\%",
- // labels_[sorted_indices[0]].c_str(),
- // probs[sorted_indices[0]] * 100);
+ std::vector sorted_indices = argsort(output_tensor, num_output_);
size_t max_indice = sorted_indices.front();
std::string match_label = labels_[max_indice];
@@ -194,27 +205,27 @@ bool CNNClassifier::postProcess(
node_ptr_->get_logger(), "cnn_classifier does not have a key [%s]", label.c_str());
continue;
}
- autoware_auto_perception_msgs::msg::TrafficLight light;
+ tier4_perception_msgs::msg::TrafficLightElement element;
if (label.find("-") != std::string::npos) {
// found "-" delimiter in label string
std::vector color_and_shape;
boost::algorithm::split(color_and_shape, label, boost::is_any_of("-"));
- light.color = label2state_[color_and_shape.at(0)];
- light.shape = label2state_[color_and_shape.at(1)];
+ element.color = label2state_[color_and_shape.at(0)];
+ element.shape = label2state_[color_and_shape.at(1)];
} else {
- if (label == state2label_[autoware_auto_perception_msgs::msg::TrafficLight::UNKNOWN]) {
- light.color = autoware_auto_perception_msgs::msg::TrafficLight::UNKNOWN;
- light.shape = autoware_auto_perception_msgs::msg::TrafficLight::UNKNOWN;
+ if (label == state2label_[tier4_perception_msgs::msg::TrafficLightElement::UNKNOWN]) {
+ element.color = tier4_perception_msgs::msg::TrafficLightElement::UNKNOWN;
+ element.shape = tier4_perception_msgs::msg::TrafficLightElement::UNKNOWN;
} else if (isColorLabel(label)) {
- light.color = label2state_[label];
- light.shape = autoware_auto_perception_msgs::msg::TrafficLight::CIRCLE;
+ element.color = label2state_[label];
+ element.shape = tier4_perception_msgs::msg::TrafficLightElement::CIRCLE;
} else {
- light.color = autoware_auto_perception_msgs::msg::TrafficLight::GREEN;
- light.shape = label2state_[label];
+ element.color = tier4_perception_msgs::msg::TrafficLightElement::GREEN;
+ element.shape = label2state_[label];
}
}
- light.confidence = probability;
- traffic_signal.lights.push_back(light);
+ element.confidence = probability;
+ traffic_signal.elements.push_back(element);
}
return true;
@@ -262,12 +273,12 @@ std::vector CNNClassifier::argsort(std::vector & tensor, int num_
bool CNNClassifier::isColorLabel(const std::string label)
{
- using autoware_auto_perception_msgs::msg::TrafficSignal;
+ using tier4_perception_msgs::msg::TrafficSignal;
if (
- label == state2label_[autoware_auto_perception_msgs::msg::TrafficLight::GREEN] ||
- label == state2label_[autoware_auto_perception_msgs::msg::TrafficLight::AMBER] ||
- label == state2label_[autoware_auto_perception_msgs::msg::TrafficLight::RED] ||
- label == state2label_[autoware_auto_perception_msgs::msg::TrafficLight::WHITE]) {
+ label == state2label_[tier4_perception_msgs::msg::TrafficLightElement::GREEN] ||
+ label == state2label_[tier4_perception_msgs::msg::TrafficLightElement::AMBER] ||
+ label == state2label_[tier4_perception_msgs::msg::TrafficLightElement::RED] ||
+ label == state2label_[tier4_perception_msgs::msg::TrafficLightElement::WHITE]) {
return true;
}
return false;
diff --git a/perception/traffic_light_classifier/src/color_classifier.cpp b/perception/traffic_light_classifier/src/color_classifier.cpp
index 0267b3cd3c3ac..4b7fb37096021 100644
--- a/perception/traffic_light_classifier/src/color_classifier.cpp
+++ b/perception/traffic_light_classifier/src/color_classifier.cpp
@@ -1,4 +1,4 @@
-// Copyright 2020 Tier IV, Inc.
+// Copyright 2023 TIER IV, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -52,7 +52,7 @@ ColorClassifier::ColorClassifier(rclcpp::Node * node_ptr) : node_ptr_(node_ptr)
}
bool ColorClassifier::getTrafficSignal(
- const cv::Mat & input_image, autoware_auto_perception_msgs::msg::TrafficSignal & traffic_signal)
+ const cv::Mat & input_image, tier4_perception_msgs::msg::TrafficSignal & traffic_signal)
{
cv::Mat green_image;
cv::Mat yellow_image;
@@ -157,25 +157,25 @@ bool ColorClassifier::getTrafficSignal(
static_cast(red_filtered_bin_image.rows * red_filtered_bin_image.cols);
if (yellow_ratio < green_ratio && red_ratio < green_ratio) {
- autoware_auto_perception_msgs::msg::TrafficLight light;
- light.color = autoware_auto_perception_msgs::msg::TrafficLight::GREEN;
- light.confidence = std::min(1.0, static_cast(green_pixel_num) / (20.0 * 20.0));
- traffic_signal.lights.push_back(light);
+ tier4_perception_msgs::msg::TrafficLightElement element;
+ element.color = tier4_perception_msgs::msg::TrafficLightElement::GREEN;
+ element.confidence = std::min(1.0, static_cast(green_pixel_num) / (20.0 * 20.0));
+ traffic_signal.elements.push_back(element);
} else if (green_ratio < yellow_ratio && red_ratio < yellow_ratio) {
- autoware_auto_perception_msgs::msg::TrafficLight light;
- light.color = autoware_auto_perception_msgs::msg::TrafficLight::AMBER;
- light.confidence = std::min(1.0, static_cast(yellow_pixel_num) / (20.0 * 20.0));
- traffic_signal.lights.push_back(light);
+ tier4_perception_msgs::msg::TrafficLightElement element;
+ element.color = tier4_perception_msgs::msg::TrafficLightElement::AMBER;
+ element.confidence = std::min(1.0, static_cast(yellow_pixel_num) / (20.0 * 20.0));
+ traffic_signal.elements.push_back(element);
} else if (green_ratio < red_ratio && yellow_ratio < red_ratio) {
- autoware_auto_perception_msgs::msg::TrafficLight light;
- light.color = ::autoware_auto_perception_msgs::msg::TrafficLight::RED;
- light.confidence = std::min(1.0, static_cast(red_pixel_num) / (20.0 * 20.0));
- traffic_signal.lights.push_back(light);
+ tier4_perception_msgs::msg::TrafficLightElement element;
+ element.color = ::tier4_perception_msgs::msg::TrafficLightElement::RED;
+ element.confidence = std::min(1.0, static_cast(red_pixel_num) / (20.0 * 20.0));
+ traffic_signal.elements.push_back(element);
} else {
- autoware_auto_perception_msgs::msg::TrafficLight light;
- light.color = ::autoware_auto_perception_msgs::msg::TrafficLight::UNKNOWN;
- light.confidence = 0.0;
- traffic_signal.lights.push_back(light);
+ tier4_perception_msgs::msg::TrafficLightElement element;
+ element.color = ::tier4_perception_msgs::msg::TrafficLightElement::UNKNOWN;
+ element.confidence = 0.0;
+ traffic_signal.elements.push_back(element);
}
return true;
}
diff --git a/perception/traffic_light_classifier/src/nodelet.cpp b/perception/traffic_light_classifier/src/nodelet.cpp
index a593f34fd8273..5332f5d3baacc 100644
--- a/perception/traffic_light_classifier/src/nodelet.cpp
+++ b/perception/traffic_light_classifier/src/nodelet.cpp
@@ -1,4 +1,4 @@
-// Copyright 2020 Tier IV, Inc.
+// Copyright 2023 TIER IV, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -37,7 +37,7 @@ TrafficLightClassifierNodelet::TrafficLightClassifierNodelet(const rclcpp::NodeO
}
traffic_signal_array_pub_ =
- this->create_publisher(
+ this->create_publisher(
"~/output/traffic_signals", rclcpp::QoS{1});
using std::chrono_literals::operator""ms;
@@ -74,7 +74,7 @@ void TrafficLightClassifierNodelet::connectCb()
void TrafficLightClassifierNodelet::imageRoiCallback(
const sensor_msgs::msg::Image::ConstSharedPtr & input_image_msg,
- const autoware_auto_perception_msgs::msg::TrafficLightRoiArray::ConstSharedPtr & input_rois_msg)
+ const tier4_perception_msgs::msg::TrafficLightRoiArray::ConstSharedPtr & input_rois_msg)
{
if (classifier_ptr_.use_count() == 0) {
return;
@@ -89,15 +89,15 @@ void TrafficLightClassifierNodelet::imageRoiCallback(
input_image_msg->encoding.c_str());
}
- autoware_auto_perception_msgs::msg::TrafficSignalArray output_msg;
+ tier4_perception_msgs::msg::TrafficSignalArray output_msg;
for (size_t i = 0; i < input_rois_msg->rois.size(); ++i) {
const sensor_msgs::msg::RegionOfInterest & roi = input_rois_msg->rois.at(i).roi;
cv::Mat clipped_image(
cv_ptr->image, cv::Rect(roi.x_offset, roi.y_offset, roi.width, roi.height));
- autoware_auto_perception_msgs::msg::TrafficSignal traffic_signal;
- traffic_signal.map_primitive_id = input_rois_msg->rois.at(i).id;
+ tier4_perception_msgs::msg::TrafficSignal traffic_signal;
+ traffic_signal.traffic_light_id = input_rois_msg->rois.at(i).traffic_light_id;
if (!classifier_ptr_->getTrafficSignal(clipped_image, traffic_signal)) {
RCLCPP_ERROR(this->get_logger(), "failed classify image, abort callback");
return;
diff --git a/perception/traffic_light_classifier/src/single_image_debug_inference_node.cpp b/perception/traffic_light_classifier/src/single_image_debug_inference_node.cpp
index f324b04f1628c..10d36978224ab 100644
--- a/perception/traffic_light_classifier/src/single_image_debug_inference_node.cpp
+++ b/perception/traffic_light_classifier/src/single_image_debug_inference_node.cpp
@@ -1,4 +1,4 @@
-// Copyright 2023 Tier IV, Inc.
+// Copyright 2023 TIER IV, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -28,31 +28,31 @@ namespace
{
std::string toString(const uint8_t state)
{
- if (state == autoware_auto_perception_msgs::msg::TrafficLight::RED) {
+ if (state == tier4_perception_msgs::msg::TrafficLightElement::RED) {
return "red";
- } else if (state == autoware_auto_perception_msgs::msg::TrafficLight::AMBER) {
+ } else if (state == tier4_perception_msgs::msg::TrafficLightElement::AMBER) {
return "yellow";
- } else if (state == autoware_auto_perception_msgs::msg::TrafficLight::GREEN) {
+ } else if (state == tier4_perception_msgs::msg::TrafficLightElement::GREEN) {
return "green";
- } else if (state == autoware_auto_perception_msgs::msg::TrafficLight::WHITE) {
+ } else if (state == tier4_perception_msgs::msg::TrafficLightElement::WHITE) {
return "white";
- } else if (state == autoware_auto_perception_msgs::msg::TrafficLight::CIRCLE) {
+ } else if (state == tier4_perception_msgs::msg::TrafficLightElement::CIRCLE) {
return "circle";
- } else if (state == autoware_auto_perception_msgs::msg::TrafficLight::LEFT_ARROW) {
+ } else if (state == tier4_perception_msgs::msg::TrafficLightElement::LEFT_ARROW) {
return "left";
- } else if (state == autoware_auto_perception_msgs::msg::TrafficLight::RIGHT_ARROW) {
+ } else if (state == tier4_perception_msgs::msg::TrafficLightElement::RIGHT_ARROW) {
return "right";
- } else if (state == autoware_auto_perception_msgs::msg::TrafficLight::UP_ARROW) {
+ } else if (state == tier4_perception_msgs::msg::TrafficLightElement::UP_ARROW) {
return "straight";
- } else if (state == autoware_auto_perception_msgs::msg::TrafficLight::DOWN_ARROW) {
+ } else if (state == tier4_perception_msgs::msg::TrafficLightElement::DOWN_ARROW) {
return "down";
- } else if (state == autoware_auto_perception_msgs::msg::TrafficLight::DOWN_LEFT_ARROW) {
+ } else if (state == tier4_perception_msgs::msg::TrafficLightElement::DOWN_LEFT_ARROW) {
return "down_left";
- } else if (state == autoware_auto_perception_msgs::msg::TrafficLight::DOWN_RIGHT_ARROW) {
+ } else if (state == tier4_perception_msgs::msg::TrafficLightElement::DOWN_RIGHT_ARROW) {
return "down_right";
- } else if (state == autoware_auto_perception_msgs::msg::TrafficLight::CROSS) {
+ } else if (state == tier4_perception_msgs::msg::TrafficLightElement::CROSS) {
return "cross";
- } else if (state == autoware_auto_perception_msgs::msg::TrafficLight::UNKNOWN) {
+ } else if (state == tier4_perception_msgs::msg::TrafficLightElement::UNKNOWN) {
return "unknown";
} else {
return "";
@@ -122,17 +122,17 @@ class SingleImageDebugInferenceNode : public rclcpp::Node
return;
}
cv::cvtColor(crop, crop, cv::COLOR_BGR2RGB);
- autoware_auto_perception_msgs::msg::TrafficSignal traffic_signal;
+ tier4_perception_msgs::msg::TrafficSignal traffic_signal;
if (!classifier_ptr_->getTrafficSignal(crop, traffic_signal)) {
RCLCPP_ERROR(get_logger(), "failed to classify image");
return;
}
cv::Scalar color;
cv::Scalar text_color;
- for (const auto & light : traffic_signal.lights) {
- auto color_str = toString(light.color);
- auto shape_str = toString(light.shape);
- auto confidence_str = std::to_string(light.confidence);
+ for (const auto & element : traffic_signal.elements) {
+ auto color_str = toString(element.color);
+ auto shape_str = toString(element.shape);
+ auto confidence_str = std::to_string(element.confidence);
if (shape_str == "circle") {
if (color_str == "red") {
color = cv::Scalar(0, 0, 255);
diff --git a/perception/traffic_light_classifier/utils/trt_common.cpp b/perception/traffic_light_classifier/utils/trt_common.cpp
deleted file mode 100644
index f12be16879321..0000000000000
--- a/perception/traffic_light_classifier/utils/trt_common.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-// Copyright 2020 Tier IV, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include
-
-#if (defined(_MSC_VER) or (defined(__GNUC__) and (7 <= __GNUC_MAJOR__)))
-#include
-namespace fs = ::std::filesystem;
-#else
-#include
-namespace fs = ::std::experimental::filesystem;
-#endif
-
-#include
-#include
-
-namespace Tn
-{
-void check_error(const ::cudaError_t e, decltype(__FILE__) f, decltype(__LINE__) n)
-{
- if (e != ::cudaSuccess) {
- std::stringstream s;
- s << ::cudaGetErrorName(e) << " (" << e << ")@" << f << "#L" << n << ": "
- << ::cudaGetErrorString(e);
- throw std::runtime_error{s.str()};
- }
-}
-
-TrtCommon::TrtCommon(
- std::string model_path, std::string precision, std::string input_name, std::string output_name)
-: model_file_path_(model_path),
- precision_(precision),
- input_name_(input_name),
- output_name_(output_name),
- is_initialized_(false)
-{
- runtime_ = UniquePtr(nvinfer1::createInferRuntime(logger_));
-}
-
-void TrtCommon::setup()
-{
- const fs::path path(model_file_path_);
- std::string extension = path.extension().string();
-
- if (fs::exists(path)) {
- if (extension == ".engine") {
- loadEngine(model_file_path_);
- } else if (extension == ".onnx") {
- fs::path cache_engine_path{model_file_path_};
- cache_engine_path.replace_extension("engine");
- if (fs::exists(cache_engine_path)) {
- loadEngine(cache_engine_path.string());
- } else {
- logger_.log(nvinfer1::ILogger::Severity::kINFO, "start build engine");
- buildEngineFromOnnx(model_file_path_, cache_engine_path.string());
- logger_.log(nvinfer1::ILogger::Severity::kINFO, "end build engine");
- }
- } else {
- is_initialized_ = false;
- return;
- }
- } else {
- is_initialized_ = false;
- return;
- }
-
- context_ = UniquePtr(engine_->createExecutionContext());
-
-#if (NV_TENSORRT_MAJOR * 10000) + (NV_TENSORRT_MINOR * 100) + NV_TENSOR_PATCH >= 80500
- input_dims_ = engine_->getTensorShape(input_name_.c_str());
- output_dims_ = engine_->getTensorShape(output_name_.c_str());
-#else
- // Deprecated since 8.5
- input_dims_ = engine_->getBindingDimensions(engine_->getBindingIndex(input_name_.c_str()));
- output_dims_ = engine_->getBindingDimensions(engine_->getBindingIndex(output_name_.c_str()));
-#endif
-
- is_initialized_ = true;
-}
-
-bool TrtCommon::loadEngine(std::string engine_file_path)
-{
- std::ifstream engine_file(engine_file_path);
- std::stringstream engine_buffer;
- engine_buffer << engine_file.rdbuf();
- std::string engine_str = engine_buffer.str();
- engine_ = UniquePtr(runtime_->deserializeCudaEngine(
- reinterpret_cast(engine_str.data()), engine_str.size()));
- return true;
-}
-
-bool TrtCommon::buildEngineFromOnnx(std::string onnx_file_path, std::string output_engine_file_path)
-{
- auto builder = UniquePtr(nvinfer1::createInferBuilder(logger_));
- const auto explicitBatch =
- 1U << static_cast(nvinfer1::NetworkDefinitionCreationFlag::kEXPLICIT_BATCH);
- auto network = UniquePtr(builder->createNetworkV2(explicitBatch));
- auto config = UniquePtr(builder->createBuilderConfig());
-
- auto parser = UniquePtr(nvonnxparser::createParser(*network, logger_));
- if (!parser->parseFromFile(
- onnx_file_path.c_str(), static_cast(nvinfer1::ILogger::Severity::kERROR))) {
- return false;
- }
-
-#if (NV_TENSORRT_MAJOR * 1000) + (NV_TENSORRT_MINOR * 100) + NV_TENSOR_PATCH >= 8400
- config->setMemoryPoolLimit(nvinfer1::MemoryPoolType::kWORKSPACE, 16 << 20);
-#else
- config->setMaxWorkspaceSize(16 << 20);
-#endif
-
- if (precision_ == "fp16") {
- config->setFlag(nvinfer1::BuilderFlag::kFP16);
- } else if (precision_ == "int8") {
- config->setFlag(nvinfer1::BuilderFlag::kINT8);
- } else {
- return false;
- }
-
- auto plan = UniquePtr(builder->buildSerializedNetwork(*network, *config));
- if (!plan) {
- return false;
- }
- engine_ =
- UniquePtr(runtime_->deserializeCudaEngine(plan->data(), plan->size()));
- if (!engine_) {
- return false;
- }
-
- // save engine
- std::ofstream file;
- file.open(output_engine_file_path, std::ios::binary | std::ios::out);
- if (!file.is_open()) {
- return false;
- }
- file.write((const char *)plan->data(), plan->size());
- file.close();
-
- return true;
-}
-
-bool TrtCommon::isInitialized()
-{
- return is_initialized_;
-}
-
-int TrtCommon::getNumInput()
-{
- return std::accumulate(
- input_dims_.d, input_dims_.d + input_dims_.nbDims, 1, std::multiplies());
-}
-
-int TrtCommon::getNumOutput()
-{
- return std::accumulate(
- output_dims_.d, output_dims_.d + output_dims_.nbDims, 1, std::multiplies());
-}
-
-} // namespace Tn
diff --git a/perception/traffic_light_classifier/utils/trt_common.hpp b/perception/traffic_light_classifier/utils/trt_common.hpp
deleted file mode 100644
index d7e314a3b4705..0000000000000
--- a/perception/traffic_light_classifier/utils/trt_common.hpp
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright 2020 Tier IV, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef PERCEPTION__TRAFFIC_LIGHT_CLASSIFIER__UTILS__TRT_COMMON_HPP_
-#define PERCEPTION__TRAFFIC_LIGHT_CLASSIFIER__UTILS__TRT_COMMON_HPP_
-
-#include
-#include
-
-#include <./cudnn.h>
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#define CHECK_CUDA_ERROR(e) (Tn::check_error(e, __FILE__, __LINE__))
-
-namespace Tn
-{
-class Logger : public nvinfer1::ILogger
-{
-public:
- Logger() : Logger(Severity::kINFO) {}
-
- explicit Logger(Severity severity) : reportableSeverity(severity) {}
-
- void log(Severity severity, const char * msg) noexcept override
- {
- // suppress messages with severity enum value greater than the reportable
- if (severity > reportableSeverity) {
- return;
- }
-
- switch (severity) {
- case Severity::kINTERNAL_ERROR:
- std::cerr << "[TRT_COMMON][INTERNAL_ERROR]: ";
- break;
- case Severity::kERROR:
- std::cerr << "[TRT_COMMON][ERROR]: ";
- break;
- case Severity::kWARNING:
- std::cerr << "[TRT_COMMON][WARNING]: ";
- break;
- case Severity::kINFO:
- std::cerr << "[TRT_COMMON][INFO]: ";
- break;
- default:
- std::cerr << "[TRT_COMMON][UNKNOWN]: ";
- break;
- }
- std::cerr << msg << std::endl;
- }
-
- Severity reportableSeverity{Severity::kWARNING};
-};
-
-void check_error(const ::cudaError_t e, decltype(__FILE__) f, decltype(__LINE__) n);
-
-struct InferDeleter
-{
- void operator()(void * p) const { ::cudaFree(p); }
-};
-
-template
-using UniquePtr = std::unique_ptr;
-
-// auto array = Tn::make_unique(n);
-// ::cudaMemcpy(array.get(), src_array, sizeof(float)*n, ::cudaMemcpyHostToDevice);
-template
-typename std::enable_if::value, Tn::UniquePtr>::type make_unique(
- const std::size_t n)
-{
- using U = typename std::remove_extent::type;
- U * p;
- ::cudaMalloc(reinterpret_cast(&p), sizeof(U) * n);
- return Tn::UniquePtr{p};
-}
-
-// auto value = Tn::make_unique();
-// ::cudaMemcpy(value.get(), src_value, sizeof(my_class), ::cudaMemcpyHostToDevice);
-template
-Tn::UniquePtr make_unique()
-{
- T * p;
- ::cudaMalloc(reinterpret_cast(&p), sizeof(T));
- return Tn::UniquePtr{p};
-}
-
-class TrtCommon
-{
-public:
- TrtCommon(
- std::string model_path, std::string precision, std::string input_name, std::string output_name);
- ~TrtCommon() {}
-
- bool loadEngine(std::string engine_file_path);
- bool buildEngineFromOnnx(std::string onnx_file_path, std::string output_engine_file_path);
- void setup();
-
- bool isInitialized();
- int getNumInput();
- int getNumOutput();
-
- UniquePtr context_;
-
-private:
- Logger logger_;
- std::string model_file_path_;
- UniquePtr runtime_;
- UniquePtr engine_;
-
- nvinfer1::Dims input_dims_;
- nvinfer1::Dims output_dims_;
- std::string cache_dir_;
- std::string precision_;
- std::string input_name_;
- std::string output_name_;
- bool is_initialized_;
-};
-
-} // namespace Tn
-
-#endif // PERCEPTION__TRAFFIC_LIGHT_CLASSIFIER__UTILS__TRT_COMMON_HPP_
diff --git a/perception/traffic_light_fine_detector/.gitignore b/perception/traffic_light_fine_detector/.gitignore
new file mode 100644
index 0000000000000..8fce603003c1e
--- /dev/null
+++ b/perception/traffic_light_fine_detector/.gitignore
@@ -0,0 +1 @@
+data/
diff --git a/perception/traffic_light_fine_detector/CMakeLists.txt b/perception/traffic_light_fine_detector/CMakeLists.txt
new file mode 100644
index 0000000000000..a26cafff1ee4d
--- /dev/null
+++ b/perception/traffic_light_fine_detector/CMakeLists.txt
@@ -0,0 +1,156 @@
+cmake_minimum_required(VERSION 3.14)
+project(traffic_light_fine_detector)
+
+find_package(autoware_cmake REQUIRED)
+autoware_package()
+
+add_compile_options(-Wno-deprecated-declarations)
+
+option(CUDA_VERBOSE "Verbose output of CUDA modules" OFF)
+
+find_package(OpenCV REQUIRED)
+
+# set flags for CUDA availability
+option(CUDA_AVAIL "CUDA available" OFF)
+find_package(CUDA)
+if(CUDA_FOUND)
+ find_library(CUBLAS_LIBRARIES cublas HINTS
+ ${CUDA_TOOLKIT_ROOT_DIR}/lib64
+ ${CUDA_TOOLKIT_ROOT_DIR}/lib
+ )
+ if(CUDA_VERBOSE)
+ message(STATUS "CUDA is available!")
+ message(STATUS "CUDA Libs: ${CUDA_LIBRARIES}")
+ message(STATUS "CUDA Headers: ${CUDA_INCLUDE_DIRS}")
+ endif()
+ set(CUDA_AVAIL ON)
+else()
+ message(STATUS "CUDA NOT FOUND")
+ set(CUDA_AVAIL OFF)
+endif()
+
+# set flags for TensorRT availability
+option(TRT_AVAIL "TensorRT available" OFF)
+# try to find the tensorRT modules
+find_library(NVINFER NAMES nvinfer)
+find_library(NVONNXPARSER nvonnxparser)
+find_library(NVINFER_PLUGIN NAMES nvinfer_plugin)
+if(NVINFER AND NVONNXPARSER AND NVINFER_PLUGIN)
+ if(CUDA_VERBOSE)
+ message(STATUS "TensorRT is available!")
+ message(STATUS "NVINFER: ${NVINFER}")
+ message(STATUS "NVPARSERS: ${NVPARSERS}")
+ message(STATUS "NVINFER_PLUGIN: ${NVINFER_PLUGIN}")
+ message(STATUS "NVONNXPARSER: ${NVONNXPARSER}")
+ endif()
+ set(TRT_AVAIL ON)
+else()
+ message(STATUS "TensorRT is NOT Available")
+ set(TRT_AVAIL OFF)
+endif()
+
+# set flags for CUDNN availability
+option(CUDNN_AVAIL "CUDNN available" OFF)
+# try to find the CUDNN module
+find_library(CUDNN_LIBRARY
+ NAMES libcudnn.so${__cudnn_ver_suffix} libcudnn${__cudnn_ver_suffix}.dylib ${__cudnn_lib_win_name}
+ PATHS $ENV{LD_LIBRARY_PATH} ${__libpath_cudart} ${CUDNN_ROOT_DIR} ${PC_CUDNN_LIBRARY_DIRS} ${CMAKE_INSTALL_PREFIX}
+ PATH_SUFFIXES lib lib64 bin
+ DOC "CUDNN library."
+)
+if(CUDNN_LIBRARY)
+ if(CUDA_VERBOSE)
+ message(STATUS "CUDNN is available!")
+ message(STATUS "CUDNN_LIBRARY: ${CUDNN_LIBRARY}")
+ endif()
+ set(CUDNN_AVAIL ON)
+else()
+ message(STATUS "CUDNN is NOT Available")
+ set(CUDNN_AVAIL OFF)
+endif()
+
+# Download caffemodel and prototxt
+set(PRETRAINED_MODEL_HASH f3af5bd588c6c99ccf9ca236a07ad41e)
+set(LAMP_LABEL_HASH e9f45efb02f2a9aa8ac27b3d5c164905)
+set(DATA_DIR https://awf.ml.dev.web.auto/perception/models/tlr_yolox_s/v2)
+
+set(DATA_PATH "${CMAKE_CURRENT_SOURCE_DIR}/data")
+if(NOT EXISTS "${DATA_PATH}")
+ execute_process(COMMAND mkdir -p ${DATA_PATH})
+endif()
+function(download FILE_NAME FILE_HASH)
+ message(STATUS "Checking and downloading ${FILE_NAME}")
+ set(FILE_PATH ${DATA_PATH}/${FILE_NAME})
+ set(STATUS_CODE 0)
+ message(STATUS "start ${FILE_NAME}")
+ if(EXISTS ${FILE_PATH})
+ message(STATUS "found ${FILE_NAME}")
+ file(MD5 ${FILE_PATH} EXISTING_FILE_HASH)
+ if(${FILE_HASH} STREQUAL ${EXISTING_FILE_HASH})
+ message(STATUS "same ${FILE_NAME}")
+ message(STATUS "File already exists.")
+ else()
+ message(STATUS "diff ${FILE_NAME}")
+ message(STATUS "File hash changes. Downloading now ...")
+ file(DOWNLOAD ${DATA_DIR}/${FILE_NAME} ${FILE_PATH} STATUS DOWNLOAD_STATUS TIMEOUT 300)
+ list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
+ list(GET DOWNLOAD_STATUS 1 ERROR_MESSAGE)
+ endif()
+ else()
+ message(STATUS "not found ${FILE_NAME}")
+ message(STATUS "File doesn't exists. Downloading now ...")
+ file(DOWNLOAD ${DATA_DIR}/${FILE_NAME} ${FILE_PATH} STATUS DOWNLOAD_STATUS TIMEOUT 300)
+ list(GET DOWNLOAD_STATUS 0 STATUS_CODE)
+ list(GET DOWNLOAD_STATUS 1 ERROR_MESSAGE)
+ endif()
+ if(${STATUS_CODE} EQUAL 0)
+ message(STATUS "Download completed successfully!")
+ else()
+ message(FATAL_ERROR "Error occurred during download: ${ERROR_MESSAGE}")
+ endif()
+endfunction()
+download(tlr_yolox_s.onnx ${PRETRAINED_MODEL_HASH})
+download(tlr_labels.txt ${LAMP_LABEL_HASH})
+
+if(TRT_AVAIL AND CUDA_AVAIL AND CUDNN_AVAIL)
+ include_directories(
+ ${OpenCV_INCLUDE_DIRS}
+ ${CUDA_INCLUDE_DIRS}
+ )
+
+ ament_auto_add_library(traffic_light_fine_detector_nodelet SHARED
+ src/nodelet.cpp
+ )
+
+ target_include_directories(traffic_light_fine_detector_nodelet PUBLIC
+ lib/include
+ )
+
+ target_link_libraries(traffic_light_fine_detector_nodelet
+ ${NVINFER}
+ ${NVONNXPARSER}
+ ${NVINFER_PLUGIN}
+ ${CUDA_LIBRARIES}
+ ${CUBLAS_LIBRARIES}
+ ${CUDNN_LIBRARY}
+ ${OpenCV_LIB}
+ stdc++fs
+ )
+
+ rclcpp_components_register_node(traffic_light_fine_detector_nodelet
+ PLUGIN "traffic_light::TrafficLightFineDetectorNodelet"
+ EXECUTABLE traffic_light_fine_detector_node
+ )
+
+ ament_auto_package(INSTALL_TO_SHARE
+ data
+ launch
+ )
+
+else()
+ message(STATUS "TrafficLightFineDetector won't be built, CUDA and/or TensorRT were not found.")
+ # to avoid launch file missing without a gpu
+ ament_auto_package(INSTALL_TO_SHARE
+ launch
+ )
+endif()
diff --git a/perception/traffic_light_fine_detector/README.md b/perception/traffic_light_fine_detector/README.md
new file mode 100644
index 0000000000000..1ed6debfeae91
--- /dev/null
+++ b/perception/traffic_light_fine_detector/README.md
@@ -0,0 +1,66 @@
+# traffic_light_fine_detector
+
+## Purpose
+
+It is a package for traffic light detection using YoloX-s.
+
+## Training Information
+
+### Pretrained Model
+
+The model is based on [YOLOX](https://github.com/Megvii-BaseDetection/YOLOX) and the pretrained model could be downloaded from [here](https://github.com/Megvii-BaseDetection/YOLOX/releases/download/0.1.1rc0/yolox_s.pth).
+
+### Training Data
+
+The model was fine-tuned on around 17,000 TIER IV internal images of Japanese traffic lights.
+
+### Trained Onnx model
+
+-
+
+## Inner-workings / Algorithms
+
+Based on the camera image and the global ROI array detected by `map_based_detection` node, a CNN-based detection method enables highly accurate traffic light detection.
+
+## Inputs / Outputs
+
+### Input
+
+| Name | Type | Description |
+| --------------- | -------------------------------------------------- | ------------------------------------------------------------------- |
+| `~/input/image` | `sensor_msgs/Image` | The full size camera image |
+| `~/input/rois` | `tier4_perception_msgs::msg::TrafficLightRoiArray` | The array of ROIs detected by map_based_detector |
+| `~/expect/rois` | `tier4_perception_msgs::msg::TrafficLightRoiArray` | The array of ROIs detected by map_based_detector without any offset |
+
+### Output
+
+| Name | Type | Description |
+| --------------------- | -------------------------------------------------- | ---------------------------- |
+| `~/output/rois` | `tier4_perception_msgs::msg::TrafficLightRoiArray` | The detected accurate rois |
+| `~/debug/exe_time_ms` | `tier4_debug_msgs::msg::Float32Stamped` | The time taken for inference |
+
+## Parameters
+
+### Core Parameters
+
+| Name | Type | Default Value | Description |
+| ---------------------------- | ------ | ------------- | ---------------------------------------------------------------------- |
+| `fine_detector_score_thresh` | double | 0.3 | If the objectness score is less than this value, the object is ignored |
+| `fine_detector_nms_thresh` | double | 0.65 | IoU threshold to perform Non-Maximum Suppression |
+
+### Node Parameters
+
+| Name | Type | Default Value | Description |
+| -------------------------- | ------ | ------------- | ------------------------------------------------------------------ |
+| `fine_detector_model_path` | string | "" | The onnx file name for yolo model |
+| `fine_detector_label_path` | string | "" | The label file with label names for detected objects written on it |
+| `fine_detector_precision` | string | "fp32" | The inference mode: "fp32", "fp16" |
+| `approximate_sync` | bool | false | Flag for whether to ues approximate sync policy |
+
+## Assumptions / Known limits
+
+## Reference repositories
+
+YOLOX github repository
+
+-
diff --git a/perception/traffic_light_fine_detector/include/traffic_light_fine_detector/nodelet.hpp b/perception/traffic_light_fine_detector/include/traffic_light_fine_detector/nodelet.hpp
new file mode 100644
index 0000000000000..f115596453835
--- /dev/null
+++ b/perception/traffic_light_fine_detector/include/traffic_light_fine_detector/nodelet.hpp
@@ -0,0 +1,172 @@
+// Copyright 2023 TIER IV, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef TRAFFIC_LIGHT_FINE_DETECTOR__NODELET_HPP_
+#define TRAFFIC_LIGHT_FINE_DETECTOR__NODELET_HPP_
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#if __has_include()
+#include
+#else
+#include
+#endif
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include