File: slice2.cc

package info (click to toggle)
vspline 1.1.7-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,708 kB
  • sloc: cpp: 15,905; ansic: 443; sh: 17; makefile: 2
file content (220 lines) | stat: -rw-r--r-- 8,825 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/************************************************************************/
/*                                                                      */
/*    vspline - a set of generic tools for creation and evaluation      */
/*              of uniform b-splines                                    */
/*                                                                      */
/*            Copyright 2015 - 2023 by Kay F. Jahnke                    */
/*                                                                      */
/*    Permission is hereby granted, free of charge, to any person       */
/*    obtaining a copy of this software and associated documentation    */
/*    files (the "Software"), to deal in the Software without           */
/*    restriction, including without limitation the rights to use,      */
/*    copy, modify, merge, publish, distribute, sublicense, and/or      */
/*    sell copies of the Software, and to permit persons to whom the    */
/*    Software is furnished to do so, subject to the following          */
/*    conditions:                                                       */
/*                                                                      */
/*    The above copyright notice and this permission notice shall be    */
/*    included in all copies or substantial portions of the             */
/*    Software.                                                         */
/*                                                                      */
/*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
/*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
/*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
/*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
/*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
/*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
/*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
/*    OTHER DEALINGS IN THE SOFTWARE.                                   */
/*                                                                      */
/************************************************************************/

/// \file slice2.cc
///
/// \brief create 2D image data from a 3D spline
///
/// build a 3D volume from samples of the RGB colour colour_space
/// build a spline over it and extract a 2D slice, using vspline::transform()
///
/// while the result is just about the same as the one we get from slice.cc,
/// here we use additional functors to create the colour gradient and do the
/// coordinate transformation.
///
/// compile with:
/// clang++ -std=c++11 -march=native -o slice2 -O3 -pthread -DUSE_VC=1 slice2.cc -lvigraimpex -lVc
/// or: clang++ -std=c++11 -march=native -o slice2 -O3 -pthread slice2.cc -lvigraimpex
/// g++ also works.

#include <iostream>

#include <vspline/vspline.h>

#include <vigra/stdimage.hxx>
#include <vigra/imageinfo.hxx>
#include <vigra/impex.hxx>

// pixel_type is the result type, an RGB float pixel

typedef vigra::RGBValue < unsigned char , 0 , 1 , 2 > pixel_type ;

// voxel_type is the source data type, here we're using double precision

typedef vigra::TinyVector < double , 3 > voxel_type ;

// coordinate2_type has a 2D coordinate

typedef vigra::TinyVector < float , 2 > coordinate2_type ;

// coordinate3_type has a 3D coordinate

typedef vigra::TinyVector < float , 3 > coordinate3_type ;

// target_type is a 2D array of pixels  

typedef vigra::MultiArray < 2 , pixel_type > target_type ;

// we'll use a common vectorization width of 8 throughout

enum { VSIZE = 8 } ;

// we'll use a functor to create the gradient in the b-spline

struct calculate_gradient_type
: public vspline::unary_functor < coordinate3_type , voxel_type , VSIZE >
{
  // this method generates a voxel from a 3D coordinate.
  
  template < class IN , class OUT >
  void eval ( const IN & c , OUT & result ) const
  {
    // assign input to output and scale
    
    result = c ;
    result *= 25.5 ;
    
    // because we don't have the relevant vigra numeric and promote traits,
    // we *can't* write the obvious
    
    // result = 25.5 * c ;
  } ;
} ;

// type of b-spline evaluator producing pixels from 3D coordinates
// here we pass all template arguments an evaluator can take:
// - coordinate3_type for the type of incoming 3D coordinates
// - pixel_type for the data type we want to receive as result
// - VSIZE for the vectorization width
// - -1 indicates we want unspecialized b-spline evaluation
// - double: we want internal calculations done in double precision
// - voxel_type will be the type of coefficients held in the spline

