API Reference / Adding Stabilization Algorithms
Introduction
The stabilization algorithms dictate how the interpolated orientations for each frame will be smoothed out and readjusted. Generally, each algorithm can be understood as a filter that takes a vector of quaternion-timestamp value pairs and delivers a vector of corrected orientations whose correction can be tuned by certain given parameters. The steps to implement a new stabilization algorithm are:
- Define the new stabilization algorithm.
- Define the stabilizer parameters for the algorithm.
Next, we will showcase how to implement any algorithm following the previous steps.
Define the Stabilization Algorithm
The RidgeRun Video Stabilization Library is extensible and can adopt different stabilization algorithms. Apart from the usual constructor method, the IStabilizer interface describes how to implement new algorithms with the following methods:
- The Apply method that implements the core of the algorithm.
- The Reset method that updates the stabilization algorithm parameters.
Additionally, the algorithm can be included in the static builder method of the interface.
Add the Constructor Method
This method should take a shared pointer to the corresponding stabilization parameters instance and return it. Since this parameter is also derived, casting it to validate the type dynamically is necessary.
ExampleStabilizer::ExampleStabilizer(const std::shared_ptr<ExampleParams> params) { std::shared_ptr<ExampleParams> casted = std::dynamic_pointer_cast<ExampleParams>(params); if (casted == nullptr) { throw RuntimeError{RuntimeError::IncompatibleParameters, "The runtime settings are incompatible. Use " "ExampleParams"}; } else { params_ = casted; } }
Extend Static Builder
To enable the IStabilizer interface to instantiate custom algorithms, it is required to:
- Extend the StabilizerAlgorithms enumerator class.
- Add the corresponding case to the switch in the builder method.
Extend StabilizerAlgorithms enum
enum class StabilizerAlgorithms { kSphericalExponential = 0, kFixedHorizon, /* add new algorithm */ ExampleStabilizer, };
Modify Builder Method
std::shared_ptr<IStabilizer> IStabilizer::Build( const StabilizerAlgorithms algorithm, const std::shared_ptr<StabilizerParams> params) { switch (algorithm) { case StabilizerAlgorithms::kSphericalExponential: return std::make_shared<SphericalExponential>(params); case StabilizerAlgorithms::kFixedHorizon: return std::make_shared<FixedHorizon>(params); break; case StabilizerAlgorithms::ExampleStabilizer: return std::make_shared<ExampleStabilizer>(params); break; default: return nullptr; } }
Define the Apply Method
This method must receive an input vector of quaternion-timestamp value pairs as the first parameter. The quaternions must be in double format, and the timestamps need to be 64-bit unsigned integers in microsecond units. The second parameter corresponds to the framerate of the video stream to correct, and it is generally required by stabilization algorithms. This second parameter must be at least a length of 3, each corresponding to the previous sample (index 0), current sample (index 1) and future samples (index 2).
RuntimeError ExampleStabilizer::Apply( std::vector<Quaternion<double>>& correction, const std::vector<std::pair<Quaternion<double>, uint64_t>>& interpolated, const double rate) { RuntimeError ret{}; /* Algorithm here */ return ret; }
Define the Reset Method
This method only needs to specify how to dynamically cast the parameters shared pointer into the stabilizer algorithm class.
RuntimeError ExampleStabilizer::Reset( const std::shared_ptr<StabilizerParams> params) { RuntimeError ret{}; std::shared_ptr<ExampleParams> casted = std::dynamic_pointer_cast<ExampleParams>(params); if (casted == nullptr) { throw RuntimeError{RuntimeError::IncompatibleParameters, "The runtime settings are incompatible. Use " "ExampleParams"}; } else { params_ = casted; return ret; } }
Define the Stabilization Parameters
The stabilization parameters describe what will be the initial orientation that the algorithm should stabilize towards, and the smoothing degree desired. These parameters are extensible given the case an algorithm requires additional parameters.
struct ExampleParams : public StabilizerParams { /** * additional parameter. */ double additional_ = 0; ExampleParams(double smoothing, Quaternion<double> initial_orientation, double additional) : StabilizerParams{smoothing, initial_orientation}, additional_{additional} {} /** * @brief Destroy the ExampleParams instance. */ virtual ~ExampleParams() = default; };