vspline 1.1.0
Generic C++11 Code for Uniform B-Splines
Classes | Namespaces | Functions
filter.h File Reference

generic implementation of separable filtering for nD arrays More...

#include <vector>
#include "common.h"

Go to the source code of this file.

Classes

struct  vspline::bundle< dtype, vsize >
 class 'bundle' holds all information needed to access a set of vsize 1D subarrays of an nD array. This is the data structure we use to tell the buffering and unbuffering code which data we want it to put into the buffer or distribute back out. The buffer itself holds the data in compact form, ready for vector code to access them at maximum speed. More...
 
class  vspline::buffer_handling< _vtype, _dtype, _vsize >
 buffer_handling provides services needed for interfacing with a buffer of simdized/goading data. The init() routine receives two views: one to a buffer accepting incoming data, and one to a buffer providing results. Currently, all filters used in vspline operate in-place, but the two-argument form leaves room to manoevre. get() and put() receive 'bundle' arguments which are used to transfer incoming data to the view defined in in_window, and to transfer result data from the view defined in out_window back to target memory. More...
 
struct  vspline::detail::separable_filter< input_array_type, output_array_type, stripe_handler_type >
 struct separable_filter is the central object used for 'wielding' filters. The filters themselves are defined as 1D operations, which is sufficient for a separable filter: the 1D operation is applied to each axis in turn. If the data themselves are 1D, this is inefficient if the run of data is very long: we'd end up with a single thread processing the data without vectorization. So for this special case, we use a bit of trickery: long runs of 1D data are folded up, processed as 2D (with multithreading and vectorization) and the result of this operation, which isn't correct everywhere, is 'mended' where it is wrong. If the data are nD, we process them by buffering chunks collinear to the processing axis and applying the 1D filter to these chunks. 'Chunks' isn't quite the right word to use here - what we're buffering are 'bundles' of 1D subarrays, where a bundle holds as many 1D subarrays as a SIMD vector is wide. this makes it possible to process the buffered data with vectorized code. While most of the time the buffering will simply copy data into and out of the buffer, we use a distinct data type for the buffer which makes sure that arithmetic can be performed in floating point and with sufficient precision to do the data justice. With this provision we can safely process arrays of integral type. Such data are 'promoted' to this type when they are buffered and converted to the result type afterwards. Of course there will be quantization errors if the data are converted to an integral result type; it's best to use a real result type. The type for arithmetic operations inside the filter is fixed via stripe_handler_type, which takes a template argument '_math_ele_type'. This way, the arithmetic type is distributed consistently. Also note that an integral target type will receive the data via a simple type conversion and not with saturation arithmetics. If this is an issue, filter to a real-typed target and process separately. A good way of using integral data is to have integral input and real-typed output. Promoting the integral data to a real type preserves them precisely, and the 'exact' result is then stored in floating point. With such a scheme, raw data (like image data, which are often 8 or 16 bit integers) can be 'sucked in' without need for previous conversion, producing filtered data in, say, float for further processing. More...
 

Namespaces

namespace  vspline
 
namespace  vspline::detail
 

Functions

template<class stype , class ttype , size_t vsize>
void vspline::move (const bundle< stype, vsize > &src, ttype *trg, std::ptrdiff_t trg_stride)
 move bundle data to compact memory More...
 
template<class stype , class ttype , size_t vsize>
void vspline::move (const bundle< stype, vsize > &src, ttype *trg, std::ptrdiff_t trg_stride, int ni)
 
template<class stype , class ttype , size_t vsize>
void vspline::move (const stype *src, std::ptrdiff_t src_stride, const bundle< ttype, vsize > &trg)
 move data from compact memory to bundle More...
 
template<class stype , class ttype , size_t vsize>
void vspline::move (const stype *src, std::ptrdiff_t src_stride, const bundle< ttype, vsize > &trg, int ni)
 
template<typename source_view_type , typename target_view_type , typename stripe_handler_type >
void vspline::detail::present (vspline::atomic< std::ptrdiff_t > *p_tickets, const source_view_type *p_source, target_view_type *p_target, const typename stripe_handler_type::arg_type *p_args, int axis)
 'present' feeds 'raw' data to a filter and returns the filtered data. In order to perform this task with maximum efficiency, the actual code is quite involved. More...
 
template<typename source_view_type , typename target_view_type , typename stripe_handler_type >
void vspline::detail::vpresent (vspline::atomic< std::ptrdiff_t > *p_tickets, const std::vector< source_view_type > *p_source, std::vector< target_view_type > *p_target, const typename stripe_handler_type::arg_type *p_args, int axis)
 vpresent is a variant of 'present' processing 'stacks' of arrays. See 'present' for discussion. This variant of 'present' will rarely be used. Having it does no harm but if you study the code, you may safely ignore it unless you are actually using single-axis filtering of stacks of arrays. the code is structurally similar to 'present', with the extra complication of processing stacks instead of single arrays. More...
 
template<typename in_type , typename out_type , unsigned int D, class filter_type , typename ... types>
void vspline::filter (const vigra::MultiArrayView< D, in_type > &input, vigra::MultiArrayView< D, out_type > &output, types ... args)
 vspline::filter is the common entry point for filter operations in vspline. This routine does not yet do any processing, it's purpose is to convert it's arguments to 'canonical' format and then call the actual filter code in namespace detail. It also determines the type used for arithmetic operations. The type specification for input and output assures that only arrays with the same dimensionality are accepted, and a static assertion makes sure the number of channels match. canonical form means that input and output value type are either fundamental (for single-channel data) or TinyVectors of a fundamental data type. This way, the input and output is presented in a neutral form, ignoring all specifics of T1 and T2, which may be TinyVectors, complex, RGBValue etc. More...
 

Detailed Description

generic implementation of separable filtering for nD arrays

This body of code provides the application of separable filters, not the filters themselves. Most essential for vspline is the use for b-spline prefiltering, see prefilter.h for the implementation of the specific filter.

Another type of filter used by and provided by vspline is general separable convolution, which, inside vspline, is used for reconstruction of the original data from b-spline coefficients, see convolve.h.

The code in this file is what I call 'wielding' code. It's function is to present the data in such a fashion that the code needed for the actual filter is a reasonably trivial 1D operation. 'Presenting' the data is a complex operation in vspline: the data are distributed to a set of worker threads, and they are restructured so that they can be processed by the processor's vector units. All of this is optional and transparent to the calling code. The 'wielding' code in this file is structurally similar to the code in transform.h, but here we use specific buffering operations which would make no sense there: for separable filtering, we have to preserve the adjacency of the data along the processing axis and present it to the filter, which is unnecessary for transformations, where each value can be processed in isolation.

Most of the functionality in this file is in namespace detail, signalling that it is not meant to be called from outside. Class buffer_handling and the data types it uses to interface with nD memory are the exception, since they are meant to be inherited/used to implement specific filters.

At the bottom of the file there's a free function template called 'filter'. This is what other code will normally call.

Definition in file filter.h.