Skip to content

Commit d3627a5

Browse files
authored
Merge pull request #17 from vortexntnu/Thomas_refactor
Thomas refactor
2 parents 1451a74 + 536d3f3 commit d3627a5

28 files changed

Lines changed: 1490 additions & 655 deletions

.gitignore

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,59 @@ devel/
22
logs/
33
build/
44
bin/
5-
lib/
5+
msg_gen/
6+
srv_gen/
7+
msg/*Action.msg
8+
msg/*ActionFeedback.msg
9+
msg/*ActionGoal.msg
10+
msg/*ActionResult.msg
11+
msg/*Feedback.msg
12+
msg/*Goal.msg
13+
msg/*Result.msg
14+
msg/_*.py
15+
build_isolated/
16+
devel_isolated/
17+
*/launch/__pycache__
18+
19+
# Generated by dynamic reconfigure
20+
*.cfgc
21+
/cfg/cpp/
22+
/cfg/*.py
23+
24+
# Ignore generated docs
25+
*.dox
26+
*.wikidoc
27+
28+
# eclipse stuff
29+
.project
30+
.cproject
31+
32+
# qcreator stuff
33+
CMakeLists.txt.user
34+
35+
srv/_*.py
36+
*.pcd
37+
*.pyc
38+
qtcreator-*
39+
*.user
40+
41+
/planning/cfg
42+
/planning/docs
43+
/planning/src
44+
45+
*~
46+
47+
# Emacs
48+
.#*
49+
50+
# Catkin custom files
51+
CATKIN_IGNORE
52+
53+
.vscode/*
54+
image-filtering/.vscode/*devel/
55+
logs/
56+
build/
57+
bin/
658
msg_gen/
759
srv_gen/
860
msg/*Action.msg
@@ -53,3 +105,4 @@ CATKIN_IGNORE
53105

54106
.vscode/
55107
log/
108+
image-filtering/.vscode/*

README.md

Lines changed: 121 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Image Filtering Node
22
[![Industrial CI](https://github.com/vortexntnu/vortex-image-filtering/actions/workflows/industrial-ci.yml/badge.svg)](https://github.com/vortexntnu/vortex-image-filtering/actions/workflows/industrial-ci.yml)
3+
[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/vortexntnu/vortex-image-filtering/main.svg)](https://results.pre-commit.ci/latest/github/vortexntnu/vortex-image-filtering/main)
34
[![codecov](https://codecov.io/github/vortexntnu/vortex-image-filtering/graph/badge.svg?token=6XHprkpUsR)](https://codecov.io/github/vortexntnu/vortex-image-filtering)
45

56
The `image_filtering_node` is a ROS 2 node developed in the `vortex::image_filters` namespace. It is designed to subscribe to image topics, apply various image filters using OpenCV, and publish the filtered images back to ROS.
@@ -31,96 +32,162 @@ Parameters can be set through a YAML file or dynamically adjusted at runtime.
3132

3233
## Implementing New Filters
3334

34-
To extend the functionality of the `image_filtering_node` by adding new filters, follow these steps to ensure compatibility and integration with the existing codebase:
35+
To extend the functionality of the `image_filtering_node` by adding new filters, follow these steps to ensure compatibility and integration with the existing codebase. There should be //TODO(New filter) comments where you add your filter:
3536

36-
### Step 1: Define Filter Parameters
37+
### Step 1: Filter Enum
3738

38-
Each filter should have its own set of parameters encapsulated in a structure. Define this structure within the `vortex::image_filters` namespace.
39+
You should define your filtertype in the filtertype enum in [typedef.hpp](image-filtering/include/lib/typedef.hpp)
3940

4041
```cpp
41-
struct YourFilterParams {
42-
// Add necessary parameters here
43-
int example_param;
42+
enum class FilterType {
43+
NoFilter,
44+
Flip,
45+
Unsharpening,
46+
Erosion,
47+
Dilation,
48+
...
49+
// Add your filter here
4450
};
4551
```
46-
47-
### Step 2: Add to FilterParams Structure
48-
49-
Integrate your new filter parameters structure into the existing `FilterParams` structure. This allows the `apply_filter` function to access the parameters specific to your filter.
52+
To access the filter through the yaml file we need to access it through a string. In the same file you need to add it as an item in the kFilterMap.
5053
5154
```cpp
52-
struct FilterParams {
53-
std::string filter_type;
54-
UnsharpeningFilterParams unsharpening;
55-
ErodingFilterParams eroding;
56-
DilatingFilterParams dilating;
57-
WhiteBalancingFilterParams white_balancing;
58-
EbusFilterParams ebus;
59-
YourFilterParams your_filter; // Add your filter params here
55+
static constexpr std::pair<std::string_view, FilterType> kFilterMap[] = {
56+
{"no_filter", FilterType::NoFilter},
57+
{"flip", FilterType::Flip},
58+
{"unsharpening", FilterType::Unsharpening},
59+
...
60+
61+
// Add your filter here
62+
{"example", FilterType::Example},
63+
{"unknown", FilterType::Unknown}
6064
};
6165
```
6266

63-
### Step 3: Create the Filter Function
67+
### Step 2: Make the filter header
68+
Each filter should have its own headerfile asosiated with it. You can add this in the [filters](image-filtering/include/lib/filters), and name it the same as your filter (your_filter.hpp). In this file you start with adding these lines (swapping out example with your filter):
6469

65-
Implement your filter function. This function should take the `cv::Mat` objects for the input and output images and a `const FilterParams&` which includes your specific filter parameters. Make sure to use your parameter structure within this function.
70+
```cpp
71+
#ifndef LIB__FILTERS__EXAMPLE_HPP_
72+
#define LIB__FILTERS__EXAMPLE_HPP_
73+
#include "abstract_filter_class.hpp"
6674

75+
76+
// Insert code here ...
77+
78+
79+
#endif // LIB__FILTERS__EXAMPLE_HPP_
80+
```
81+
This new file needs to be added to [all_filters.hpp](image-filtering/include/lib/filters/all_filters.hpp).
6782
```cpp
68-
void your_filter_function(const cv::Mat &original, cv::Mat &filtered, const FilterParams& filter_params) {
69-
// Access your filter-specific parameters like this:
70-
int example_param = filter_params.your_filter.example_param;
83+
#ifndef LIB__FILTERS__EXAMPLE_HPP_
84+
#define LIB__FILTERS__EXAMPLE_HPP_
7185

72-
// Implement your filtering logic here
73-
}
86+
// Add your filter to the top of this file:
87+
#include "lib/filters/your_filter.hpp"
88+
89+
#include "lib/filters/example.hpp"
90+
#include "lib/filters/no_filter.hpp"
91+
92+
93+
#endif // LIB__FILTERS__EXAMPLE_HPP_
7494
```
7595

76-
### Step 4: Register the Filter Function
7796

78-
Add an entry to the `filter_functions` map for your new filter. This step is crucial as it links the filter name (as a string) to the corresponding filter function pointer.
97+
### Step 3: Define Filter Parameters
98+
99+
Each filter should have its own set of parameters encapsulated in a structure. Define this structure within your_filter.hpp.
79100

80101
```cpp
81-
std::map<std::string, FilterFunction> filter_functions = {
82-
{"no_filter", no_filter},
83-
{"sharpening", sharpening_filter},
84-
{"unsharpening", unsharpening_filter},
85-
{"eroding", eroding_filter},
86-
{"dilating", dilating_filter},
87-
{"white_balancing", white_balance_filter},
88-
{"ebus", ebus_filter},
89-
{"your_filter", your_filter_function} // Add your filter here
102+
struct ExampleParams{
103+
// Add necessary filter parameters here
104+
int example_int;
105+
std::string example_string;
90106
};
91107
```
92108

93-
### Step 5: Declare and Assign Parameters
109+
### Step 4: Add filter class
110+
111+
Below the filter parameters add a Class for your filter inheriting from the Filter class, with the same structure as shown below.
112+
```cpp
113+
class Example: public Filter{
114+
public:
115+
explicit Example(ExampleParams params): filter_params(params) {}
116+
void apply_filter(const cv::Mat& original, cv::Mat& filtered) const override; // This is the filter itself
117+
private:
118+
ExampleParams filter_params;
119+
};
120+
```
121+
Here you can add other filter specific stuff like storing variables that need to change between runs and so on.
94122

95-
Declare the new filter parameters in the ROS 2 node constructor and assign these parameters to the `FilterParams` structure within the `set_filter_params` function.
96123

97-
#### In the Node Constructor
124+
### Step 5: Define the filter function
98125

99-
In the constructor of your ROS 2 node, declare each of the new filter parameters using the `declare_parameter` function. This sets the default values and prepares the node to accept these parameters at runtime through command line or a YAML configuration file.
126+
You can do this in two different ways. If your filter is big you can add a cpp file for your filter, explained in the [helperfunctions](#helper-functions) section of this page. Otherwise you can add the function definition just below the class definition like this.
100127

101128
```cpp
102-
ImageFilteringNode::ImageFilteringNode() : Node("image_filtering_node")
103-
{
104-
this->declare_parameter<std::string>("filter_params.your_filter.example_param", "default_value");
105-
...
106-
// Other parameters declarations
129+
inline void Example::apply_filter(const cv::Mat& original, cv::Mat& filtered) const{
130+
std::string example_str = this->filter_params.example_string;
131+
int example_int = this->filter_params.example_int;
132+
DoExample(original,filtered, example_str, example_int);
107133
}
108134
```
109135
110136
111-
#### In the set_filter_params Function
137+
### Step 6: Add to config file
112138
113-
In the set_filter_params function, retrieve and assign the parameters to the corresponding fields in the FilterParams structure. Ensure to handle cases where the parameter might not be set or provided.
139+
In the [image_filtering_params.yaml](image-filtering/config/image_filtering_params.yaml) file you add your filter and filterparameters for easily interfacing with the filters:
114140
115-
```cpp
141+
```yaml
142+
filter_params:
143+
filter_type: "example"
116144
117-
void ImageFilteringNode::set_filter_params(){
118-
FilterParams params = filter_params_; // assuming filter_params_ is already defined in your class
145+
flip:
146+
flip_code: 1
147+
...
148+
# Add your filter type here
149+
150+
example:
151+
example_int: 5
152+
example_string: "This is an example"
153+
```
119154

120-
params.your_filter.example_param = this->get_parameter("filter_params.your_filter.example_param").as_string();
155+
156+
### Step 7: Declare and Assign Parameters
157+
158+
Now we need to use the right filter and set the variables for your filter. We do that by making a new case in `set_filter_params`, in [image_filtering_ros.cpp](image-filtering/src/ros/image_filtering_ros.cpp), for your filter.
159+
160+
```cpp
161+
void ImageFilteringNode::set_filter_params() {
121162
...
122-
// Retrieve other parameters and handle cases where parameters might not be provided
123-
filter_params_ = params; // Update the filter parameters structure
124-
RCLCPP_INFO(this->get_logger(), "Filter parameters updated for your_filter.");
163+
switch (filter_type){
164+
165+
...
166+
167+
case FilterType::Example: {
168+
ExampleParams params;
169+
params.example_int =
170+
declare_and_get<int>("filter_params.example.example_int");
171+
params.example_string =
172+
declare_and_get<std::string>(
173+
"filter_params.example.example_string");
174+
175+
filter_ptr = std::make_unique<Example>(params);
176+
break;
177+
}
178+
}
125179
}
126180
```
181+
182+
183+
184+
### Helper functions
185+
186+
#### Define the apply filter function
187+
188+
If the YourFilter::apply_filter function gets to big you can add a cpp file named the same as your hpp file (your_filter.cpp) in the [filters](image-filtering/src/lib/filters) folder. There you add #include "lib/filters/your_filter.hpp" at the top. Then you can define your filter there. Whenever you make a new c++ file, add the path to [CMakeList.txt](image-filtering/CMakeLists.txt), to the `add_library(${CORE_LIB} SHARED` part.
189+
190+
#### Make and use helperfunctions
191+
192+
193+
If you are making a function that is useful for many different filters, then you can add the declaration to [utilities.hpp](image-filtering/include/lib/utilities.hpp), and the definition to [utilities.cpp](image-filtering/src/lib/utilities.cpp). Make a description off the function above the declaration. To use this in the filter add `#include "image-filtering/include/lib/utilities.hpp"` to your_filter.hpp

image-filtering/CMakeLists.txt

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,48 @@ find_package(cv_bridge REQUIRED)
1818
find_package(spdlog REQUIRED)
1919
find_package(fmt REQUIRED)
2020

21-
include_directories(include)
2221

23-
set(LIB_NAME "${PROJECT_NAME}_component")
2422

25-
add_library(${LIB_NAME} SHARED
26-
src/image_processing.cpp
27-
src/image_filtering_ros.cpp
23+
# ---- Library (no ROS) ----
24+
set(LIB "${PROJECT_NAME}")
25+
26+
add_library(${LIB} SHARED
27+
src/lib/utilities.cpp
2828
)
2929

30-
target_link_libraries(${LIB_NAME} PUBLIC
30+
target_link_libraries(${LIB} PUBLIC
3131
${OpenCV_LIBS}
3232
)
3333

34-
target_include_directories(${LIB_NAME} PUBLIC
34+
target_include_directories(${LIB} PUBLIC
3535
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
3636
$<INSTALL_INTERFACE:include>
3737
${OpenCV_INCLUDE_DIRS}
3838
)
3939

40-
ament_target_dependencies(${LIB_NAME} PUBLIC
40+
ament_target_dependencies(${LIB} PUBLIC
41+
spdlog
42+
fmt
43+
)
44+
45+
# ---- ROS library ----
46+
set(ROS_LIB "${PROJECT_NAME}_component")
47+
48+
add_library(${ROS_LIB} SHARED
49+
src/ros/image_filtering_ros.cpp
50+
src/ros/image_filtering_ros_utils.cpp
51+
)
52+
53+
target_link_libraries(${ROS_LIB} PUBLIC
54+
${LIB}
55+
)
56+
57+
target_include_directories(${ROS_LIB} PUBLIC
58+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
59+
$<INSTALL_INTERFACE:include>
60+
)
61+
62+
ament_target_dependencies(${ROS_LIB} PUBLIC
4163
rclcpp
4264
rclcpp_components
4365
cv_bridge
@@ -47,21 +69,36 @@ ament_target_dependencies(${LIB_NAME} PUBLIC
4769
)
4870

4971
rclcpp_components_register_node(
50-
${LIB_NAME}
51-
PLUGIN "ImageFilteringNode"
52-
EXECUTABLE ${PROJECT_NAME}_node
72+
${ROS_LIB}
73+
PLUGIN "ImageFilteringNode"
74+
EXECUTABLE ${PROJECT_NAME}_node
5375
)
5476

55-
# Export the target for other packages to use
56-
ament_export_targets(export_${LIB_NAME})
5777

58-
install(TARGETS ${LIB_NAME}
59-
EXPORT export_${LIB_NAME}
78+
79+
# Export BOTH targets
80+
ament_export_targets(export_${LIB} HAS_LIBRARY_TARGET)
81+
ament_export_targets(export_${ROS_LIB} HAS_LIBRARY_TARGET)
82+
ament_export_include_directories(include)
83+
ament_export_dependencies(OpenCV spdlog fmt)
84+
ament_export_dependencies(rclcpp rclcpp_components cv_bridge sensor_msgs)
85+
86+
install(TARGETS ${LIB}
87+
EXPORT export_${LIB}
6088
ARCHIVE DESTINATION lib
6189
LIBRARY DESTINATION lib
6290
RUNTIME DESTINATION bin
6391
)
6492

93+
install(TARGETS ${ROS_LIB}
94+
EXPORT export_${ROS_LIB}
95+
ARCHIVE DESTINATION lib
96+
LIBRARY DESTINATION lib
97+
RUNTIME DESTINATION bin
98+
)
99+
100+
101+
65102
install(
66103
DIRECTORY include/
67104
DESTINATION include

0 commit comments

Comments
 (0)