This page offers a tutorial for writing an own processing step for cedar and including that step into cedar via a plugin libary.
Tutorial: One Small Step
In this section, we will give a brief introduction on how to create a new processing step that adheres to the principles of the cedar processing framework.
The first thing to do when developing a new processing step (cedar::proc::Step) is to think about what the new step is supposed to do. For now, we pick a fairly simple example: we will create a processing step that receives two matrices and adds them together.
Setting up and building your project
Each processing step consists of single C++ class. To prevent writing too much code from hand templates for such a cedar class can be generated with the help of a python script. However in order to use other cedar functions and classes the new class needs to be linked against your compiled cedar version. Therefore we will start with setting up our workspace.
- Create a new folder, where you will place all your files belonging to the plugin. We will call this folder PLUGIN_ROOT_DIRECTORY for the rest of the tutorial.
- Copy the files cedarProject.cmake, exampleCMakeLists.txt and project.conf.example from CEDAR_ROOT_DIRECTORY/templates/project to the PLUGIN_ROOT_DIRECTORY.
- Rename project.conf.example to project.conf and open it. Change the entry in the variable CEDAR_HOME to your personal path to the CEDAR_ROOT_DIRECTORY. If you build your cedar version in another folder than build you also need to uncomment and specify the CEDAR_BUILD_DIR variable.
- Rename exampleCMakeLists.txt to CMakeLists.txt and open it. Remove the # in front of the line "cedar_project_add ...", in front of the "LIBRARY ..." line and in front of the last line with the close brackets ")". Now think of a name for your plugin and replace "folder" in the "LIBRARY ..." line with your name. We will call this PLUGIN_NAME from now on.
- In the PLUGIN_ROOT_DIRECTORY create a folder with the name PLUGIN_NAME.
- Now we will use the python script to generate the step class. Open a terminal at CEDAR_ROOT_DIRECTORY/tools. Think of a name for your step (In this tutorial we will choose the name "SimpleSummation"). Execute the cedar_create_class.py script with the step name as a parameter (type "./cedar_create_class.py SimpleSummation"). Proceed with "y" and the following three files will be generated in the CEDAR_ROOT_DIRECTORY/tools directory:SimpleSummation.h,SimpleSummation.fwd.h andSimpleSummation.cpp. Move the three files to your folder named PLUGIN_NAME in the PLUGIN_ROOT_DIRECTORY
- Now everything should be set up to compile this library. In order to do that create a folder named "build" in your PLUGIN_ROOT_DIRECTORY. Open a terminal in the build folder and type: "cmake ..". If the CEDAR_HOME directory was set up correctly this script should run through without errors. Afterwards type "make" to compile your library. It is now located in the build directory of the Plugin.
If the above setup worked we can now continue to add our own personal code to the generated .cpp and .h files to give the new step some functionality.
A New Class
First, let's have a look at our new class SimpleSummation. In order for it to work within the framework, it has to inherit cedar::proc::Step, so in the class header include the Step header file and inherit from cedar::proc::Step.
#include <cedar/processing/Step.h> // if we are going to inherit from cedar::proc::Step, we have to include the header
// FORWARD DECLARATIONS
#include <cedar/auxiliaries/MatData.fwd.h> // forward declaration for the class MatData that we will use in our step.
class SimpleSummation : public cedar::proc::Step
// we assume that you declare all members and functions used throughout the tutorial here
Let's begin by implementing the constructor in the .cpp File. From our planning stage, we already know what the inputs and outputs of the step are going to be: we need two inputs (the matrices we plan to add up) and one output (the sum). In terms of the processing framework, this is expressed in the constructor:
// CEDAR INCLUDES
#include <cedar/processing/ExternalData.h> // getInputSlot() returns ExternalData
#include <cedar/auxiliaries/MatData.h> // this is the class MatData, used internally in this step
: // <- the colon starts the member initialization list
mOutput(new cedar::aux::MatData(cv::Mat::zeros(1, 1, CV_32F)))
/* Declare both inputs; the "true" means that the inputs are mandatory, i.e.,
the step will not run unless both of the inputs are connected to data.
// Declare the output and set it to the output matrix defined above.
That's all we need to do in the constructor for now. Don't forget to declare a member variable mOutput of type cedar::aux::MatDataPtr in the header file SimpleSummation.h under private members (Add the line: "cedar::aux::MatDataPtr mOutput;"). In order to be able to use the step, we also have to tell it what to compute; for this, we implement the compute function:
// The arguments are unused here
void SimpleSummation::compute(const cedar::proc::Arguments&)
// Using data like this is more convenient.
cv::Mat& sum = mOutput->getData();
// Get a pointer to the first input.
cedar::aux::ConstDataPtr op1 = this->getInputSlot("operand1")->getData();
/* Retreive its stored data and add it to the sum.
Note, that we assume that op1 can be cast to MatData!
The call to the clone function is necessary to avoid writing into the input matrix.
sum = op1->getData<cv::Mat>().clone();
// Same as above for the second input.
cedar::aux::ConstDataPtr op2 = this->getInputSlot("operand2")->getData();
sum += op2->getData<cv::Mat>().clone();
// In a console application, this lets us see that the computation is actually happening.
std::cout << "A sum was computed!" << std::endl;
Again do not forget to declare the compute function as a private void method in the header-file: Add the line: "void compute(const cedar::proc::Arguments&);"
Note, that the compute function does not check that operand1 and operand2 are valid, non-null pointers. This is done automatically by the framework, because we specified the inputs to be mandatory in the constructor. Something that we do assume here is that the data connected to the input slots can be cast to cedar::aux::MatData.
Tutorial: Plug In and Play
As a prepraration for using the SimpleSummation step in cedar, we first have to group our declarations into a plugin. These plugins can then be loaded from cedar and used for creating architecture files in a comfortable way.
Let us assume that our library compiles to libSimpleSummation.so and, so far, contains the code from the previous tutorials in SimpleSummation.h and SimpleSummation.cpp. In order to turn this library into a plugin, we add two more files: plugin.h and plugin.cpp to our PLUGIN_NAME directory. The plugin.h file must always contain at least this:
CEDAR_DECLARE_PROC_PLUGIN_FUNCTION(void pluginDeclaration(cedar::aux::PluginDeclarationListPtr plugin));
#endif // SIMPLE_SUMMATION_PLUGIN_H
Upon loading the plugin, the processing framework calls the function declared here and imports everything declared in the cedar::proc::PluginDeclaration. Therefore, we declare our summation step in this function:
void pluginDeclaration(cedar::aux::PluginDeclarationListPtr plugin)
After recompiling, now, the plugin is ready for use!
Using the Summation Step in cedar's GUI
Now it is time to include the summation plugin we created above. First, click on "Tools" in the main menu, then click on "Manage plugins ...". In the dialog that opens up, click "add", navigate to the library of our plugin and select the libSimpleSummation.so file located in the build directory. Once you click "ok", the plugins are loaded into the framework. Now, in the "Elements" tab, you should be able to find our plugin in the category "Utilities". Now you simply drag our summation step and for example two Gauss inputs into the white drawing field. Then connect the Gauss inputs to the summation step by dragging a line from the data slot (little circle) of the Gauss inputs to the input of the summation steps (also little circles). Now right click on your SimpleSummation Step to plot all the inputs and outputs and verify the correctness of your code.