typedef vspline::evaluator < coordinate3_type ,
                             pixel_type ,
                             VSIZE ,
                             -1 ,
                             double ,
                             voxel_type
                           > ev_type ;

// this functor is used for the coordinate transformation. It receives
// 2D coordinates (discrete target coordinates) and produces 3D
// coordinates which will be used to evaluate the spline. We pass
// the vectorization width explicitly to make sure it's the same
// as that used by the evaluator; if this weren't the case we could
// not 'chain' them further down

struct calculate_pickup_type
: public vspline::unary_functor < coordinate2_type , coordinate3_type , VSIZE >
{
  // this method transforms incoming discrete 2D coordinates - coordinates
  // pertaining to pixels in the target image - into 3D 'pick-up' coordinates
  // at which to evaluate the spline. Note how it's written as a template,
  // since the code for unvectorized and vectorized evaluation is just
  // the same. Note how we have coded coordinate2_type as consisting of
  // two floats, rather than two ints, which would have been just as well,
  // but which would have required transforming 'c' to it's floating point
  // equivalent before doing the maths. The 'index-based' version of
  // vspline::transform will feed the functor with the type it expects as
  // it's incoming type, so coordinate2_type in this case - or it's
  // vectorized equivalent.
  
  template < class IN , class OUT >
  void eval ( const IN & c , OUT & result ) const
  {
    result[0] = c[0] / 192.0f ;
    result[1] = 10.0f - result[0] ;
    result[2] = c[1] / 108.0f ;
  } ;
} ;

int main ( int argc , char * argv[] )
{
  // we want a b-spline with natural boundary conditions
  
  vigra::TinyVector < vspline::bc_code , 3 > bcv ( vspline::NATURAL ) ;
  
  // create quintic 3D b-spline object containing voxels
  // note the shape of the spline: it's ten units wide in each direction.
  // this explains the factor 25.5 used to calculate the voxels it holds:
  // the voxel's values will go from 0 to 255 for each channel
  
  vspline::bspline < voxel_type , 3 >
    colour_space ( vigra::Shape3 ( 10 , 10 , 10 ) , 5 , bcv ) ;
  
  // this functor will calculate the colour cube's content:
    
  calculate_gradient_type gradient ;
  
  // we could instead use vspline's 'amplify_type' to the same effect:

//   vspline::amplify_type < voxel_type , voxel_type , voxel_type , VSIZE >
//            gradient ( voxel_type ( 25.5 ) ) ;
  
  // now we run an index-based transform on the spline's 'core'. This will
  // feed successive 3D coordinates to 'gradient', which will calculate
  // voxel values from them

  vspline::transform ( gradient , colour_space.core ) ;
  
  // prefilter the b-spline
  
  colour_space.prefilter() ;
  
  // create the coordinate transformation functor
  
  calculate_pickup_type pick ;
  
  // get an evaluator for the b-spline
  
  ev_type ev ( colour_space ) ;
  
  // 'chain' the coordinate transformation functor and the evaluator
  
  auto combined = vspline::chain ( pick , ev ) ;
  
  // this is where the result should go:
  
  target_type target ( vigra::Shape2 ( 1920 , 1080 ) ) ;

  // now we perform the transform, yielding the result
  // note how we use a 'index-based' transform feeding the functor
  // (combined) with discrete target coordinates. Inside 'combined',
  // the incoming discrete coordinate is first transformed to the
  // 'pick-up' coordinate, which is in turn used to evaluate the
  // spline, yielding the result, which is stored in 'target'.
  
  vspline::transform ( combined , target ) ;

  // store the result with vigra impex
  
  vigra::ImageExportInfo imageInfo ( "slice.tif" );
  
  vigra::exportImage ( target ,
                      imageInfo
                      .setPixelType("UINT8")
                      .setCompression("100")
                      .setForcedRangeMapping ( 0 , 255 , 0 , 255 ) ) ;
  
  std::cout << "result was written to slice.tif" << std::endl ;
  exit ( 0 ) ;
}