-
Notifications
You must be signed in to change notification settings - Fork 1
Framework
The vision system used by the unball team uses its own computer vision framework. This page provides information about how this framework works and how to use it.
The purpose of the framework is to provide a simple, highly customizable interface for the implementation of multiple object tracking algorithms.
The framework consists of three steps: segmentation, identification and tracking. Both the segmentation and identification steps work by keeping lists of implemented algorithms. These algorithms are to be implemented by the user, and may be vastly different. The framework requires only that they follow a determined structure, that will be described ahead. This structure is, of course, extensible.
The segmentation step requires an algorithm that operates on the raw image given to the framework, and produces another image as the output.
The identification step requires an algorithm that operates on the output of a segmentation algorithm, and produces information about the object(s) whose position(s) are being identified.
In the tracking step each tracked object takes the results from a given identification algorithm and uses it to track itself.
The information about each object (the algorithms it uses) is stored in a configuration file, vision.yaml
. This file follows a predefined structure, that is described in detail on the next section.
In order to create a segmentation algorithm, you need to create a class that contains the algorithm's implementation. This class has the following requirements:
- It needs to publicly inherit from the base class
SegmentationAlgorithm
; - It needs to declare its own type, within its public members, using the macro
ALGORITHM_TYPE
; - It needs to register itself as a segmentation algorithm, within its private members, using the macro
REGISTER_ALGORITHM_DEC
; - It needs to complete the self-registration using the macro
REGISTER_ALGORITHM_DEF
on the class'.cpp
file. - It needs to implement the
void run()
public method. - It needs to write its output to the
cv::Mat output_image_
field.
If the algorithm requires any logic prior to its continuous execution in the run()
method, the class may implement the void init()
public method. The class should not implement a constructor.
In order to create an identification algorithm, you need to create a class to contain the algorithm's implementation. This class has the following requirements:
- It needs to publicly inherit from the base class
IdentificationAlgorithm
; - It needs to declare its own type, within its public members, using the macro
ALGORITHM_TYPE
; - It needs to register itself as a segmentation algorithm, within its private members, using the macro
REGISTER_ALGORITHM_DEC
; - It needs to complete the self-registration using the macro
REGISTER_ALGORITHM_DEF
on the class'.cpp
file. - It needs to implement the
void run()
public method. - It needs to write its output to the
std::shared_ptr<IdentificationOutput> output_info_
field.
Like the segmentation class , if the identification algorithm requires any logic prior to its continuous execution in the run()
method, the class may implement the void init()
public method. The class should not implement a constructor.
In order to have the framework track an object, all you need to do is edit the configuration file, vision.yaml
. Here is an example of this file:
vision:
object_list:
- "dummy_object"
dummy_object:
segmentation_algorithm: "DummySegmentationAlgorithm"
identification_algorithm: "DummyIdentificationAlgorithm"
The first thing to note here is the object_list
field. This field contains the list of objects that are currently being tracked. After this field comes the description for each object. Within its description the object must inform the segmentation and identification algorithms it currently uses. Upon execution, the framework will parse this config file and create all objects on the object_list
, as well as their algorithms.
Note that having the description for an object that is not on the object list will not result in error. This object, however, will not be tracked, and its algorithms will not be created if they're not being used by other objects.
The framework contains two dummy algorithms, DummySegmentationAlgorithm and DummyIdentificationAlgorithm. Let's first take a look at the dummy segmentation algorithm:
dummy_segmentation_algorithm.hpp
:
class DummySegmentationAlgorithm : public SegmentationAlgorithm
{
public:
ALGORITHM_TYPE(DummySegmentationAlgorithm);
void run();
private:
REGISTER_ALGORITHM_DEC(DummySegmentationAlgorithm);
};
Note the usage of the macros ALGORITHM_TYPE
and REGISTER_ALGORITHM_DEC
. The first macro defines the algorithm's name_
field, and the second one registers the class as a valid segmentation algorithm.
dummy_segmentation_algorithm.cpp
:
#include <vision/dummy_segmentation_algorithm.hpp>
REGISTER_ALGORITHM_DEF(DummySegmentationAlgorithm);
void DummySegmentationAlgorithm::run()
{
ROS_INFO("Running dummy segmentation algorithm");
RawImage::getInstance().getRawImage().copyTo(output_image_);
}
Note the usage of the macro REGISTER_ALGORITHM_DEF
. This macro completes the algorithm's registration as a valid algorithm. Also, note that the run()
method doesn't actually do anything: it only copies the raw image as its output.
Now, let's take a look at the DummyIdentificationAlgorithm class:
dummy_identification_algorithm.hpp
:
class DummyIdentificationAlgorithm : public IdentificationAlgorithm
{
public:
ALGORITHM_TYPE(DummyIdentificationAlgorithm);
void run();
private:
REGISTER_ALGORITHM_DEC(DummyIdentificationAlgorithm);
};
This declaration is a lot like the segmentation algorithm. The macros in use serve the same purpose. Let's move on.
dummy_identification_algorithm.cpp
:
#include <vision/dummy_identification_algorithm.hpp>
REGISTER_ALGORITHM_DEF(DummyIdentificationAlgorithm);
void DummyIdentificationAlgorithm::run()
{
output_info_ = std::make_shared<IdentificationOutput>();
output_info_->object_center = cv::Point(10,10);
}
Again, the implementation file resembles the previous segmentation one. A key difference here is the nature of the identification algorithm's output, as it is a shared pointer. This allows overriding of the identification output if you need it.