aimsalgo  5.0.5
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>
43 #include <aims/data/data.h>
45 
46 
47 namespace {
48  template <class T>
49  void _sliceResamp( const carto::Volume<T>& input_data,
50  carto::Volume<T> & resamp,
51  const T&background, T* out,
52  const Point3df& start,
53  int t, const carto::Volume<float>& Rinv );
54 } // anonymous namespace
55 
56 namespace aims
57 {
58 
59 template <class T>
60 void MaskLinearResampler<T>::
61 doResample( const carto::Volume<T> &input_data,
62  const soma::Transformation3d &inverse_transform,
63  const T &background,
64  const Point3df& output_location,
65  T &output_value, int t ) const
66 {
67  const Point3df input_location = inverse_transform.transform(output_location);
68 
69  float xf = std::floor(input_location[0]);
70  float yf = std::floor(input_location[1]);
71  float zf = std::floor(input_location[2]);
72 
73  std::vector<int> dims = input_data.getSize();
74 
75  // The test is done using floating-point so that NaN values are excluded (the
76  // background value is returned if the transformation yields NaN)
77  if ( ( xf >= 0 ) && ( xf < dims[0] ) &&
78  ( yf >= 0 ) && ( yf < dims[1] ) &&
79  ( zf >= 0 ) && ( zf < dims[2] ) )
80  {
81  int x = static_cast<int>(xf);
82  int y = static_cast<int>(yf);
83  int z = static_cast<int>(zf);
84 
85  if (input_data.at(x, y, z, t) == -32768 ||
86  input_data.at(x + 1, y, z, t) == -32768 ||
87  input_data.at(x, y + 1, z, t) == -32768 ||
88  input_data.at(x + 1, y + 1, z, t) == -32768 ||
89  input_data.at(x, y, z + 1, t) == -32768 ||
90  input_data.at(x + 1, y, z + 1, t) == -32768 ||
91  input_data.at(x, y + 1, z + 1, t) == -32768 ||
92  input_data.at(x + 1, y + 1, z + 1, t) == -32768)
93  {
94  output_value = -32768;
95  } else {
96  // Normal linear interpolation
97  _linearresampler.resample_inv_to_vox(input_data, inverse_transform,
98  background, output_location,
99  output_value, t);
100  }
101  } else {
102  output_value = background;
103  }
104 }
105 
106 
107 template <class T>
108 void MaskLinearResampler<T>::resample( const carto::Volume< T >& input_data,
110  motion,
111  const T& background,
112  carto::Volume< T > & thing,
113  bool verbose ) const
114 {
115  int dimt = thing.getSizeT();
116  ASSERT( thing.getSizeT() == input_data.getSizeT()
117  && thing.refVolume().isNull() );
118 
119  aims::AffineTransformation3d dirMotion = motion;
120  aims::AffineTransformation3d invMotion = motion.inverse();
121 
122  // scale motion
123  Point3df sizeFrom( input_data.getVoxelSize() );
124  Point3df sizeTo( thing.getVoxelSize() );
125  dirMotion.scale( sizeFrom, sizeTo );
126  invMotion.scale( sizeTo, sizeFrom );
127 
128  //
129  Point3df start;
130  T* it = &thing.at( 0 );
131  int dimz = thing.getSizeZ();
132 
133  if(verbose) {
134  std::cout << "Resampling volume [ 1] / slice [ 1]" << std::flush;
135  }
136 
137  for (int t = 1; t <= dimt; t++ )
138  {
139  start = invMotion.translation();
140  for ( int s = 1; s <= dimz; s++ )
141  {
142  if(verbose) {
143  std::cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
144  << std::setw( 3 ) << t << "] / slice ["
145  << std::setw( 3 ) << s << "]" << std::flush;
146  }
147 
148  _sliceResamp( input_data, thing, background, it, start, t - 1,
149  invMotion.rotation().volume() );
150  it = &thing.at( 0, 0, s, t - 1 );
151  start[ 0 ] += invMotion.rotation()( 0, 2 );
152  start[ 1 ] += invMotion.rotation()( 1, 2 );
153  start[ 2 ] += invMotion.rotation()( 2, 2 );
154  }
155  }
156  if(verbose) {
157  std::cout << std::endl;
158  }
159 }
160 
161 } // namespace aims
162 
163 
164 namespace {
165 
166 template <class T>
167 void _sliceResamp( const carto::Volume<T>& input_data,
168  carto::Volume<T> & resamp,
169  const T& background, T* out,
170  const Point3df& start, int t,
171  const carto::Volume<float>& Rinv )
172 {
174  "the optimizations need at least 32-bit int");
175 
176  const T* pOrig = &input_data.at( 0, 0, 0, t );
177 
178  int dimX1 = input_data.getSizeX();
179  int dimX2 = resamp.getSizeX();
180  int dimY2 = resamp.getSizeY();
181 
182  const int SIXTEEN = 16;
183  const int TWO_THEN_SIXTEEN = 65536;
184 
185  int maxX = TWO_THEN_SIXTEEN * ( dimX1 - 1 );
186  int maxY = TWO_THEN_SIXTEEN * ( input_data.getSizeY() - 1 );
187  int maxZ = TWO_THEN_SIXTEEN * ( input_data.getSizeZ() - 1 );
188 
189  int xLinCurrent = ( int )( 65536.0 * start[ 0 ] );
190  int yLinCurrent = ( int )( 65536.0 * start[ 1 ] );
191  int zLinCurrent = ( int )( 65536.0 * start[ 2 ] );
192 
193  int xu = ( int )( 65536.0 * Rinv( 0, 0 ) );
194  int yu = ( int )( 65536.0 * Rinv( 1, 0 ) );
195  int zu = ( int )( 65536.0 * Rinv( 2, 0 ) );
196  int xv = ( int )( 65536.0 * Rinv( 0, 1 ) );
197  int yv = ( int )( 65536.0 * Rinv( 1, 1 ) );
198  int zv = ( int )( 65536.0 * Rinv( 2, 1 ) );
199 
200  int xCurrent, yCurrent, zCurrent;
201  int dx, dy, dz;
202  const T* it;
203  long incr_vois[8] = {
204  0,
205  1,
206  &input_data.at( 0, 1, 0 ) - &input_data.at( 0 ),
207  &input_data.at( 0, 1, 0 ) - &input_data.at( 0 ),
208  &input_data.at( 0, 0, 1 ) - &input_data.at( 0 ),
209  &input_data.at( 1, 0, 1 ) - &input_data.at( 0 ),
210  &input_data.at( 1, 1, 1 ) - &input_data.at( 0 ),
211  &input_data.at( 0, 1, 1 ) - &input_data.at( 0 )
212  };
213 float stock1, stock2, stock3;
214  for ( int v = dimY2; v--; )
215  {
216  xCurrent = xLinCurrent;
217  yCurrent = yLinCurrent;
218  zCurrent = zLinCurrent;
219 
220  for ( int u = dimX2; u--; )
221  {
222  if ( xCurrent >= 0 && xCurrent < maxX &&
223  yCurrent >= 0 && yCurrent < maxY &&
224  zCurrent >= 0 && zCurrent < maxZ )
225  {
226  dx = xCurrent & 0xffff;
227  dy = yCurrent & 0xffff;
228  dz = zCurrent & 0xffff;
229 
230  it = pOrig + ( zCurrent >> SIXTEEN ) * incr_vois[4]
231  + ( yCurrent >> SIXTEEN ) * dimX1
232  + ( xCurrent >> SIXTEEN );
233 
234  if (*(it + incr_vois[0]) == -32768 ||
235  *(it + incr_vois[1]) == -32768 ||
236  *(it + incr_vois[2]) == -32768 ||
237  *(it + incr_vois[3]) == -32768 ||
238  *(it + incr_vois[4]) == -32768 ||
239  *(it + incr_vois[5]) == -32768 ||
240  *(it + incr_vois[6]) == -32768 ||
241  *(it + incr_vois[7]) == -32768 )
242  {
243  *out++ = -32768;
244  }
245  else
246  {
247 
248 
249  stock1 = *it * ( TWO_THEN_SIXTEEN - dx );
250  stock1 += *(++it) * dx;
251  stock1 /= TWO_THEN_SIXTEEN;
252 
253  it += dimX1;
254  stock2 = *it * dx;
255  stock2 += *(--it) * ( TWO_THEN_SIXTEEN - dx );
256  stock2 /= TWO_THEN_SIXTEEN;
257 
258  stock1 *= ( TWO_THEN_SIXTEEN - dy );
259  stock1 += stock2 * dy;
260  stock1 /= TWO_THEN_SIXTEEN;
261 
262  it += incr_vois[4] - dimX1;
263  stock2 = *it * ( TWO_THEN_SIXTEEN - dx );
264  stock2 += *(++it) * dx;
265  stock2 /= TWO_THEN_SIXTEEN;
266 
267  it += dimX1;
268  stock3 = *it * dx;
269  stock3 += *(--it) * ( TWO_THEN_SIXTEEN - dx );
270  stock3 /= TWO_THEN_SIXTEEN;
271 
272  stock2 *= TWO_THEN_SIXTEEN - dy;
273  stock2 += stock3 * dy;
274  stock2 /= TWO_THEN_SIXTEEN;
275 
276  stock1 *= ( TWO_THEN_SIXTEEN - dz );
277  stock1 += stock2 * dz;
278 
279  *out++ = static_cast<T>( stock1 / TWO_THEN_SIXTEEN );
280  }
281  }
282  else
283  *out++ = background;
284 
285  xCurrent += xu;
286  yCurrent += yu;
287  zCurrent += zu;
288  }
289  xLinCurrent += xv;
290  yLinCurrent += yv;
291  zLinCurrent += zv;
292  }
293 }
294 
295 } // anonymous namespace
int getSizeZ() const
const T & at(long x, long y=0, long z=0, long t=0) const
Point3dd transform(double x, double y, double z) const
AimsData< float > rotation()
std::vector< int > getSize() const
int getSizeX() const
bool isNull() const
rc_ptr< Volume< T > > refVolume() const
carto::rc_ptr< carto::Volume< float > > volume()
std::vector< float > getVoxelSize() const
int getSizeY() const
virtual void scale(const Point3df &sizeFrom, const Point3df &sizeTo)
int getSizeT() const
#define ASSERT(EX)
#define static_assert(expr, msg)
AffineTransformation3d inverse() const