Skip to content

vortexntnu/vortex-image-filtering

Repository files navigation

Image Filtering Node

Industrial CI pre-commit.ci status codecov

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.

Features

  • Multiple Filters: Supports sharpening, unsharpening, eroding, dilating, white balancing, and a custom "ebus" filter.
  • Dynamic Reconfiguration: Allows for runtime changes to filter parameters and subscribed image topics via ROS 2 parameters.
  • Parameter-Driven Configuration: Configures filter types and specific attributes through ROS 2 parameters.

Configuration

Configure the node using ROS 2 parameters:

  • image_topic: Topic from which the node will subscribe to image messages.
  • filter_params.filter_type: Specifies the filter to apply. Current options include:
    • nofilter
    • sharpening
    • unsharpening
    • eroding
    • dilating
    • white_balancing
    • ebus
  • Other filter-specific parameters such as blur_size, size, contrast_percentage, can be configured through parameter filter_params.{filter_name}.{param_name}

Parameters can be set through a YAML file or dynamically adjusted at runtime.

Additional filters

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. There should be //TODO(New filter) comments where you add your filter:

Step 1: Filter Enum

You should define your filtertype in the filtertype enum in typedef.hpp

enum class FilterType {
  NoFilter,
  Flip,
  Unsharpening,
  Erosion,
  Dilation,
  ...
  // Add your filter here
};

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.

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 2: Make the filter header

Each filter should have its own headerfile asosiated with it. You can add this in the 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):

#ifndef LIB__FILTERS__EXAMPLE_HPP_
#define LIB__FILTERS__EXAMPLE_HPP_
#include "abstract_filter_class.hpp"


// Insert code here ...


#endif // LIB__FILTERS__EXAMPLE_HPP_

This new file needs to be added to all_filters.hpp.

#ifndef LIB__FILTERS__EXAMPLE_HPP_
#define LIB__FILTERS__EXAMPLE_HPP_

// Add your filter to the top of this file:
#include "lib/filters/your_filter.hpp"

#include "lib/filters/example.hpp"
#include "lib/filters/no_filter.hpp"


#endif // LIB__FILTERS__EXAMPLE_HPP_

Step 3: Define Filter Parameters

Each filter should have its own set of parameters encapsulated in a structure. Define this structure within your_filter.hpp.

struct ExampleParams{
    // Add necessary filter parameters here
    int example_int;
    std::string example_string;
};

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.

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: Define the filter function

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 section of this page. Otherwise you can add the function definition just below the class definition like this.

inline 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);
}

Step 6: Add to config file

In the image_filtering_params.yaml file you add your filter and filterparameters for easily interfacing with the filters:

    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

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, for your filter.

void ImageFilteringNode::set_filter_params() {
    ...
    switch (filter_type){

        ...

        case FilterType::Example: {
            ExampleParams params;
            params.example_int =
                declare_and_get<int>("filter_params.example.example_int");
            params.example_string =
                declare_and_get<std::string>(
                    "filter_params.example.example_string");

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

Helper functions

Define the apply filter function

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 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, to the add_library(${CORE_LIB} SHARED part.

Make and use helperfunctions

If you are making a function that is useful for many different filters, then you can add the declaration to utilities.hpp, and the definition to 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

About

Ros2 package for image filtering

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •