vspline 1.1.0
Generic C++11 Code for Uniform B-Splines
polish.cc
Go to the documentation of this file.
1/************************************************************************/
2/* */
3/* vspline - a set of generic tools for creation and evaluation */
4/* of uniform b-splines */
5/* */
6/* Copyright 2015 - 2023 by Kay F. Jahnke */
7/* */
8/* The git repository for this software is at */
9/* */
10/* https://bitbucket.org/kfj/vspline */
11/* */
12/* Please direct questions, bug reports, and contributions to */
13/* */
14/* kfjahnke+vspline@gmail.com */
15/* */
16/* Permission is hereby granted, free of charge, to any person */
17/* obtaining a copy of this software and associated documentation */
18/* files (the "Software"), to deal in the Software without */
19/* restriction, including without limitation the rights to use, */
20/* copy, modify, merge, publish, distribute, sublicense, and/or */
21/* sell copies of the Software, and to permit persons to whom the */
22/* Software is furnished to do so, subject to the following */
23/* conditions: */
24/* */
25/* The above copyright notice and this permission notice shall be */
26/* included in all copies or substantial portions of the */
27/* Software. */
28/* */
29/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
30/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
31/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
32/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
33/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
34/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
35/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
36/* OTHER DEALINGS IN THE SOFTWARE. */
37/* */
38/************************************************************************/
39
40/*! \file polish.cc
41
42 \brief 'polish' a b-spline several times, to see if it's precision
43 can be improved. It turns out that, starting out with zero
44 tolerance for the coefficient generation, there is very little
45 room for improvement.
46*/
47
48#include <vigra/multi_array.hxx>
49#include <vigra/accumulator.hxx>
50#include <vigra/multi_math.hxx>
51#include <iostream>
52#include <typeinfo>
53#include <random>
54#include <ctime>
55#include <chrono>
56
57#include <vspline/vspline.h>
58
59bool verbose = true ; // false ;
60
61// 'condense' aggregate types (TinyVectors etc.) into a single value
62
63template < typename T >
64double condense ( const T & t , std::true_type )
65{
66 return std::abs ( t ) ;
67}
68
69template < typename T >
70double condense ( const T & t , std::false_type )
71{
72 return sqrt ( sum ( t * t ) ) / t.size() ;
73}
74
75template < typename T >
76double condense ( const std::complex<T> & t , std::false_type )
77{
78 return std::abs ( t ) ;
79}
80
81template < class T >
82using is_singular = typename
83 std::conditional
84 < std::is_fundamental < T > :: value ,
85 std::true_type ,
86 std::false_type
87 > :: type ;
88
89template < typename T >
90double condense ( const T & t )
91{
92 return condense ( t , is_singular<T>() ) ;
93}
94
95template < int dim , typename T >
96double check_diff ( vigra::MultiArrayView < dim , T > & reference ,
97 vigra::MultiArrayView < dim , T > & candidate )
98{
99 using namespace vigra::multi_math ;
100 using namespace vigra::acc;
101
102 assert ( reference.shape() == candidate.shape() ) ;
103
104 vigra::MultiArray < 1 , double >
105 error_array ( vigra::Shape1(reference.size() ) ) ;
106
107 for ( int i = 0 ; i < reference.size() ; i++ )
108 {
109 auto help = candidate[i] - reference[i] ;
110// std::cerr << reference[i] << " <> " << candidate[i]
111// << " CFD " << help << std::endl ;
112 error_array [ i ] = condense ( help ) ;
113 }
114
115 AccumulatorChain < double , Select < Mean, Maximum > > ac ;
116 extractFeatures ( error_array.begin() , error_array.end() , ac ) ;
117 double mean = get<Mean>(ac) ;
118 double max = get<Maximum>(ac) ;
119 if ( verbose )
120 {
121 std::cout << "delta Mean: "
122 << mean << std::endl;
123 std::cout << "delta Maximum: "
124 << max << std::endl;
125 }
126 return max ;
127}
128
129template < int dim , typename T > void
130polish_test ( vigra::TinyVector < int , dim > shape ,
132 int spline_degree )
133{
134 typedef vigra::MultiArray < dim , T > array_type ;
136
137 array_type arr ( shape ) ;
138 vigra::TinyVector < vspline::bc_code , dim > bcv { bc } ;
139 spline_type bsp ( shape , spline_degree , bcv , 0.0 ) ;
140
141 if ( verbose )
142 std::cout << "created b-spline:" << std::endl << bsp << std::endl ;
143
144 std::random_device rd ;
145 std::mt19937 gen ( rd() ) ;
146// gen.seed ( 765 ) ; // level playing field
147 std::uniform_real_distribution<> dis ( -1.0 , 1.0 ) ;
148 for ( auto & e : arr )
149 e = dis ( gen ) ; // fill array with random data
150
151 array_type reference = arr ; // hold a copy of these data
152
153 bsp.prefilter ( arr ) ; // suck into b-spline via prefilter
154
155 vspline::restore < dim , T > ( bsp , arr ) ; // restore back to arr
156
157 if ( verbose )
158 std::cout << "after restoration of original data:" << std::endl ;
159
160 double emax = check_diff < dim , T > ( reference , arr ) ;
161
162 if ( verbose )
163 {
164 // print a summary, can use '| grep CF' on cout
165 std::cout
166 << typeid(T()).name()
167 << " CF "
168// << vspline::pfs_name [ pfs ][0]
169 << " D " << dim
170 << " " << arr.shape()
171 << " BC " << vspline::bc_name[bc]
172 << " DG " << spline_degree
173 << " TOL " << bsp.tolerance
174 << " EMAX "
175 << emax << std::endl ;
176 }
177
178 for ( int times = 1 ; times < 5 ; times++ )
179 {
180 // difference original / restored
181 arr -= reference ;
182 // create another bspline
183 spline_type polish_spl ( arr.shape() , spline_degree , bcv , 0.0 ) ;
184 // prefilter it, sucking in the difference
185 polish_spl.prefilter ( arr ) ;
186 // and layer the resulting coeffs on top of the previous set
187 bsp.core -= polish_spl.core ;
188 // brace the 'augmented' spline
189 bsp.brace() ;
190 // and check it's quality
191 vspline::restore < dim , T > ( bsp , arr ) ;
192
193 if ( verbose )
194 std::cout << "after polishing run " << times << std::endl ;
195
196 double emax2 = check_diff < dim , T > ( reference , arr ) ;
197
198 if ( verbose )
199 {
200 // print a summary, can use '| grep CF' on cout
201 std::cout
202 << typeid(T()).name()
203 << " CF "
204 // << vspline::pfs_name [ pfs ][0]
205 << " D " << dim
206 << " " << arr.shape()
207 << " BC " << vspline::bc_name[bc]
208 << " DG " << spline_degree
209 << " TOL " << bsp.tolerance
210 << " EMAX "
211 << emax2 << std::endl ;
212 }
213 }
214}
215
216int main ( int argc , char * argv[] )
217{
218 if ( argc < 2 )
219 {
220 std::cerr << "pass the spline degree as parameter" << std::endl ;
221 exit ( -1 ) ;
222 }
223
224 int degree = std::atoi ( argv[1] ) ;
225
226 polish_test < 2 , float >
227 ( { 1000 , 1000 } ,vspline::PERIODIC , degree ) ;
228
229 polish_test < 2 , double >
230 ( { 1000 , 1000 } ,vspline::PERIODIC , degree ) ;
231
232 polish_test < 2 , long double >
233 ( { 1000 , 1000 } ,vspline::PERIODIC , degree ) ;
234}
vspline::bspline< pixel_type, 2 > spline_type
Definition: ca_correct.cc:111
typename std::conditional< std::is_fundamental< T > ::value, std::true_type, std::false_type > ::type is_singular
Definition: grind.cc:88
const std::string bc_name[]
bc_name is for diagnostic output of bc codes
Definition: common.h:84
bc_code
This enumeration is used for codes connected to boundary conditions. There are two aspects to boundar...
Definition: common.h:71
@ PERIODIC
Definition: common.h:73
int main(int argc, char *argv[])
Definition: polish.cc:216
bool verbose
Definition: polish.cc:59
void polish_test(vigra::TinyVector< int, dim > shape, vspline::bc_code bc, int spline_degree)
Definition: polish.cc:130
double condense(const T &t, std::true_type)
Definition: polish.cc:64
double check_diff(vigra::MultiArrayView< dim, T > &reference, vigra::MultiArrayView< dim, T > &candidate)
Definition: polish.cc:96
class bspline now builds on class bspline_base, adding coefficient storage, while bspline_base provid...
Definition: bspline.h:499
view_type core
Definition: bspline.h:566
void prefilter(vspline::xlf_type boost=vspline::xlf_type(1), int njobs=vspline::default_njobs)
prefilter converts the knot point data in the 'core' area into b-spline coefficients....
Definition: bspline.h:815
void brace(int axis=-1)
if the spline coefficients are already known, they obviously don't need to be prefiltered....
Definition: bspline.h:773
const xlf_type tolerance
Definition: bspline.h:213
includes all headers from vspline (most of them indirectly)