aimsalgo 6.0.0
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/transformation/affinetransformation3d.h>
44
45
46namespace {
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
55namespace aims
56{
57
58template <class T>
59void MaskLinearResampler<T>::
60doResample( 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
106template <class T>
107void MaskLinearResampler<T>::resample( const carto::Volume< T >& input_data,
108 const aims::AffineTransformation3d&
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 std::unique_ptr<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
163namespace {
164
165template <class T>
166void _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{
172 static_assert(std::numeric_limits<int>::digits >= 31,
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 };
212float 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)
std::unique_ptr< 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
static const int digits
AimsVector< float, 3 > Point3df