vspline 1.1.0
Generic C++11 Code for Uniform B-Splines
|
defines class bspline More...
Go to the source code of this file.
Classes | |
struct | vspline::bspline_base< _dimension > |
struct bspline is the object in vspline holding b-spline coefficients. In a way, the b-spline 'is' it's coefficients, since it is totally determined by them - while, of course, the 'actual' spline is an n-dimensional curve. So, even if this is a bit sloppy, I often refer to the coefficients as 'the spline', and have named struct bspline so even if it just holds the coefficients. More... | |
struct | vspline::bspline< _value_type, _dimension > |
class bspline now builds on class bspline_base, adding coefficient storage, while bspline_base provides metadata handling. This separation makes it easier to generate classes which use the same metadata scheme. One concrete example is a class to type-erase a spline (not yet part of the library) which abstracts a spline, hiding the type of it's coefficients. Such a class can inherit from bspline_base and initialize the base class in the c'tor from a given bspline object, resulting in a uniform interface to the metadata. class bspline takes an additional template argument: the value type. This is the type of the coefficients stored in the spline, and it will typically be a single fundamental type or a small aggregate - like a vigra::TinyVector. vspline uses vigra's ExpandElementResult mechanism to inquire for a value type's elementary type and size, which makes it easy to adapt to new value types because the mechanism is traits-based. More... | |
Namespaces | |
namespace | vspline |
Typedefs | |
template<class spline_type , typename rc_type > | |
using | vspline::bspl_coordinate_type = vspline::canonical_type< rc_type, spline_type::dimension > |
using declaration for a coordinate suitable for bspline, given elementary type rc_type. This produces the elementary type itself if the spline is 1D, a TinyVector of rc_type otherwise. More... | |
template<class spline_type > | |
using | vspline::bspl_value_type = typename spline_type::value_type |
using declaration for a bspline's value type More... | |
defines class bspline
class bspline is an object to contain a b-spline's coefficients and some metadata in one handy package. It also provides easy access to b-spline prefiltering. The idea is that user code establishes a bspline object representing the data at hand and then proceeds to create 'evaluators' to evaluate the spline. You may be reminded of SciPy's bisplrep object, and I admit that SciPy's bspline code has been one of my inspirations.
It attempts to do 'the right thing' by automatically creating suitable helper objects and parametrization so that the spline does what it's supposed to do. Most users will not need anything else, and using class bspline is quite straightforward. It's quite possible to have a b-spline up and running with a few lines of code without even having to make choices concerning it's parametrization, since there are sensible defaults for everything. At the same time, pretty much everything can be parametrized.
Note that class bspline does not provide evaluation of the spline. To evaluate, objects of class evaluator (see eval.h) are used, which construct from a bspline object and additional parameters, like, whether to calculate the spline's value or it's derivative(s) or whether to use optimizations for special cases.
While using 'raw' coefficient arrays with an evaluation scheme which applies boundary conditions is feasible and most memory-efficient, it's not so well suited for very fast evaluation, since the boundary treatment needs conditionals, and 'breaks' uniform access, which is especially detrimental when using vectorization. So vspline uses coefficient arrays with a few extra coefficients 'framing' or 'bracing' the 'core' coefficients. Since evaluation of the spline looks at a certain small section of coefficients (the evaluator's 'support'), the bracing is chosen so that this lookup will always succeed without having to consider boundary conditions: the brace is set up to make the boundary conditions explicit, and the evaluation can proceed blindly without bounds checking. With large coefficient arrays, the little extra space needed for the brace becomes negligible, but the code for evaluation becomes faster and simpler. In effect, 'bracing' is taken a little bit further than merely providing enough extra coefficients to cover the support: additional coefficients are produced to allow for the spline to be evaluated without bounds checking
This makes the code more robust: being very strict about the ends of the defined range can easily result in quantization errors producing out-of-bounds access to the coefficient array, so the slightly wider brace acts as a safeguard. While the 'brace' has a specific size which depends on the parameters (see get_left_brace_size() and get_right_brace_size()) - there may be even more additional coefficients if this is needed (see parameter 'headroom'). All additional coefficients around the core form the spline's 'frame'. So the frame is always at least as large as the brace. Adding the frame around the coefficient array uses extra memory. For low spline dimensions, this does not 'cost much', but with rising dimension, the extra coefficients of the frame take up more and more space, and the method becomes impractical for splines with very many dimensions, which you should keep at the back of your mind if you intend to use vspline for higher-dimensional splines. This is due to the geometrical fact that with rising dimensionality the 'surface' of an object becomes proportionally larger, and the additional coefficients envelope the surface of the coefficient array.
class bspline handles two views to the coefficients it operates on, these are realized as vigra::MultiArrayViews, and they share the same storage:
Probably the most common scenario is that the source data for the spline are available from someplace like a file. Instead of reading the file's contents into memory first and passing the memory to class bspline, there is a more efficient way: a bspline object is set up first, with the specification of the size of the incoming data and the intended mode of operation. The bspline object allocates the memory it will need for the purpose, but doesn't do anything else. The 'empty' bspline object is then 'filled' by the user by putting data into it's 'core' area. Subsequently, prefilter() is called, which converts the data to b-spline coefficients. This way, only one block of memory is used throughout, the initial data are overwritten by the coefficients, operation is in-place and most efficient. This method works well with image import functions from vigraimpex: vigraimpex accepts vigra::MultiArrayViews as target for image loading, so the 'core' of a bspline object can be directly passed to vigraimpex to be filled with image data.
If this pattern can't be followed, there are alternatives:
Definition in file bspline.h.