|
template<class filter_args > |
void | operator() (const input_array_type &input, output_array_type &output, const filter_args &handler_args, int njobs=vspline::default_njobs) const |
| this is the standard entry point to the separable filter code for processing all axes of an array. first we use a dispatch to separate processing of 1D data from processing of nD data. More...
|
|
template<typename ... types> |
void | _on_dimension (std::true_type, types ... args) const |
|
template<typename ... types> |
void | _on_dimension (std::false_type, types ... args) const |
|
template<typename in_vt , typename out_vt > |
void | _process_1d (const in_vt &input, out_vt &output, const std::vector< typename stripe_handler_type::arg_type > &handler_args, int njobs) const |
| specialized processing of 1D input/output. We have established that the data are 1D. we have received a std::vector of handler arguments. It has to contain precisely one element which we unpack and use to call the overload below. More...
|
|
template<typename in_vt , typename out_vt > |
void | _process_1d (const in_vt &input, out_vt &output, int axis, const typename stripe_handler_type::arg_type &handler_args, int njobs) const |
| specialized processing of 1D input/output. We have established that the data are 1D and we have a single handler argument. This routine may come as a surprise and it's quite long and complex. The strategy is this: More...
|
|
template<typename in_vt , typename out_vt > |
void | _process_1d (const in_vt &input, out_vt &output, const typename stripe_handler_type::arg_type &handler_args, int njobs) const |
|
void | _process_nd (const input_array_type &input, output_array_type &output, const std::vector< typename stripe_handler_type::arg_type > &handler_args, int njobs) const |
| specialized processing of nD input/output. We have established that the data are nD. Now we process the axes in turn, passing the per-axis handler args. More...
|
|
void | operator() (const input_array_type &input, output_array_type &output, int axis, const typename stripe_handler_type::arg_type &handler_args, int njobs=vspline::default_njobs) const |
| this operator() overload for single-axis processing takes plain arrays for input and output, they may be either 1D or nD. again we use _on_dimension, now with a different argument signature (we have 'axis' now). As _on_dimension is a variadic template, we 'reemerge' in the right place. More...
|
|
template<typename ... types> |
void | _process_nd (types ... args) const |
| processing of nD input/output. we have established that the data are nD. now we look at the data type. If the data are multi-channel, they need to be element-expanded for further processing, which is done by '_on_expand'. Note that there are two variants of _on_expand, one for plain arrays and one for stacks of arrays, which are coded after the operator() overload taking stacks of arrays further down. More...
|
|
template<typename in_t , typename out_t > |
void | _on_expand (std::false_type, const in_t &input, out_t &output, int axis, const typename stripe_handler_type::arg_type &handler_args, int njobs) const |
| variant of _on_expand for single arrays. this overload is called if the data are multi-channel. we element-expand the arrays, then call the single-channel overload below More...
|
|
template<typename in_t , typename out_t > |
void | _on_expand (std::true_type, const in_t &input, out_t &output, int axis, const typename stripe_handler_type::arg_type &handler_args, int njobs) const |
| Variant of _on_expand for single arrays. This is the single-channel overload. The arrays now hold fundamentals, either because that was their original data type or because they have been element-expanded. Now we finally get to do the filtering. Note how we introduce input and output as templates, since we can't be sure of their type: they may or may not have been element-expanded. More...
|
|
void | operator() (const std::vector< input_array_type > &input, std::vector< output_array_type > &output, int axis, const typename stripe_handler_type::arg_type &handler_args, int njobs=vspline::default_njobs) const |
| this operator() overload for single-axis processing takes std::vectors ('stacks') of arrays. this is only supported for nD data. This is a rarely-used variant; throughout vspline there isn't currently any place where this routine is called, but it's needed for some special applications. If you are studying the code, you may safely disregard the remainder of the code in this class definition; the two _on_expand variants below are also for the special case of 'stacks' of arrays. More...
|
|
template<typename in_vt , typename out_vt > |
void | _on_expand (std::false_type, const std::vector< in_vt > &input, std::vector< out_vt > &output, int axis, const typename stripe_handler_type::arg_type &handler_args, int njobs) const |
| variant of _on_expand for stacks of arrays. this overload is called if the data are multi-channel. we element-expand the arrays, then call the single-channel overload below More...
|
|
template<typename in_vt , typename out_vt > |
void | _on_expand (std::true_type, const std::vector< in_vt > &input, std::vector< out_vt > &output, int axis, const typename stripe_handler_type::arg_type &handler_args, int njobs) const |
| variant of _on_expand for stacks of arrays this is the single-channel overload. The arrays now hold fundamentals, either because that was their original data type or because they have been element-expanded. We end up in this routine for all processing of stacks and finally get to do the filtering. More...
|
|
template<typename input_array_type, typename output_array_type, typename stripe_handler_type>
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.
Definition at line 729 of file filter.h.