vspline 1.1.0
Generic C++11 Code for Uniform B-Splines
gsm2.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/* Permission is hereby granted, free of charge, to any person */
9/* obtaining a copy of this software and associated documentation */
10/* files (the "Software"), to deal in the Software without */
11/* restriction, including without limitation the rights to use, */
12/* copy, modify, merge, publish, distribute, sublicense, and/or */
13/* sell copies of the Software, and to permit persons to whom the */
14/* Software is furnished to do so, subject to the following */
15/* conditions: */
16/* */
17/* The above copyright notice and this permission notice shall be */
18/* included in all copies or substantial portions of the */
19/* Software. */
20/* */
21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
23/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
24/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
25/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
26/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
27/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
28/* OTHER DEALINGS IN THE SOFTWARE. */
29/* */
30/************************************************************************/
31
32/// \file gsm2.cc
33///
34/// \brief calculating the gradient squared magnitude, derivatives
35///
36/// alternative implementation of gsm.cc, performing the calculation of the
37/// gradient squared magnitude with a functor and transform(), which is faster
38/// since the whole operation is multithreaded and potentially vectorized.
39///
40/// compile with:
41/// clang++ -std=c++11 -march=native -o gsm -O3 -pthread -DUSE_VC gsm.cc -lvigraimpex -lVc
42/// or clang++ -std=c++11 -march=native -o gsm -O3 -pthread gsm.cc -lvigraimpex
43/// (with Vc; use -DUSE_HWY and -lhwy for highway, or -std=c++17 and -DUSE_STDSIMD
44/// for the std::simd backend)
45///
46/// invoke passing an image file. the result will be written to 'gsm2.tif'
47
48#include <iostream>
49
50#include <vspline/vspline.h>
51
52#include <vigra/stdimage.hxx>
53#include <vigra/imageinfo.hxx>
54#include <vigra/impex.hxx>
55
56// we silently assume we have a colour image
57typedef vigra::RGBValue<float,0,1,2> pixel_type;
58
59// coordinate_type has a 2D coordinate
60typedef vigra::TinyVector < float , 2 > coordinate_type ;
61
62// type of b-spline object
64
65// target_type is a 2D array of pixels
66typedef vigra::MultiArray < 2 , pixel_type > target_type ;
67
68// b-spline evaluator producing float pixels
69typedef vspline::evaluator < coordinate_type , // incoming coordinate's type
70 pixel_type // singular result data type
72
73/// we build a vspline::unary_functor which calculates the sum of gradient squared
74/// magnitudes.
75/// Note how the 'compound evaluator' we construct follows a pattern of
76/// - derive from vspline::unary_functor
77/// - keep const instances of 'inner' types
78/// - initialize these in the constructor, yielding a 'pure' functor
79/// - if the vector code is identical to the unvectorized code, implement
80/// eval() with a template
81
82// we start out by coding the evaluation functor.
83// this class does the actual computations:
84
85struct ev_gsm
86: public vspline::unary_functor < coordinate_type , pixel_type >
87{
88 // we create two evaluators for the b-spline, one for the horizontal and
89 // one for the vertical gradient. The derivatives for a b-spline are requested
90 // by passing a TinyVector with as many elements as the spline's dimension
91 // with the desired derivative degree for each dimension. Here we want the
92 // first derivatives in x and in y direction:
93
94 const vigra::TinyVector < float , 2 > dx1_spec { 1 , 0 } ;
95 const vigra::TinyVector < float , 2 > dy1_spec { 0 , 1 } ;
96
97 // we keep two 'inner' evaluators, one for each direction
98
99 const ev_type xev , yev ;
100
101 // which are initialized in the constructor, using the bspline and the
102 // derivative specifiers
103
104 ev_gsm ( const spline_type & bspl )
105 : xev ( bspl , dx1_spec ) ,
106 yev ( bspl , dy1_spec )
107 { } ;
108
109 // since the code is the same for vectorized and unvectorized
110 // operation, we can write a template:
111
112 template < class IN , class OUT >
113 void eval ( const IN & c ,
114 OUT & result ) const
115 {
116 OUT dx , dy ;
117
118 xev.eval ( c , dx ) ; // get the gradient in x direction
119 yev.eval ( c , dy ) ; // get the gradient in y direction
120
121 // really, we'd like to write:
122 // result = dx * dx + dy * dy ;
123 // but fail due to problems with type inference: for vectorized
124 // types, both dx and dy are vigra::TinyVectors of two simdized
125 // values, and multiplying two such objects is not defined.
126 // It's possible to activate code performing such operations by
127 // defining the relevant traits in namespace vigra, but for this
128 // example we'll stick with using multiply-assigns, which are defined.
129
130 dx *= dx ; // square the gradients
131 dy *= dy ;
132 dx += dy ; // add them up
133
134 result = dx ; // assign to result
135 }
136
137} ;
138
139int main ( int argc , char * argv[] )
140{
141 if ( argc < 2 )
142 {
143 std::cerr << "pass a colour image file as argument" << std::endl ;
144 exit( -1 ) ;
145 }
146 // get the image file name
147
148 vigra::ImageImportInfo imageInfo ( argv[1] ) ;
149
150 // we want a b-spline with natural boundary conditions
151
152 vigra::TinyVector < vspline::bc_code , 2 > bcv ( vspline::NATURAL ) ;
153
154 // create cubic 2D b-spline object containing the image data
155
156 spline_type bspl ( imageInfo.shape() , // the shape of the data for the spline
157 3 , // degree 3 == cubic spline
158 bcv // specifies natural BCs along both axes
159 ) ;
160
161 // load the image data into the b-spline's core. This is a common idiom:
162 // the spline's 'core' is a MultiArrayView to that part of the spline's
163 // data container which precisely corresponds with the input data.
164 // This saves loading the image to some memory first and then transferring
165 // the data into the spline. Since the core is a vigra::MultiarrayView,
166 // we can pass it to importImage as the desired target for loading the
167 // image from disk.
168
169 vigra::importImage ( imageInfo , bspl.core ) ;
170
171 // prefilter the b-spline
172
173 bspl.prefilter() ;
174
175 // now we construct the gsm evaluator
176
177 ev_gsm ev ( bspl ) ;
178
179 // this is where the result should go:
180
181 target_type target ( imageInfo.shape() ) ;
182
183 // now we obtain the result by performing a vspline::transform. This function
184 // successively passes discrete coordinates into the target to the evaluator
185 // it's invoked with, storing the result of the evaluator's evaluation
186 // at the self-same coordinates. This is done multithreaded and vectorized
187 // automatically, so it's very convenient, if the evaluator is at hand.
188 // So here we have invested moderately more coding effort in the evaluator
189 // and are rewarded with being able to use the evaluator with vspline's
190 // high-level code for a fast implementation of our gsm problem.
191 // The difference is quite noticeable. On my system, processing a full HD
192 // image, I get:
193
194 // $ time ./gsm image.jpg
195 //
196 // real 0m0.838s
197 // user 0m0.824s
198 // sys 0m0.012s
199 //
200 // $ time ./gsm2 image.jpg
201 //
202 // real 0m0.339s
203 // user 0m0.460s
204 // sys 0m0.016s
205
206 vspline::transform ( ev , target ) ;
207
208 // store the result with vigra impex
209
210 vigra::ImageExportInfo eximageInfo ( "gsm2.tif" );
211
212 std::cout << "storing the target image as 'gsm2.tif'" << std::endl ;
213
214 vigra::exportImage ( target ,
215 eximageInfo
216 .setPixelType("UINT8") ) ;
217
218 exit ( 0 ) ;
219}
vigra::RGBValue< float, 0, 1, 2 > pixel_type
Definition: ca_correct.cc:103
vigra::MultiArray< 2, pixel_type > target_type
Definition: ca_correct.cc:115
class evaluator encodes evaluation of a spline-like object. This is a generalization of b-spline eval...
Definition: eval.h:1718
void eval(const typename base_type::in_type &_coordinate, typename base_type::out_type &_result) const
unvectorized evaluation function. this is delegated to 'feed' above, which reinterprets the arguments...
Definition: eval.h:1822
int main(int argc, char *argv[])
Definition: gsm2.cc:139
vigra::RGBValue< float, 0, 1, 2 > pixel_type
Definition: gsm2.cc:57
vigra::TinyVector< float, 2 > coordinate_type
Definition: gsm2.cc:60
vspline::evaluator< coordinate_type, pixel_type > ev_type
Definition: gsm2.cc:71
vspline::bspline< pixel_type, 2 > spline_type
Definition: gsm2.cc:63
vigra::MultiArray< 2, pixel_type > target_type
Definition: gsm2.cc:66
void transform(const unary_functor_type &functor, const vigra::MultiArrayView< dimension, typename unary_functor_type::in_type > &input, vigra::MultiArrayView< dimension, typename unary_functor_type::out_type > &output, int njobs=vspline::default_njobs, vspline::atomic< bool > *p_cancel=0)
implementation of two-array transform using wielding::coupled_wield.
Definition: transform.h:211
@ NATURAL
Definition: common.h:75
we build a vspline::unary_functor which calculates the sum of gradient squared magnitudes....
Definition: gsm2.cc:87
void eval(const IN &c, OUT &result) const
Definition: gsm2.cc:113
const vigra::TinyVector< float, 2 > dy1_spec
Definition: gsm2.cc:95
const ev_type xev
Definition: gsm2.cc:99
const ev_type yev
Definition: gsm2.cc:99
const vigra::TinyVector< float, 2 > dx1_spec
Definition: gsm2.cc:94
ev_gsm(const spline_type &bspl)
Definition: gsm2.cc:104
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
class unary_functor provides a functor object which offers a system of types for concrete unary funct...
includes all headers from vspline (most of them indirectly)