aimsalgo  5.1.2
Neuroimaging image processing
masklinresampler_d.h
Go to the documentation of this file.
1 /* This software and supporting documentation are distributed by
2  * Institut Federatif de Recherche 49
3  * CEA/NeuroSpin, Batiment 145,
4  * 91191 Gif-sur-Yvette cedex
5  * France
6  *
7  * This software is governed by the CeCILL-B license under
8  * French law and abiding by the rules of distribution of free software.
9  * You can use, modify and/or redistribute the software under the
10  * terms of the CeCILL-B license as circulated by CEA, CNRS
11  * and INRIA at the following URL "http://www.cecill.info".
12  *
13  * As a counterpart to the access to the source code and rights to copy,
14  * modify and redistribute granted by the license, users are provided only
15  * with a limited warranty and the software's author, the holder of the
16  * economic rights, and the successive licensors have only limited
17  * liability.
18  *
19  * In this respect, the user's attention is drawn to the risks associated
20  * with loading, using, modifying and/or developing or reproducing the
21  * software by the user in light of its specific status of free software,
22  * that may mean that it is complicated to manipulate, and that also
23  * therefore means that it is reserved for developers and experienced
24  * professionals having in-depth computer knowledge. Users are therefore
25  * encouraged to load and test the software's suitability as regards their
26  * requirements in conditions enabling the security of their systems and/or
27  * data to be ensured and, more generally, to use and operate it in the
28  * same conditions as regards security.
29  *
30  * The fact that you are presently reading this means that you have had
31  * knowledge of the CeCILL-B license and that you accept its terms.
32  */
33 
35 
36 #include <cmath>
37 #include <iomanip>
38 #include <iostream>
39 #include <limits>
40 #include <stdexcept>
41 
42 #include <aims/vector/vector.h>
44 
45 
46 namespace {
47  template <class T>
48  void _sliceResamp( const carto::Volume<T>& input_data,
49  carto::Volume<T> & resamp,
50  const T&background, T* out,
51  const Point3df& start,
52  int t, const carto::Volume<float>& Rinv );
53 } // anonymous namespace
54 
55 namespace aims
56 {
57 
58 template <class T>
59 void MaskLinearResampler<T>::
60 doResample( const carto::Volume<T> &input_data,
61  const soma::Transformation3d &inverse_transform,
62  const T &background,
63  const Point3df& output_location,
64  T &output_value, int t ) const
65 {
66  const Point3df input_location = inverse_transform.transform(output_location);
67 
68  float xf = std::floor(input_location[0]);
69  float yf = std::floor(input_location[1]);
70  float zf = std::floor(input_location[2]);
71 
72  std::vector<int> dims = input_data.getSize();
73 
74  // The test is done using floating-point so that NaN values are excluded (the
75  // background value is returned if the transformation yields NaN)
76  if ( ( xf >= 0 ) && ( xf < dims[0] ) &&
77  ( yf >= 0 ) && ( yf < dims[1] ) &&
78  ( zf >= 0 ) && ( zf < dims[2] ) )
79  {
80  int x = static_cast<int>(xf);
81  int y = static_cast<int>(yf);
82  int z = static_cast<int>(zf);
83 
84  if (input_data.at(x, y, z, t) == -32768 ||
85  input_data.at(x + 1, y, z, t) == -32768 ||
86  input_data.at(x, y + 1, z, t) == -32768 ||
87  input_data.at(x + 1, y + 1, z, t) == -32768 ||
88  input_data.at(x, y, z + 1, t) == -32768 ||
89  input_data.at(x + 1, y, z + 1, t) == -32768 ||
90  input_data.at(x, y + 1, z + 1, t) == -32768 ||
91  input_data.at(x + 1, y + 1, z + 1, t) == -32768)
92  {
93  output_value = -32768;
94  } else {
95  // Normal linear interpolation
96  _linearresampler.resample_inv_to_vox(input_data, inverse_transform,
97  background, output_location,
98  output_value, t);
99  }
100  } else {
101  output_value = background;
102  }
103 }
104 
105 
106 template <class T>
107 void MaskLinearResampler<T>::resample( const carto::Volume< T >& input_data,
109  motion,
110  const T& background,
111  carto::Volume< T > & thing,
112  bool verbose ) const
113 {
114  int dimt = thing.getSizeT();
115  ASSERT( thing.getSizeT() == input_data.getSizeT()
116  && thing.refVolume().isNull() );
117 
118  aims::AffineTransformation3d dirMotion = motion;
119  aims::AffineTransformation3d invMotion = motion.inverse();
120 
121  // scale motion
122  Point3df sizeFrom( input_data.getVoxelSize() );
123  Point3df sizeTo( thing.getVoxelSize() );
124  dirMotion.scale( sizeFrom, sizeTo );
125  invMotion.scale( sizeTo, sizeFrom );
126 
127  //
128  Point3df start;
129  T* it = &thing.at( 0 );
130  int dimz = thing.getSizeZ();
131 
132  if(verbose) {
133  std::cout << "Resampling volume [ 1] / slice [ 1]" << std::flush;
134  }
135 
136  for (int t = 1; t <= dimt; t++ )
137  {
138  start = invMotion.translation();
139  for ( int s = 1; s <= dimz; s++ )
140  {
141  if(verbose) {
142  std::cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
143  << std::setw( 3 ) << t << "] / slice ["
144  << std::setw( 3 ) << s << "]" << std::flush;
145  }
146 
147  _sliceResamp( input_data, thing, background, it, start, t - 1,
148  invMotion.rotation() );
149  it = &thing.at( 0, 0, s, t - 1 );
150  start[ 0 ] += invMotion.rotation()( 0, 2 );
151  start[ 1 ] += invMotion.rotation()( 1, 2 );
152  start[ 2 ] += invMotion.rotation()( 2, 2 );
153  }
154  }
155  if(verbose) {
156  std::cout << std::endl;
157  }
158 }
159 
160 } // namespace aims
161 
162 
163 namespace {
164 
165 template <class T>
166 void _sliceResamp( const carto::Volume<T>& input_data,
167  carto::Volume<T> & resamp,
168  const T& background, T* out,
169  const Point3df& start, int t,
170  const carto::Volume<float>& Rinv )
171 {
173  "the optimizations need at least 32-bit int");
174 
175  const T* pOrig = &input_data.at( 0, 0, 0, t );
176 
177  int dimX1 = input_data.getSizeX();
178  int dimX2 = resamp.getSizeX();
179  int dimY2 = resamp.getSizeY();
180 
181  const int SIXTEEN = 16;
182  const int TWO_THEN_SIXTEEN = 65536;
183 
184  int maxX = TWO_THEN_SIXTEEN * ( dimX1 - 1 );
185  int maxY = TWO_THEN_SIXTEEN * ( input_data.getSizeY() - 1 );
186  int maxZ = TWO_THEN_SIXTEEN * ( input_data.getSizeZ() - 1 );
187 
188  int xLinCurrent = ( int )( 65536.0 * start[ 0 ] );
189  int yLinCurrent = ( int )( 65536.0 * start[ 1 ] );
190  int zLinCurrent = ( int )( 65536.0 * start[ 2 ] );
191 
192  int xu = ( int )( 65536.0 * Rinv( 0, 0 ) );
193  int yu = ( int )( 65536.0 * Rinv( 1, 0 ) );
194  int zu = ( int )( 65536.0 * Rinv( 2, 0 ) );
195  int xv = ( int )( 65536.0 * Rinv( 0, 1 ) );
196  int yv = ( int )( 65536.0 * Rinv( 1, 1 ) );
197  int zv = ( int )( 65536.0 * Rinv( 2, 1 ) );
198 
199  int xCurrent, yCurrent, zCurrent;
200  int dx, dy, dz;
201  const T* it;
202  long incr_vois[8] = {
203  0,
204  1,
205  &input_data.at( 0, 1, 0 ) - &input_data.at( 0 ),
206  &input_data.at( 0, 1, 0 ) - &input_data.at( 0 ),
207  &input_data.at( 0, 0, 1 ) - &input_data.at( 0 ),
208  &input_data.at( 1, 0, 1 ) - &input_data.at( 0 ),
209  &input_data.at( 1, 1, 1 ) - &input_data.at( 0 ),
210  &input_data.at( 0, 1, 1 ) - &input_data.at( 0 )
211  };
212 float stock1, stock2, stock3;
213  for ( int v = dimY2; v--; )
214  {
215  xCurrent = xLinCurrent;
216  yCurrent = yLinCurrent;
217  zCurrent = zLinCurrent;
218 
219  for ( int u = dimX2; u--; )
220  {
221  if ( xCurrent >= 0 && xCurrent < maxX &&
222  yCurrent >= 0 && yCurrent < maxY &&
223  zCurrent >= 0 && zCurrent < maxZ )
224  {
225  dx = xCurrent & 0xffff;
226  dy = yCurrent & 0xffff;
227  dz = zCurrent & 0xffff;
228 
229  it = pOrig + ( zCurrent >> SIXTEEN ) * incr_vois[4]
230  + ( yCurrent >> SIXTEEN ) * dimX1
231  + ( xCurrent >> SIXTEEN );
232 
233  if (*(it + incr_vois[0]) == -32768 ||
234  *(it + incr_vois[1]) == -32768 ||
235  *(it + incr_vois[2]) == -32768 ||
236  *(it + incr_vois[3]) == -32768 ||
237  *(it + incr_vois[4]) == -32768 ||
238  *(it + incr_vois[5]) == -32768 ||
239  *(it + incr_vois[6]) == -32768 ||
240  *(it + incr_vois[7]) == -32768 )
241  {
242  *out++ = -32768;
243  }
244  else
245  {
246 
247 
248  stock1 = *it * ( TWO_THEN_SIXTEEN - dx );
249  stock1 += *(++it) * dx;
250  stock1 /= TWO_THEN_SIXTEEN;
251 
252  it += dimX1;
253  stock2 = *it * dx;
254  stock2 += *(--it) * ( TWO_THEN_SIXTEEN - dx );
255  stock2 /= TWO_THEN_SIXTEEN;
256 
257  stock1 *= ( TWO_THEN_SIXTEEN - dy );
258  stock1 += stock2 * dy;
259  stock1 /= TWO_THEN_SIXTEEN;
260 
261  it += incr_vois[4] - dimX1;
262  stock2 = *it * ( TWO_THEN_SIXTEEN - dx );
263  stock2 += *(++it) * dx;
264  stock2 /= TWO_THEN_SIXTEEN;
265 
266  it += dimX1;
267  stock3 = *it * dx;
268  stock3 += *(--it) * ( TWO_THEN_SIXTEEN - dx );
269  stock3 /= TWO_THEN_SIXTEEN;
270 
271  stock2 *= TWO_THEN_SIXTEEN - dy;
272  stock2 += stock3 * dy;
273  stock2 /= TWO_THEN_SIXTEEN;
274 
275  stock1 *= ( TWO_THEN_SIXTEEN - dz );
276  stock1 += stock2 * dz;
277 
278  *out++ = static_cast<T>( stock1 / TWO_THEN_SIXTEEN );
279  }
280  }
281  else
282  *out++ = background;
283 
284  xCurrent += xu;
285  yCurrent += yu;
286  zCurrent += zu;
287  }
288  xLinCurrent += xv;
289  yLinCurrent += yv;
290  zLinCurrent += zv;
291  }
292 }
293 
294 } // anonymous namespace
#define ASSERT(EX)
#define static_assert(expr, msg)
carto::VolumeRef< float > rotation()
AffineTransformation3d inverse() const
int getSizeY() const
std::vector< float > getVoxelSize() const
int getSizeX() const
std::vector< int > getSize() const
int getSizeZ() const
int getSizeT() const
rc_ptr< Volume< T > > refVolume() const
const T & at(long x, long y=0, long z=0, long t=0) const
bool isNull() const
virtual void scale(const Point3df &sizeFrom, const Point3df &sizeTo)
Point3dd transform(double x, double y, double z) const