Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
0063195
Initial commit
jorgenfj May 26, 2024
11d9ab7
initial commit
jorgenfj May 26, 2024
39e8379
added gitignore
jorgenfj May 27, 2024
eb7c50c
removed unused main file
jorgenfj May 28, 2024
385c042
ci: add ci workflows and config files
kluge7 Mar 25, 2025
8dcc03f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 25, 2025
a7f2da6
Merge pull request #3 from vortexntnu/ci/setup-workflows
jorgenfj Mar 25, 2025
69cd612
docs(README.md): add status badges for CI workflows
kluge7 Mar 26, 2025
2507055
otsu filter and refactor
jorgenfj Apr 14, 2025
51f4892
Merge pull request #5 from vortexntnu/refactor-and-otsu-filter
jorgenfj Apr 15, 2025
74775ac
[pre-commit.ci] pre-commit autoupdate (#4)
pre-commit-ci[bot] Apr 26, 2025
af7438c
declare param function
jorgenfj Sep 14, 2025
a52c845
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Sep 14, 2025
d6edc65
[pre-commit.ci] pre-commit autoupdate
pre-commit-ci[bot] Jul 7, 2025
e76c207
Merge pull request #7 from vortexntnu/declare-param-function
jorgenfj Sep 14, 2025
29291ad
Adding the gauian blur but without the 5th step (declare and asign pa…
rom-thom Oct 22, 2025
8719586
Adding future stuf
rom-thom Oct 26, 2025
45d7cf8
adding new files and filters
rom-thom Nov 2, 2025
9e30fe6
remove .vscode files and cashed stuff
rom-thom Nov 2, 2025
43c0d08
remove image_filtering.vscode files and cashed stuff
rom-thom Nov 2, 2025
d68360d
Making the utils file work
rom-thom Nov 2, 2025
497d74d
Starting the modulation prosses. made auto gamma modular
rom-thom Nov 2, 2025
c794f1f
Adding modular computation of otsu threshold
rom-thom Nov 2, 2025
2ab9709
test
rom-thom Nov 2, 2025
544c9ce
adding last part has to be tested first
rom-thom Nov 2, 2025
d9c206e
Add dilation errotion and dilation
rom-thom Nov 3, 2025
ad04b9b
Small changes
rom-thom Nov 3, 2025
f4e9a43
finishing the modularity phase
rom-thom Nov 3, 2025
d7fcc6a
adding last part of the modularity stuf
rom-thom Nov 3, 2025
23a8a1b
its time to say goodbye
rom-thom Nov 3, 2025
4a50ca1
Making median_binary filter from the paper (it is kind of ass)
rom-thom Nov 3, 2025
6cc3f94
Filip said it was ok
rom-thom Nov 5, 2025
df64d93
testing
rom-thom Nov 7, 2025
c8df273
Hei
rom-thom Nov 7, 2025
831412e
tilbake
rom-thom Nov 7, 2025
4a297af
Basicaly changed the whole thing, trust me bro it is beter
rom-thom Nov 12, 2025
c978a30
It is done
rom-thom Nov 12, 2025
4ec71f2
Adding the rest of the filters
rom-thom Nov 13, 2025
4596c56
changed(not realy fixed) some bugs
rom-thom Nov 18, 2025
fdb5e6b
removing unesesary code
rom-thom Jan 5, 2026
7a64cf5
Merge branch 'Thomas_refactor' of https://github.com/vortexntnu/vorte…
rom-thom Jan 5, 2026
6c29ba5
Documenting the code with examples
rom-thom Jan 5, 2026
1737631
refactoring
rom-thom Jan 5, 2026
c06fb2f
Fixing mono vs bgr for otsu
rom-thom Jan 6, 2026
146b0e0
Merge branch 'main' into Thomas_refactor
rom-thom Jan 6, 2026
2a28bc9
Adding final tutches, like coloring coments ++
rom-thom Jan 6, 2026
1cae050
i fixed a warning coming from the dinosaur from toy story in asci art…
rom-thom Jan 7, 2026
213dc8b
Maching the read me
rom-thom Jan 7, 2026
61844d9
sadest chapter of vortex history: unfortunately the dinosaur from toy…
rom-thom Jan 7, 2026
8904c7c
spelling mistake
rom-thom Jan 7, 2026
82a5e2a
Spelling
rom-thom Jan 7, 2026
5490448
Fixing with precommit
rom-thom Jan 7, 2026
90dac02
Fixing some stuf, not all is done?
rom-thom Jan 8, 2026
c031c91
Final changes i hope
rom-thom Jan 8, 2026
9779ff9
We are saved, the dinosaur from toystory is back to life, and beter t…
rom-thom Jan 8, 2026
fd73f5e
Removing log files
rom-thom Jan 8, 2026
bc9b5f3
Fixing some of jørgens complaints
rom-thom Jan 9, 2026
e8d5e0f
fixing swich case for filtertype and try catch for running the filter…
rom-thom Jan 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,5 +51,60 @@ qtcreator-*
# Catkin custom files
CATKIN_IGNORE

.vscode/*
image-filtering/.vscode/*devel/
logs/
build/
bin/
lib/
msg_gen/
srv_gen/
msg/*Action.msg
msg/*ActionFeedback.msg
msg/*ActionGoal.msg
msg/*ActionResult.msg
msg/*Feedback.msg
msg/*Goal.msg
msg/*Result.msg
msg/_*.py
build_isolated/
devel_isolated/
*/launch/__pycache__

# Generated by dynamic reconfigure
*.cfgc
/cfg/cpp/
/cfg/*.py

# Ignore generated docs
*.dox
*.wikidoc

# eclipse stuff
.project
.cproject

# qcreator stuff
CMakeLists.txt.user

srv/_*.py
*.pcd
*.pyc
qtcreator-*
*.user

/planning/cfg
/planning/docs
/planning/src

*~

# Emacs
.#*

# Catkin custom files
CATKIN_IGNORE

.vscode/
log/
image-filtering/.vscode/*
155 changes: 100 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Image Filtering Node
[![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)
[![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)
[![codecov](https://codecov.io/github/vortexntnu/vortex-image-filtering/graph/badge.svg?token=6XHprkpUsR)](https://codecov.io/github/vortexntnu/vortex-image-filtering)

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.
Expand Down Expand Up @@ -31,96 +32,140 @@ Parameters can be set through a YAML file or dynamically adjusted at runtime.

## Implementing New Filters

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:
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:

### Step 1: Define Filter Parameters
### Step 1: Filter Enum

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

```cpp
struct YourFilterParams {
// Add necessary parameters here
int example_param;
enum class FilterType {
NoFilter,
Flip,
Unsharpening,
Erosion,
Dilation,
...
// Add your filter here
};
```

### Step 2: Add to FilterParams Structure

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.
### Step 2: Filter string
To access the filter through the yaml file we need to access it through a string. You need to add it as a string to map to the Enum in [image_processing.hpp](image-filtering/include/image_filters/image_processing.hpp)

```cpp
struct FilterParams {
std::string filter_type;
UnsharpeningFilterParams unsharpening;
ErodingFilterParams eroding;
DilatingFilterParams dilating;
WhiteBalancingFilterParams white_balancing;
EbusFilterParams ebus;
YourFilterParams your_filter; // Add your filter params here
static constexpr std::pair<std::string_view, FilterType> kFilterMap[] = {
{"no_filter", FilterType::NoFilter},
{"flip", FilterType::Flip},
{"unsharpening", FilterType::Unsharpening},
...

// Add your filter here
{"example", FilterType::Example},
{"unknown", FilterType::Unknown}
};
```

### Step 3: Create the Filter Function

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.
### Step 3: Define Filter Parameters

```cpp
void your_filter_function(const cv::Mat &original, cv::Mat &filtered, const FilterParams& filter_params) {
// Access your filter-specific parameters like this:
int example_param = filter_params.your_filter.example_param;
Each filter should have its own set of parameters encapsulated in a structure. Define this structure within [image_processing.hpp](image-filtering/include/image_filters/image_processing.hpp).

// Implement your filtering logic here
}
```cpp
struct ExampleParams{
// Add necessary filter parameters here
int example_int;
std::string example_string;
};
```

### Step 4: Register the Filter Function

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.
### Step 4: Add filter class

Below the filter parameters add a Class for your filter inheriting from the Filter class, with the same structure as shown below. This should also be in [image_processing.hpp](image-filtering/include/image_filters/image_processing.hpp)
```cpp
std::map<std::string, FilterFunction> filter_functions = {
{"no_filter", no_filter},
{"sharpening", sharpening_filter},
{"unsharpening", unsharpening_filter},
{"eroding", eroding_filter},
{"dilating", dilating_filter},
{"white_balancing", white_balance_filter},
{"ebus", ebus_filter},
{"your_filter", your_filter_function} // Add your filter here
class Example: public Filter{
public:
explicit Example(ExampleParams params): filter_params(params) {}
void apply_filter(const cv::Mat& original, cv::Mat& filtered) const override; // This is the filter itself
private:
ExampleParams filter_params;
};
```
Here you can add other filter specific stuff like storing variables that need to change between runs and so on.

### Step 5: Declare and Assign Parameters

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.

#### In the Node Constructor
### Step 5: Create the Filter Function

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.
Implement your filter function in [image_processing.cpp](image-filtering/src/image_processing.cpp). This function should take in the `cv::Mat` objects for the input and the filtered image, and change the filtered one according to your needs.

```cpp
ImageFilteringNode::ImageFilteringNode() : Node("image_filtering_node")
{
this->declare_parameter<std::string>("filter_params.your_filter.example_param", "default_value");
...
// Other parameters declarations
void Example::apply_filter(const cv::Mat& original, cv::Mat& filtered) const{
std::string example_str = this->filter_params.example_string;
int example_int = this->filter_params.example_int;
DoExample(original,filtered, example_str, example_int);
}
```
*If you need a helper function go to the [helperfunction](#adding-helper-functions) section of this page.


#### In the set_filter_params Function
### Step 6: Add to config file

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.
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:

```cpp
```yaml
filter_params:
filter_type: "example"

flip:
flip_code: 1
...
# Add your filter type here

example:
example_int: 5
example_string: "This is an example"
```


### Step 7: Declare and Assign Parameters

void ImageFilteringNode::set_filter_params(){
FilterParams params = filter_params_; // assuming filter_params_ is already defined in your class
In the constructor of your ROS 2 node, declare each of the new filter parameters using the `declare_parameter` function in [image_filtering_ros.cpp](image-filtering/src/image_filtering_ros.cpp). This declares the ros2 parameters and prepares the node to accept them at runtime through command line or the YAML configuration file.

```cpp
void ImageFilteringNode::declare_parameters() {
// Declare your parameters here
this->declare_parameter<int>("filter_params.example.example_int");
this->declare_parameter<std::string>("filter_params.example.example_string");
}
```

params.your_filter.example_param = this->get_parameter("filter_params.your_filter.example_param").as_string();
Then in the same file you make a new case in `set_filter_params` for your filter, to set the variables you just declared.
```cpp
void ImageFilteringNode::set_filter_params() {
...
// Retrieve other parameters and handle cases where parameters might not be provided
filter_params_ = params; // Update the filter parameters structure
RCLCPP_INFO(this->get_logger(), "Filter parameters updated for your_filter.");
switch (filter_type){

...
// Add case here
case FilterType::Example:
{
ExampleParams params;
params.example_int =
this->get_parameter("filter_params.example.example_int").as_int();
params.example_string =
this->get_parameter("filter_params.example.example_string").as_string();

filter_ptr = std::make_unique<Example>(params);
break;
}

}
}
```



#### Adding Helper functions

If you need helper functions for your filter, you can add the declaration to [utilities.hpp](image-filtering/include/image_filters/utilities.hpp), and then add the function definition to [utilities.cpp](image-filtering/src/utilities.cpp). There will be TODO(New filter) comments where you can add them. These functions are already included in the image_processing files.
1 change: 1 addition & 0 deletions image-filtering/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ set(LIB_NAME "${PROJECT_NAME}_component")
add_library(${LIB_NAME} SHARED
src/image_processing.cpp
src/image_filtering_ros.cpp
src/utilities.cpp
)

target_link_libraries(${LIB_NAME} PUBLIC
Expand Down
30 changes: 24 additions & 6 deletions image-filtering/config/image_filtering_params.yaml
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
/**:
ros__parameters:
sub_topic: "/downwards_camera/image_raw"
sub_topic: "/fls_publisher/display_mono"
pub_topic: "/filtered_image"
input_encoding: "mono8"
output_encoding: "mono8"

filter_params:
filter_type: "otsu"
filter_type: "example"
flip:
flip_code: 1
unsharpening:
blur_size: 8
erosion:
size: 1
dilation:
size: 1
size: 3
white_balancing:
contrast_percentage: 0.1
contrast_percentage: 10.0
ebus:
erosion_size: 2
blur_size: 30
Expand All @@ -26,8 +28,24 @@
gamma_auto_correction: true
gamma_auto_correction_weight: 4.0
otsu_segmentation: true
erosion_size: 10
dilation_size: 10
erosion_size: 2
dilation_size: 2
overlap:
percentage_threshold: 20.0 # Percentage (0-100) to cap the pixel intensity difference
median_binary: # finds the median of each n x n square around each pixel
kernel_size: 3 # must be odd >= 1
threshold: 100 # [0, 255]
invert: false
binary:
threshold: 20. # in percent
maxval: 255.
invert: true

# TODO(New filter): add your filterparameters here
example:
example_int: 1
example_string: "Get filtered"


# Filter params should reflect the FilterParams struct
# defined in /include/image_filters/image_processing.hpp
13 changes: 5 additions & 8 deletions image-filtering/include/image_filters/image_filtering_ros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include <cv_bridge/cv_bridge.h>
#include <spdlog/spdlog.h>
#include <spdlog/fmt/ostr.h>
#include <fmt/color.h>
#include <memory>
#include <rclcpp/parameter_event_handler.hpp>
#include <rclcpp/qos.hpp>
Expand All @@ -11,6 +13,7 @@
#include <string>
#include "image_processing.hpp"


class ImageFilteringNode : public rclcpp::Node {
public:
explicit ImageFilteringNode(const rclcpp::NodeOptions& options);
Expand Down Expand Up @@ -99,16 +102,10 @@ class ImageFilteringNode : public rclcpp::Node {
std::string image_topic_;

/**
* @brief The filter parameters
*
*/
FilterParams filter_params_;

/**
* @brief filter to apply
* @brief Pointer to the filter object
*
*/
std::string filter_;
std::unique_ptr<Filter> filter_ptr;
};

#endif // IMAGE_FILTERS__IMAGE_FILTERING_ROS_HPP_
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// FilterType ImageFilteringNode::create_binary_filter(){

// }
Loading
Loading