33 #ifndef __INCLUDE_MIST_REGISTRATION__
34 #define __INCLUDE_MIST_REGISTRATION__
37 #ifndef __INCLUDE_MIST_CONF_H__
42 #ifndef __INCLUDE_MIST_H__
46 #ifndef __INCLUDE_MIST_VECTOR__
50 #ifndef __INCLUDE_MIST_MINIMIZATION__
54 #ifndef __INCLUDE_MIST_DRAWING__
58 #ifndef __INCLUDE_MIST_LIMITS__
62 #ifndef __INCLUDE_MIST_FFT__
66 #ifndef __INCLUDE_CONVERTER__
70 #ifndef __INCLUDE_INTERPOLATE__
74 #ifndef __INCLUDE_GEOMETRY__
79 #define M_PI 3.14159265358979323846
89 namespace __non_rigid_registration_utility__
91 inline void FFD(
double v,
double &f0,
double &f1,
double &f2,
double &f3 )
96 f0 = v_ * v_ * v_ / 6.0;
97 f1 = 0.5 * v3 - v2 + 4.0 / 6.0;
98 f2 = ( v2 - v3 + v ) * 0.5 + 1.0 / 6.0;
104 template <
class TARGETTYPE,
class TARGETTYPEA,
class SOURCETYPE,
class SOURCETYPEA,
class CONTROLMESH >
105 static void non_rigid_transformation_( array2< TARGETTYPE, TARGETTYPEA > &target,
const array2< SOURCETYPE, SOURCETYPEA > &source,
const CONTROLMESH &control_mesh,
106 typename CONTROLMESH::difference_type mx = -1,
107 typename CONTROLMESH::difference_type my = -1,
108 typename CONTROLMESH::difference_type mz = -1,
109 typename CONTROLMESH::size_type thread_id = 0,
110 typename CONTROLMESH::size_type thread_num = 1
113 typedef array2< TARGETTYPE, TARGETTYPEA > target_image_type;
114 typedef array2< SOURCETYPE, SOURCETYPEA > source_image_type;
115 typedef CONTROLMESH control_mesh_type;
117 typedef typename target_image_type::size_type size_type;
118 typedef typename target_image_type::difference_type difference_type;
119 typedef typename target_image_type::value_type value_type;
120 value_type minimum = type_limits< value_type >::minimum( );
122 difference_type i, j;
124 double sx[ 4 ], sy[ 4 ];
125 double stepW = control_mesh.width( ) == 1 ? 1.0 : target.width( ) /
static_cast< double >( control_mesh.width( ) - 1 );
126 double stepH = control_mesh.height( ) == 1 ? 1.0 : target.height( ) /
static_cast< double >( control_mesh.height( ) - 1 );
127 double _1_stepW = 1.0 / stepW;
128 double _1_stepH = 1.0 / stepH;
129 double _1_ax = 1.0 / source.reso1( );
130 double _1_ay = 1.0 / source.reso2( );
133 difference_type d0, d1, d2, d3;
135 difference_type cx = source.width( ) / 2;
136 difference_type cy = source.height( ) / 2;
137 typename source_image_type::const_pointer ppp = &source( cx, cy );
139 d1 = &source( cx , cy + 1 ) - ppp;
140 d2 = &source( cx + 1, cy + 1 ) - ppp;
141 d3 = &source( cx + 1, cy ) - ppp;
144 difference_type isx, isy, iex, iey;
145 difference_type mw = control_mesh.width( );
146 difference_type mh = control_mesh.height( );
147 if( mx < 0 || mw <= mx || my < 0 || mh <= my )
150 iex = target.width( ) - 1;
152 iey = target.height( ) - 1;
156 isx =
static_cast< difference_type
>( ( mx - 2 ) * stepW );
157 iex =
static_cast< difference_type
>( ( mx + 2 ) * stepW );
158 isy =
static_cast< difference_type
>( ( my - 2 ) * stepH );
159 iey =
static_cast< difference_type
>( ( my + 2 ) * stepH );
161 difference_type tw = target.width( );
162 difference_type th = target.height( );
163 isx = isx > 0 ? isx : 0;
164 isy = isy > 0 ? isy : 0;
165 iex = iex < tw ? iex : tw - 1;
166 iey = iey < th ? iey : th - 1;
170 for( difference_type y = isy + thread_id ; y <= iey ; y += thread_num )
173 j =
static_cast< difference_type
>( v );
177 FFD( v, sy[ 0 ], sy[ 1 ], sy[ 2 ], sy[ 3 ] );
179 for( difference_type x = isx ; x <= iex ; x++ )
182 i =
static_cast< difference_type
>( u );
186 FFD( u, sx[ 0 ], sx[ 1 ], sx[ 2 ], sx[ 3 ] );
188 double xx = 0.0, yy = 0.0;
189 for( difference_type m = 0 ; m <= 3 ; m++ )
191 typename control_mesh_type::const_pointer p = &control_mesh( i, j + m, 0 );
192 for( difference_type l = 0 ; l <= 3 ; l++ )
194 double val = sx[ l ] * sy[ m ];
195 xx += val * p[ l ].x;
196 yy += val * p[ l ].y;
203 if( 0 <= xx && xx < source.width( ) - 1 && 0 <= yy && yy < source.height( ) - 1 )
205 difference_type ixx =
static_cast< size_type
>( xx );
206 difference_type iyy =
static_cast< size_type
>( yy );
207 typename source_image_type::const_pointer p = &source( ixx, iyy, 0 );
211 target( x, y ) =
static_cast< typename target_image_type::value_type
>( ( p[ d0 ] + ( p[ d3 ] - p[ d0 ] ) * xx ) + ( p[ d1 ] - p[ d0 ] + ( p[ d0 ] - p[ d1 ] + p[ d2 ] - p[ d3 ] ) * xx ) * yy );
215 target( x, y ) =
static_cast< typename target_image_type::value_type
>( minimum );
223 template <
class TARGETTYPE,
class TARGETTYPEA,
class SOURCETYPE,
class SOURCETYPEA,
class CONTROLMESH >
224 static void non_rigid_transformation_( array3< TARGETTYPE, TARGETTYPEA > &target,
const array3< SOURCETYPE, SOURCETYPEA > &source,
const CONTROLMESH &control_mesh,
225 typename CONTROLMESH::difference_type mx = -1,
226 typename CONTROLMESH::difference_type my = -1,
227 typename CONTROLMESH::difference_type mz = -1,
228 typename CONTROLMESH::size_type thread_id = 0,
229 typename CONTROLMESH::size_type thread_num = 1
232 typedef array3< TARGETTYPE, TARGETTYPEA > target_image_type;
233 typedef array3< SOURCETYPE, SOURCETYPEA > source_image_type;
234 typedef CONTROLMESH control_mesh_type;
236 typedef typename target_image_type::size_type size_type;
237 typedef typename target_image_type::difference_type difference_type;
239 typedef typename target_image_type::value_type value_type;
240 value_type minimum = type_limits< value_type >::minimum( );
242 difference_type i, j, k;
244 double sx[ 4 ], sy[ 4 ], sz[ 4 ];
245 double stepW = control_mesh.width( ) == 1 ? 1.0 : target.width( ) /
static_cast< double >( control_mesh.width( ) - 1 );
246 double stepH = control_mesh.height( ) == 1 ? 1.0 : target.height( ) /
static_cast< double >( control_mesh.height( ) - 1 );
247 double stepD = control_mesh.depth( ) == 1 ? 1.0 : target.depth( ) /
static_cast< double >( control_mesh.depth( ) - 1 );
248 double _1_stepW = 1.0 / stepW;
249 double _1_stepH = 1.0 / stepH;
250 double _1_stepD = 1.0 / stepD;
251 double _1_ax = 1.0 / source.reso1( );
252 double _1_ay = 1.0 / source.reso2( );
253 double _1_az = 1.0 / source.reso3( );
255 difference_type d0, d1, d2, d3, d4, d5, d6, d7;
257 difference_type cx = source.width( ) / 2;
258 difference_type cy = source.height( ) / 2;
259 difference_type cz = source.depth( ) / 2;
260 typename source_image_type::const_pointer ppp = &source( cx, cy, cz );
262 d1 = &source( cx , cy + 1, cz ) - ppp;
263 d2 = &source( cx + 1, cy + 1, cz ) - ppp;
264 d3 = &source( cx + 1, cy , cz ) - ppp;
265 d4 = &source( cx , cy , cz + 1 ) - ppp;
266 d5 = &source( cx , cy + 1, cz + 1 ) - ppp;
267 d6 = &source( cx + 1, cy + 1, cz + 1 ) - ppp;
268 d7 = &source( cx + 1, cy , cz + 1 ) - ppp;
271 difference_type isx, isy, isz, iex, iey, iez;
272 difference_type mw = control_mesh.width( );
273 difference_type mh = control_mesh.height( );
274 difference_type md = control_mesh.depth( );
275 if( mx < 0 || mw <= mx || my < 0 || mh <= my || mz < 0 || md <= mz )
278 iex = target.width( ) - 1;
280 iey = target.height( ) - 1;
282 iez = target.depth( ) - 1;
286 isx =
static_cast< difference_type
>( ( mx - 2 ) * stepW );
287 iex =
static_cast< difference_type
>( ( mx + 2 ) * stepW );
288 isy =
static_cast< difference_type
>( ( my - 2 ) * stepH );
289 iey =
static_cast< difference_type
>( ( my + 2 ) * stepH );
290 isz =
static_cast< difference_type
>( ( mz - 2 ) * stepD );
291 iez =
static_cast< difference_type
>( ( mz + 2 ) * stepD );
293 difference_type tw = target.width( );
294 difference_type th = target.height( );
295 difference_type td = target.depth( );
296 isx = isx > 0 ? isx : 0;
297 isy = isy > 0 ? isy : 0;
298 isz = isz > 0 ? isz : 0;
299 iex = iex < tw ? iex : tw - 1;
300 iey = iey < th ? iey : th - 1;
301 iez = iez < td ? iez : td - 1;
305 for( difference_type z = isz + thread_id ; z <= iez ; z += thread_num )
308 k =
static_cast< difference_type
>( w );
312 FFD( w, sz[ 0 ], sz[ 1 ], sz[ 2 ], sz[ 3 ] );
314 for( difference_type y = isy ; y <= iey ; y++ )
317 j =
static_cast< difference_type
>( v );
321 FFD( v, sy[ 0 ], sy[ 1 ], sy[ 2 ], sy[ 3 ] );
323 for( difference_type x = isx ; x <= iex ; x++ )
326 i =
static_cast< difference_type
>( u );
330 FFD( u, sx[ 0 ], sx[ 1 ], sx[ 2 ], sx[ 3 ] );
332 double xx = 0.0, yy = 0.0, zz = 0.0;
333 for( difference_type n = 0 ; n <= 3 ; n++ )
335 for( difference_type m = 0 ; m <= 3 ; m++ )
337 typename control_mesh_type::const_pointer p = &control_mesh( i, j + m, k + n );
338 double vvv = sy[ m ] * sz[ n ];
339 for( difference_type l = 0 ; l <= 3 ; l++ )
341 double vv = sx[ l ] * vvv;
353 if( 0 <= xx && xx < source.width( ) - 1 && 0 <= yy && yy < source.height( ) - 1 && 0 <= zz && zz < source.depth( ) - 1 )
355 difference_type ixx =
static_cast< size_type
>( xx );
356 difference_type iyy =
static_cast< size_type
>( yy );
357 difference_type izz =
static_cast< size_type
>( zz );
358 typename source_image_type::const_pointer p = &source( ixx, iyy, izz );
363 double ct = ( p[ d0 ] + ( p[ d3 ] - p[ d0 ] ) * xx ) + ( p[ d1 ] - p[ d0 ] + ( p[ d0 ] - p[ d1 ] + p[ d2 ] - p[ d3 ] ) * xx ) * yy;
364 ct += ( ( p[ d4 ] + ( p[ d7 ] - p[ d4 ] ) * xx ) + ( p[ d5 ] - p[ d4 ] + ( p[ d4 ] - p[ d5 ] + p[ d6 ] - p[ d7 ] ) * xx ) * yy - ct ) * zz;
365 target( x, y, z ) =
static_cast< typename target_image_type::value_type
>( ct );
369 target( x, y, z ) =
static_cast< typename target_image_type::value_type
>( minimum );
376 struct ffd_coefficient
381 double &operator [](
size_t index ){
return( value[ index ] ); }
382 const double &operator [](
size_t index )
const {
return( value[ index ] ); }
388 double &operator [](
size_t index ){
return( value[ index ] ); }
389 const double &operator [](
size_t index )
const {
return( value[ index ] ); }
392 typedef size_t size_type;
393 typedef ptrdiff_t difference_type;
396 coefficient_type coeff_z;
399 template <
class CONTROLMESHTYPE >
400 void initialize( size_type width, size_type height, size_type depth,
const CONTROLMESHTYPE &control_mesh )
403 coeff_xy.resize( width, height );
405 double stepW = control_mesh.width( ) == 1 ? 1.0 : width /
static_cast< double >( control_mesh.width( ) - 1 );
406 double stepH = control_mesh.height( ) == 1 ? 1.0 : height /
static_cast< double >( control_mesh.height( ) - 1 );
407 double stepD = control_mesh.depth( ) == 1 ? 1.0 : depth /
static_cast< double >( control_mesh.depth( ) - 1 );
408 double _1_stepW = 1.0 / stepW;
409 double _1_stepH = 1.0 / stepH;
410 double _1_stepD = 1.0 / stepD;
412 for( size_type z = 0 ; z < coeff_z.size( ) ; z++ )
414 double w = z * _1_stepD;
415 w -=
static_cast< difference_type
>( w );
417 FFD( w, coeff_z[ z ][ 0 ], coeff_z[ z ][ 1 ], coeff_z[ z ][ 2 ], coeff_z[ z ][ 3 ] );
420 double coeff_x[ 4 ], coeff_y[ 4 ];
421 for( size_type y = 0 ; y < height ; y++ )
423 double v = y * _1_stepH;
424 v -=
static_cast< difference_type
>( v );
426 FFD( v, coeff_y[ 0 ], coeff_y[ 1 ], coeff_y[ 2 ], coeff_y[ 3 ] );
428 for( size_type x = 0 ; x < width ; x++ )
430 double u = x * _1_stepW;
431 u -=
static_cast< difference_type
>( u );
433 FFD( u, coeff_x[ 0 ], coeff_x[ 1 ], coeff_x[ 2 ], coeff_x[ 3 ] );
435 coeff_xy( x, y )[ 0 ] = coeff_x[ 0 ] * coeff_y[ 0 ];
436 coeff_xy( x, y )[ 1 ] = coeff_x[ 1 ] * coeff_y[ 0 ];
437 coeff_xy( x, y )[ 2 ] = coeff_x[ 2 ] * coeff_y[ 0 ];
438 coeff_xy( x, y )[ 3 ] = coeff_x[ 3 ] * coeff_y[ 0 ];
439 coeff_xy( x, y )[ 4 ] = coeff_x[ 0 ] * coeff_y[ 1 ];
440 coeff_xy( x, y )[ 5 ] = coeff_x[ 1 ] * coeff_y[ 1 ];
441 coeff_xy( x, y )[ 6 ] = coeff_x[ 2 ] * coeff_y[ 1 ];
442 coeff_xy( x, y )[ 7 ] = coeff_x[ 3 ] * coeff_y[ 1 ];
443 coeff_xy( x, y )[ 8 ] = coeff_x[ 0 ] * coeff_y[ 2 ];
444 coeff_xy( x, y )[ 9 ] = coeff_x[ 1 ] * coeff_y[ 2 ];
445 coeff_xy( x, y )[ 10 ] = coeff_x[ 2 ] * coeff_y[ 2 ];
446 coeff_xy( x, y )[ 11 ] = coeff_x[ 3 ] * coeff_y[ 2 ];
447 coeff_xy( x, y )[ 12 ] = coeff_x[ 0 ] * coeff_y[ 3 ];
448 coeff_xy( x, y )[ 13 ] = coeff_x[ 1 ] * coeff_y[ 3 ];
449 coeff_xy( x, y )[ 14 ] = coeff_x[ 2 ] * coeff_y[ 3 ];
450 coeff_xy( x, y )[ 15 ] = coeff_x[ 3 ] * coeff_y[ 3 ];
459 template <
class TARGETTYPE,
class TARGETTYPEA,
class SOURCETYPE,
class SOURCETYPEA,
class CONTROLMESH >
460 static void non_rigid_transformation_( array2< TARGETTYPE, TARGETTYPEA > &target,
const array2< SOURCETYPE, SOURCETYPEA > &source,
const CONTROLMESH &control_mesh,
461 const ffd_coefficient &ffd_coeff,
462 typename CONTROLMESH::difference_type mx = -1,
463 typename CONTROLMESH::difference_type my = -1,
464 typename CONTROLMESH::difference_type mz = -1,
465 typename CONTROLMESH::size_type thread_id = 0,
466 typename CONTROLMESH::size_type thread_num = 1
469 typedef array2< TARGETTYPE, TARGETTYPEA > target_image_type;
470 typedef array2< SOURCETYPE, SOURCETYPEA > source_image_type;
471 typedef CONTROLMESH control_mesh_type;
473 typedef typename target_image_type::size_type size_type;
474 typedef typename target_image_type::difference_type difference_type;
475 typedef typename target_image_type::value_type value_type;
476 value_type minimum = type_limits< value_type >::minimum( );
478 difference_type i, j;
479 double stepW = control_mesh.width( ) == 1 ? 1.0 : target.width( ) /
static_cast< double >( control_mesh.width( ) - 1 );
480 double stepH = control_mesh.height( ) == 1 ? 1.0 : target.height( ) /
static_cast< double >( control_mesh.height( ) - 1 );
481 double _1_stepW = 1.0 / stepW;
482 double _1_stepH = 1.0 / stepH;
483 double _1_ax = 1.0 / source.reso1( );
484 double _1_ay = 1.0 / source.reso2( );
486 difference_type d0, d1, d2, d3, dm;
488 difference_type cx = source.width( ) / 2;
489 difference_type cy = source.height( ) / 2;
490 typename source_image_type::const_pointer ppp = &source( cx, cy );
492 d1 = &source( cx , cy + 1 ) - ppp;
493 d2 = &source( cx + 1, cy + 1 ) - ppp;
494 d3 = &source( cx + 1, cy ) - ppp;
495 dm = &control_mesh( 0, 1, 0 ) - &control_mesh( 0, 0, 0 );
498 difference_type isx, isy, iex, iey;
499 difference_type mw = control_mesh.width( );
500 difference_type mh = control_mesh.height( );
501 if( mx < 0 || mw <= mx || my < 0 || mh <= my )
504 iex = target.width( ) - 1;
506 iey = target.height( ) - 1;
510 isx =
static_cast< difference_type
>( ( mx - 2 ) * stepW );
511 iex =
static_cast< difference_type
>( ( mx + 2 ) * stepW );
512 isy =
static_cast< difference_type
>( ( my - 2 ) * stepH );
513 iey =
static_cast< difference_type
>( ( my + 2 ) * stepH );
515 difference_type tw = target.width( );
516 difference_type th = target.height( );
517 isx = isx > 0 ? isx : 0;
518 isy = isy > 0 ? isy : 0;
519 iex = iex < tw ? iex : tw - 1;
520 iey = iey < th ? iey : th - 1;
524 for( difference_type y = isy + thread_id ; y <= iey ; y += thread_num )
526 j =
static_cast< difference_type
>( y * _1_stepH ) - 1;
528 for( difference_type x = isx ; x <= iex ; x++ )
530 i =
static_cast< difference_type
>( x * _1_stepW ) - 1;
532 const ffd_coefficient::coefficients &coeff = ffd_coeff.coeff_xy( x, y );
534 double xx = 0.0, yy = 0.0;
535 typename control_mesh_type::const_pointer p = &control_mesh( i, j, 0 );
537 xx += coeff[ 0 ] * p[ 0 ].x; yy += coeff[ 0 ] * p[ 0 ].y;
538 xx += coeff[ 1 ] * p[ 1 ].x; yy += coeff[ 1 ] * p[ 1 ].y;
539 xx += coeff[ 2 ] * p[ 2 ].x; yy += coeff[ 2 ] * p[ 2 ].y;
540 xx += coeff[ 3 ] * p[ 3 ].x; yy += coeff[ 3 ] * p[ 3 ].y;
544 xx += coeff[ 4 ] * p[ 0 ].x; yy += coeff[ 4 ] * p[ 0 ].y;
545 xx += coeff[ 5 ] * p[ 1 ].x; yy += coeff[ 5 ] * p[ 1 ].y;
546 xx += coeff[ 6 ] * p[ 2 ].x; yy += coeff[ 6 ] * p[ 2 ].y;
547 xx += coeff[ 7 ] * p[ 3 ].x; yy += coeff[ 7 ] * p[ 3 ].y;
551 xx += coeff[ 8 ] * p[ 0 ].x; yy += coeff[ 8 ] * p[ 0 ].y;
552 xx += coeff[ 9 ] * p[ 1 ].x; yy += coeff[ 9 ] * p[ 1 ].y;
553 xx += coeff[ 10 ] * p[ 2 ].x; yy += coeff[ 10 ] * p[ 2 ].y;
554 xx += coeff[ 11 ] * p[ 3 ].x; yy += coeff[ 11 ] * p[ 3 ].y;
558 xx += coeff[ 12 ] * p[ 0 ].x; yy += coeff[ 12 ] * p[ 0 ].y;
559 xx += coeff[ 13 ] * p[ 1 ].x; yy += coeff[ 13 ] * p[ 1 ].y;
560 xx += coeff[ 14 ] * p[ 2 ].x; yy += coeff[ 14 ] * p[ 2 ].y;
561 xx += coeff[ 15 ] * p[ 3 ].x; yy += coeff[ 15 ] * p[ 3 ].y;
566 if( 0 <= xx && xx < source.width( ) - 1 && 0 <= yy && yy < source.height( ) - 1 )
568 difference_type ixx =
static_cast< size_type
>( xx );
569 difference_type iyy =
static_cast< size_type
>( yy );
570 typename source_image_type::const_pointer p = &source( ixx, iyy, 0 );
574 target( x, y ) =
static_cast< typename target_image_type::value_type
>( ( p[ d0 ] + ( p[ d3 ] - p[ d0 ] ) * xx ) + ( p[ d1 ] - p[ d0 ] + ( p[ d0 ] - p[ d1 ] + p[ d2 ] - p[ d3 ] ) * xx ) * yy );
578 target( x, y ) =
static_cast< typename target_image_type::value_type
>( minimum );
587 template <
class TARGETTYPE,
class TARGETTYPEA,
class SOURCETYPE,
class SOURCETYPEA,
class CONTROLMESH >
588 static void non_rigid_transformation_( array3< TARGETTYPE, TARGETTYPEA > &target,
const array3< SOURCETYPE, SOURCETYPEA > &source,
const CONTROLMESH &control_mesh,
589 const ffd_coefficient &ffd_coeff,
590 typename CONTROLMESH::difference_type mx = -1,
591 typename CONTROLMESH::difference_type my = -1,
592 typename CONTROLMESH::difference_type mz = -1,
593 typename CONTROLMESH::size_type thread_id = 0,
594 typename CONTROLMESH::size_type thread_num = 1
597 typedef array3< TARGETTYPE, TARGETTYPEA > target_image_type;
598 typedef array3< SOURCETYPE, SOURCETYPEA > source_image_type;
599 typedef CONTROLMESH control_mesh_type;
601 typedef typename target_image_type::size_type size_type;
602 typedef typename target_image_type::difference_type difference_type;
603 typedef typename target_image_type::value_type value_type;
604 value_type minimum = type_limits< value_type >::minimum( );
606 difference_type i, j, k;
608 double stepW = control_mesh.width( ) == 1 ? 1.0 : target.width( ) /
static_cast< double >( control_mesh.width( ) - 1 );
609 double stepH = control_mesh.height( ) == 1 ? 1.0 : target.height( ) /
static_cast< double >( control_mesh.height( ) - 1 );
610 double stepD = control_mesh.depth( ) == 1 ? 1.0 : target.depth( ) /
static_cast< double >( control_mesh.depth( ) - 1 );
611 double _1_stepW = 1.0 / stepW;
612 double _1_stepH = 1.0 / stepH;
613 double _1_stepD = 1.0 / stepD;
614 double _1_ax = 1.0 / source.reso1( );
615 double _1_ay = 1.0 / source.reso2( );
616 double _1_az = 1.0 / source.reso3( );
618 difference_type d0, d1, d2, d3, d4, d5, d6, d7, dm;
620 difference_type cx = source.width( ) / 2;
621 difference_type cy = source.height( ) / 2;
622 difference_type cz = source.depth( ) / 2;
623 typename source_image_type::const_pointer ppp = &source( cx, cy, cz );
625 d1 = &source( cx , cy + 1, cz ) - ppp;
626 d2 = &source( cx + 1, cy + 1, cz ) - ppp;
627 d3 = &source( cx + 1, cy , cz ) - ppp;
628 d4 = &source( cx , cy , cz + 1 ) - ppp;
629 d5 = &source( cx , cy + 1, cz + 1 ) - ppp;
630 d6 = &source( cx + 1, cy + 1, cz + 1 ) - ppp;
631 d7 = &source( cx + 1, cy , cz + 1 ) - ppp;
632 dm = &control_mesh( 0, 1, 0 ) - &control_mesh( 0, 0, 0 );
635 difference_type isx, isy, isz, iex, iey, iez;
636 difference_type mw = control_mesh.width( );
637 difference_type mh = control_mesh.height( );
638 difference_type md = control_mesh.depth( );
639 if( mx < 0 || mw <= mx || my < 0 || mh <= my || mz < 0 || md <= mz )
642 iex = target.width( ) - 1;
644 iey = target.height( ) - 1;
646 iez = target.depth( ) - 1;
650 isx =
static_cast< difference_type
>( ( mx - 2 ) * stepW );
651 iex =
static_cast< difference_type
>( ( mx + 2 ) * stepW );
652 isy =
static_cast< difference_type
>( ( my - 2 ) * stepH );
653 iey =
static_cast< difference_type
>( ( my + 2 ) * stepH );
654 isz =
static_cast< difference_type
>( ( mz - 2 ) * stepD );
655 iez =
static_cast< difference_type
>( ( mz + 2 ) * stepD );
657 difference_type tw = target.width( );
658 difference_type th = target.height( );
659 difference_type td = target.depth( );
660 isx = isx > 0 ? isx : 0;
661 isy = isy > 0 ? isy : 0;
662 isz = isz > 0 ? isz : 0;
663 iex = iex < tw ? iex : tw - 1;
664 iey = iey < th ? iey : th - 1;
665 iez = iez < td ? iez : td - 1;
668 typedef ffd_coefficient::coefficient_type coefficient_type;
669 const coefficient_type &ffd_coeff_z = ffd_coeff.coeff_z;
671 for( difference_type z = isz + thread_id ; z <= iez ; z += thread_num )
673 k =
static_cast< difference_type
>( z * _1_stepD ) - 1;
675 sz[ 0 ] = ffd_coeff_z[ z ][ 0 ];
676 sz[ 1 ] = ffd_coeff_z[ z ][ 1 ];
677 sz[ 2 ] = ffd_coeff_z[ z ][ 2 ];
678 sz[ 3 ] = ffd_coeff_z[ z ][ 3 ];
680 for( difference_type y = isy ; y <= iey ; y++ )
682 j =
static_cast< difference_type
>( y * _1_stepH ) - 1;
684 for( difference_type x = isx ; x <= iex ; x++ )
686 i =
static_cast< difference_type
>( x * _1_stepW ) - 1;
688 double xx = 0.0, yy = 0.0, zz = 0.0, val;
689 const ffd_coefficient::coefficients &coeff = ffd_coeff.coeff_xy( x, y );
691 for( difference_type n = 0 ; n <= 3 ; n++ )
693 typename control_mesh_type::const_pointer p = &control_mesh( i, j, k + n );
695 val = sz[ n ] * coeff[ 0 ]; xx += val * p[ 0 ].x; yy += val * p[ 0 ].y; zz += val * p[ 0 ].z;
696 val = sz[ n ] * coeff[ 1 ]; xx += val * p[ 1 ].x; yy += val * p[ 1 ].y; zz += val * p[ 1 ].z;
697 val = sz[ n ] * coeff[ 2 ]; xx += val * p[ 2 ].x; yy += val * p[ 2 ].y; zz += val * p[ 2 ].z;
698 val = sz[ n ] * coeff[ 3 ]; xx += val * p[ 3 ].x; yy += val * p[ 3 ].y; zz += val * p[ 3 ].z;
702 val = sz[ n ] * coeff[ 4 ]; xx += val * p[ 0 ].x; yy += val * p[ 0 ].y; zz += val * p[ 0 ].z;
703 val = sz[ n ] * coeff[ 5 ]; xx += val * p[ 1 ].x; yy += val * p[ 1 ].y; zz += val * p[ 1 ].z;
704 val = sz[ n ] * coeff[ 6 ]; xx += val * p[ 2 ].x; yy += val * p[ 2 ].y; zz += val * p[ 2 ].z;
705 val = sz[ n ] * coeff[ 7 ]; xx += val * p[ 3 ].x; yy += val * p[ 3 ].y; zz += val * p[ 3 ].z;
709 val = sz[ n ] * coeff[ 8 ]; xx += val * p[ 0 ].x; yy += val * p[ 0 ].y; zz += val * p[ 0 ].z;
710 val = sz[ n ] * coeff[ 9 ]; xx += val * p[ 1 ].x; yy += val * p[ 1 ].y; zz += val * p[ 1 ].z;
711 val = sz[ n ] * coeff[ 10 ]; xx += val * p[ 2 ].x; yy += val * p[ 2 ].y; zz += val * p[ 2 ].z;
712 val = sz[ n ] * coeff[ 11 ]; xx += val * p[ 3 ].x; yy += val * p[ 3 ].y; zz += val * p[ 3 ].z;
716 val = sz[ n ] * coeff[ 12 ]; xx += val * p[ 0 ].x; yy += val * p[ 0 ].y; zz += val * p[ 0 ].z;
717 val = sz[ n ] * coeff[ 13 ]; xx += val * p[ 1 ].x; yy += val * p[ 1 ].y; zz += val * p[ 1 ].z;
718 val = sz[ n ] * coeff[ 14 ]; xx += val * p[ 2 ].x; yy += val * p[ 2 ].y; zz += val * p[ 2 ].z;
719 val = sz[ n ] * coeff[ 15 ]; xx += val * p[ 3 ].x; yy += val * p[ 3 ].y; zz += val * p[ 3 ].z;
726 if( 0 <= xx && xx < source.width( ) - 1 && 0 <= yy && yy < source.height( ) - 1 && 0 <= zz && zz < source.depth( ) - 1 )
728 difference_type ixx =
static_cast< size_type
>( xx );
729 difference_type iyy =
static_cast< size_type
>( yy );
730 difference_type izz =
static_cast< size_type
>( zz );
731 typename source_image_type::const_pointer p = &source( ixx, iyy, izz );
736 double ct = ( p[ d0 ] + ( p[ d3 ] - p[ d0 ] ) * xx ) + ( p[ d1 ] - p[ d0 ] + ( p[ d0 ] - p[ d1 ] + p[ d2 ] - p[ d3 ] ) * xx ) * yy;
737 ct += ( ( p[ d4 ] + ( p[ d7 ] - p[ d4 ] ) * xx ) + ( p[ d5 ] - p[ d4 ] + ( p[ d4 ] - p[ d5 ] + p[ d6 ] - p[ d7 ] ) * xx ) * yy - ct ) * zz;
738 target( x, y, z ) =
static_cast< typename target_image_type::value_type
>( ct );
742 target( x, y, z ) =
static_cast< typename target_image_type::value_type
>( minimum );
750 template <
class TARGETTYPE,
class SOURCETYPE,
class CONTROLMESH >
751 class non_rigid_registration_thread :
public thread< non_rigid_registration_thread< TARGETTYPE, SOURCETYPE, CONTROLMESH > >
754 typedef TARGETTYPE target_image_type;
755 typedef SOURCETYPE source_image_type;
756 typedef CONTROLMESH control_mesh_type;
757 typedef thread< non_rigid_registration_thread< TARGETTYPE, SOURCETYPE, CONTROLMESH > > base;
758 typedef typename base::thread_exit_type thread_exit_type;
759 typedef typename TARGETTYPE::size_type size_type;
766 target_image_type *target_;
767 const source_image_type *source_;
768 const control_mesh_type *control_mesh_;
772 const ffd_coefficient *ffd_coefficient_;
775 const non_rigid_registration_thread& operator =(
const non_rigid_registration_thread &p );
778 void setup_parameters( target_image_type &target,
const source_image_type &source,
const control_mesh_type &control_mesh,
779 const ffd_coefficient &ffd_coefficient__,
size_t mx, size_type my, size_type mz, size_type thread_id, size_type thread_num )
783 control_mesh_ = &control_mesh;
784 ffd_coefficient_ = &ffd_coefficient__;
788 thread_id_ = thread_id;
789 thread_num_ = thread_num;
792 void setup_parameters( target_image_type &target,
const source_image_type &source,
const control_mesh_type &control_mesh,
793 size_t mx, size_type my, size_type mz, size_type thread_id, size_type thread_num )
797 control_mesh_ = &control_mesh;
798 ffd_coefficient_ = NULL;
802 thread_id_ = thread_id;
803 thread_num_ = thread_num;
806 non_rigid_registration_thread( size_type
id = 0, size_type num = 1 ) : thread_id_( id ), thread_num_( num ),
807 target_( NULL ), source_( NULL ), control_mesh_( NULL ), mx_( -1 ), my_( -1 ), mz_( -1 ), ffd_coefficient_( NULL )
811 non_rigid_registration_thread(
const non_rigid_registration_thread &p ) : base( p ), thread_id_( p.thread_id_ ), thread_num_( p.thread_num_ ),
812 target_( p.target_ ), source_( p.source_ ), control_mesh_( p.control_mesh_ ), mx_( p.mx_ ), my_( p.my_ ), mz_( p.mz_ ), ffd_coefficient_( p.ffd_coefficient_ )
818 virtual thread_exit_type thread_function( )
820 if( ffd_coefficient_ != NULL )
822 non_rigid_transformation_( *target_, *source_, *control_mesh_, *ffd_coefficient_, mx_, my_, mz_, thread_id_, thread_num_ );
826 non_rigid_transformation_( *target_, *source_, *control_mesh_, mx_, my_, mz_, thread_id_, thread_num_ );
834 template <
class TARGETTYPE,
class SOURCETYPE,
class CONTROLMESH >
835 static bool transformation( TARGETTYPE &target,
const SOURCETYPE &source,
const CONTROLMESH &control_mesh,
836 typename CONTROLMESH::difference_type mx = -1,
837 typename CONTROLMESH::difference_type my = -1,
838 typename CONTROLMESH::difference_type mz = -1,
839 typename CONTROLMESH::size_type thread_num = 0
842 if(
is_same_object( target, source ) || target.empty( ) || source.empty( ) )
847 typedef TARGETTYPE target_image_type;
848 typedef SOURCETYPE source_image_type;
849 typedef CONTROLMESH control_mesh_type;
850 typedef typename target_image_type::size_type size_type;
851 typedef non_rigid_registration_thread< target_image_type, source_image_type, control_mesh_type > _non_rigid_registration_thread_;
853 if( thread_num == 0 )
855 thread_num =
static_cast< size_type
>(
get_cpu_num( ) );
858 _non_rigid_registration_thread_ *thread =
new _non_rigid_registration_thread_[ thread_num ];
861 for( i = 0 ; i < thread_num ; i++ )
863 thread[ i ].setup_parameters( target, source, control_mesh, mx, my, mz, i, thread_num );
875 template <
class TARGETTYPE,
class SOURCETYPE,
class CONTROLMESH >
876 static bool transformation( TARGETTYPE &target,
const SOURCETYPE &source,
const CONTROLMESH &control_mesh,
const ffd_coefficient &ffd_coeff,
877 typename CONTROLMESH::difference_type mx = -1,
878 typename CONTROLMESH::difference_type my = -1,
879 typename CONTROLMESH::difference_type mz = -1,
880 typename CONTROLMESH::size_type thread_num = 0
883 if(
is_same_object( target, source ) || target.empty( ) || source.empty( ) )
888 typedef TARGETTYPE target_image_type;
889 typedef SOURCETYPE source_image_type;
890 typedef CONTROLMESH control_mesh_type;
891 typedef typename target_image_type::size_type size_type;
892 typedef non_rigid_registration_thread< target_image_type, source_image_type, control_mesh_type > _non_rigid_registration_thread_;
894 if( thread_num == 0 )
896 thread_num =
static_cast< size_type
>(
get_cpu_num( ) );
899 _non_rigid_registration_thread_ *thread =
new _non_rigid_registration_thread_[ thread_num ];
902 for( i = 0 ; i < thread_num ; i++ )
904 thread[ i ].setup_parameters( target, source, control_mesh, ffd_coeff, mx, my, mz, i, thread_num );
917 template <
class TARGETTYPE,
class SOURCETYPE,
class CONTROLMESH >
918 struct registration_functor :
public thread< registration_functor< TARGETTYPE, SOURCETYPE, CONTROLMESH > >
920 typedef TARGETTYPE target_image_type;
921 typedef SOURCETYPE source_image_type;
922 typedef CONTROLMESH control_mesh_type;
923 typedef typename TARGETTYPE::size_type size_type;
924 typedef typename TARGETTYPE::difference_type difference_type;
925 typedef typename CONTROLMESH::value_type vector_type;
926 typedef matrix< double > matrix_type;
927 typedef thread< registration_functor< TARGETTYPE, SOURCETYPE, CONTROLMESH > > base;
928 typedef typename base::thread_exit_type thread_exit_type;
930 array< unsigned int * > target;
931 target_image_type transformed_image;
932 const source_image_type &source;
933 const control_mesh_type &control_mesh;
934 control_mesh_type control_mesh_tmp;
935 difference_type x, y, z;
937 array2< unsigned int > h;
938 array< unsigned int > hh;
939 array< unsigned int > __no_data_is_associated__;
941 difference_type minimum;
942 difference_type maximum;
944 ffd_coefficient ffd_coeff;
948 template <
class IMAGETYPE >
949 static difference_type get_minimum(
const IMAGETYPE &image )
951 typedef typename IMAGETYPE::value_type value_type;
952 value_type min = image[ 0 ];
953 for( size_type i = 1 ; i < image.size( ) ; i++ )
955 if( min > image[ i ] )
960 return( static_cast< difference_type >( min ) );
964 static const T get_minimum(
const T &v1,
const T &v2 )
966 return( v1 < v2 ? v1 : v2 );
969 template <
class IMAGETYPE >
970 static difference_type get_maximum(
const IMAGETYPE &image )
972 typedef typename IMAGETYPE::value_type value_type;
973 value_type max = image[ 0 ];
974 for( size_type i = 1 ; i < image.size( ) ; i++ )
976 if( max < image[ i ] )
981 return( static_cast< difference_type >( max ) );
985 static const T get_maximum(
const T &v1,
const T &v2 )
987 return( v1 > v2 ? v1 : v2 );
990 registration_functor(
const target_image_type &tgt,
const source_image_type &src,
const control_mesh_type &cmesh, size_type bin )
991 : target( tgt.size( ) ), transformed_image( tgt ), source( src ), control_mesh ( cmesh ), control_mesh_tmp( cmesh ), x( 0 ), y( 0 ), z( 0 ), BIN( bin )
994 ffd_coeff.initialize( tgt.width( ), tgt.height( ), tgt.depth( ), control_mesh );
997 transformation( transformed_image, source, control_mesh, ffd_coeff );
999 minimum = get_maximum( get_minimum( get_minimum( tgt ), get_minimum( src ) ), static_cast< difference_type >(-1000) );
1000 maximum = get_maximum( get_maximum( tgt ), get_maximum( src ) );
1001 h.resize( ( maximum - minimum + 1 ) / BIN + 1, ( maximum - minimum + 1 ) / BIN + 1 );
1002 hh.resize( ( maximum - minimum + 1 ) / BIN + 1, 1 );
1003 __no_data_is_associated__.resize( ( maximum - minimum + 1 ) / BIN + 1, 1 );
1005 size_type count = 0;
1006 difference_type upper = h.width( );
1007 double _1_bin = 1.0 / BIN;
1008 for(
size_t i = 0 ; i < tgt.size( ) ; i++ )
1010 difference_type v1 =
static_cast< difference_type
>( ( tgt[ i ] - minimum ) * _1_bin );
1011 if( v1 < 0 || upper <= v1 )
1013 target[ i ] = &__no_data_is_associated__[ 0 ];
1016 target[ i ] = &h( 0, v1 );
1029 for( size_type i = 0 ; i < hh.size( ) ; i++ )
1033 double v = hh[ i ] /
static_cast< double >( count );
1034 H1 -= v * std::log( v );
1039 void force_initialize( )
1041 ffd_coeff.initialize( transformed_image.width( ), transformed_image.height( ), transformed_image.depth( ), control_mesh );
1044 void initialize( difference_type i, difference_type j, difference_type k )
1049 control_mesh_tmp = control_mesh;
1050 transformation( transformed_image, source, control_mesh, ffd_coeff );
1053 void apply_control_point_to_mesh( control_mesh_type &cmesh )
const
1055 cmesh( x, y, z ) = control_mesh_tmp( x, y, z );
1058 template <
class PARAMETER >
1059 double operator ()(
const PARAMETER &p )
1061 return( evaluate_error( p,
false ) );
1064 template <
class PARAMETER >
1065 double evaluate_error(
const PARAMETER &p,
bool use_thread =
true )
1067 control_mesh_tmp( x, y, z ).x = control_mesh( x, y, z ).x + p[ 0 ];
1068 control_mesh_tmp( x, y, z ).y = control_mesh( x, y, z ).y + p[ 1 ];
1069 control_mesh_tmp( x, y, z ).z = control_mesh( x, y, z ).z + p[ 2 ];
1073 non_rigid_transformation_( transformed_image, source, control_mesh_tmp, ffd_coeff, x, y, z );
1077 transformation( transformed_image, source, control_mesh_tmp, ffd_coeff, x, y, z );
1081 __no_data_is_associated__.fill( );
1084 size_type count = 0;
1085 double _1_bin = 1.0 / BIN;
1087 for(
size_t i = 0 ; i < target.size( ) ; i++ )
1089 difference_type v2 =
static_cast< difference_type
>( ( transformed_image[ i ] - minimum ) * _1_bin );
1095 target[ i ][ v2 ]++;
1106 double H2 = 0.0, H12 = 0.0, _1_count = 1.0 /
static_cast< double >( count );
1108 for( size_type i = 0 ; i < hh.size( ) ; i++ )
1112 double v = hh[ i ] * _1_count;
1113 H2 -= v * std::log( v );
1116 for( size_type j = 0 ; j < hh.size( ) ; j++ )
1120 double v = ph[ j ] * _1_count;
1121 H12 -= v * std::log( v );
1127 return( -( H1 + H2 ) / H12 );
1133 double min_range(
const double &v1,
const double &v2,
const double &v3 )
const
1135 double v = v1 < v2 ? v1 : v2;
1136 v = v < v3 ? v : v3;
1140 double max_range(
const double &v1,
const double &v2,
const double &v3 )
const
1142 double v = v1 > v2 ? v1 : v2;
1143 v = v > v3 ? v : v3;
1147 double min_range(
const double &v1,
const double &v2,
const double &v3,
1148 const double &v4,
const double &v5,
const double &v6,
1149 const double &v7,
const double &v8,
const double &v9 )
const
1151 double vv1 = min_range( v1, v2, v3 );
1152 double vv2 = min_range( v4, v5, v6 );
1153 double vv3 = min_range( v7, v8, v9 );
1154 return( min_range( vv1, vv2, vv3 ) );
1157 double max_range(
const double &v1,
const double &v2,
const double &v3,
1158 const double &v4,
const double &v5,
const double &v6,
1159 const double &v7,
const double &v8,
const double &v9 )
const
1161 double vv1 = max_range( v1, v2, v3 );
1162 double vv2 = max_range( v4, v5, v6 );
1163 double vv3 = max_range( v7, v8, v9 );
1164 return( max_range( vv1, vv2, vv3 ) );
1168 virtual thread_exit_type thread_function( )
1170 typedef __minimization_utility__::__no_copy_constructor_functor__< registration_functor< TARGETTYPE, SOURCETYPE, CONTROLMESH > > no_constructor_functor_type;
1173 double search_length = 0.95;
1174 matrix_type p( 3, 1 ), dirs = matrix_type::identity( 3, 3 ), bound( 3, 2 );
1218 bound( 0, 0 ) = ( control_mesh( x - 1, y , z ).x - control_mesh( x, y, z ).x ) * search_length;
1219 bound( 0, 1 ) = ( control_mesh( x + 1, y , z ).x - control_mesh( x, y, z ).x ) * search_length;
1220 bound( 1, 0 ) = ( control_mesh( x , y - 1, z ).y - control_mesh( x, y, z ).y ) * search_length;
1221 bound( 1, 1 ) = ( control_mesh( x , y + 1, z ).y - control_mesh( x, y, z ).y ) * search_length;
1222 bound( 2, 0 ) = ( control_mesh( x , y , z - 1 ).z - control_mesh( x, y, z ).z ) * search_length;
1223 bound( 2, 1 ) = ( control_mesh( x , y , z + 1 ).z - control_mesh( x, y, z ).z ) * search_length;
1231 matrix_type dir( p.size( ), 1 ), tmp( p.size( ), 1 );
1236 no_constructor_functor_type f( *
this );
1237 __minimization_utility__::__convert_to_vector_functor__< typename matrix_type::value_type, typename matrix_type::allocator_type, no_constructor_functor_type > functor( p, dir, tmp, f );
1240 double len = 0.0, distance = 1.0;
1241 for( i = 0 ; i < dir.size( ) ; i++ )
1243 tmp[ i ] = p[ i ] + distance;
1246 tmp[ i ] = p[ i ] - distance;
1252 len += dir[ i ] * dir[ i ];
1258 len = std::sqrt( len );
1259 for( i = 0 ; i < dir.size( ) ; i++ )
1270 double l1, l2, xx = 0.0;
1271 if( __minimization_utility__::clipping_length( l1, l2, p, dir, bound ) )
1286 vector_type &v = control_mesh_tmp( x, y, z );
1287 v = control_mesh( x, y, z );
1324 template <
class TARGETTYPE >
1350 : target( tgt ), control_mesh( divW + 1, divH + 1, divD + 1, 2 ), BIN( bin )
1363 template <
class SOURCETYPE >
1364 void apply(
const SOURCETYPE &source,
double tolerance, size_type max_loop = 3, size_type coarse_to_fine_step = 1, size_type thread_num = 0 )
1378 template <
class SOURCETYPE,
class Functor >
1379 void apply(
const SOURCETYPE &source,
double tolerance, size_type max_loop, size_type coarse_to_fine_step, size_type thread_num, Functor callback )
1381 typedef __non_rigid_registration_utility__::registration_functor< TARGETTYPE, SOURCETYPE, control_mesh_type > non_rigid_registration_functor_type;
1382 typedef __minimization_utility__::__no_copy_constructor_functor__< non_rigid_registration_functor_type > no_constructor_functor_type;
1384 size_type divW = control_mesh.width( ) - 1;
1385 size_type divH = control_mesh.height( ) - 1;
1386 size_type divD = control_mesh.depth( ) - 1;
1389 double stepW = divW == 0 ? 0 : source.width( ) /
static_cast< double >( divW );
1390 double stepH = divH == 0 ? 0 : source.height( ) /
static_cast< double >( divH );
1391 double stepD = divD == 0 ? 0 : source.depth( ) /
static_cast< double >( divD );
1392 difference_type w = control_mesh.width( );
1393 difference_type h = control_mesh.height( );
1394 difference_type d = control_mesh.depth( );
1395 for( difference_type k = -2 ; k <= d + 1 ; k++ )
1397 for( difference_type j = -2 ; j <= h + 1 ; j++ )
1399 for( difference_type i = -2 ; i <= w + 1 ; i++ )
1402 v.
x = i * stepW * source.reso1( );
1403 v.
y = j * stepH * source.reso2( );
1404 v.
z = k * stepD * source.reso3( );
1411 if( thread_num == 0 )
1413 thread_num =
static_cast< size_type
>(
get_cpu_num( ) );
1417 non_rigid_registration_functor_type **f =
new non_rigid_registration_functor_type*[ thread_num ];
1419 for( size_type i = 0 ; i < thread_num ; i++ )
1421 f[ i ] =
new non_rigid_registration_functor_type( target, source, control_mesh, BIN );
1425 double err = f[ 0 ]->evaluate_error( matrix_type::zero( 3, 1 ) );
1426 double old_err = err;
1429 std::vector< control_point_index_type > control_point_list;
1435 size_type fine_step_loop = 0;
1436 while( fine_step_loop++ < coarse_to_fine_step )
1440 difference_type w = control_mesh.width( );
1441 difference_type h = control_mesh.height( );
1442 difference_type d = control_mesh.depth( );
1443 size_type X[] = { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2 };
1444 size_type Y[] = { 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2 };
1445 size_type Z[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2 };
1447 control_point_list.clear( );
1449 for( size_type s = 0 ; s < 27 ; s++ )
1451 for( difference_type k = Z[ s ] ; k < d ; k += 3 )
1453 for( difference_type j = Y[ s ] ; j < h ; j += 3 )
1455 for( difference_type i = X[ s ] ; i < w ; i += 3 )
1466 size_type loop = 0, count = 0;
1467 double max_iteration_num = control_point_list.size( ) * max_loop /
static_cast< double >( thread_num );
1468 while( loop++ < max_loop )
1470 for( size_type i = 0 ; i < control_point_list.size( ) ; )
1472 size_type numthreads;
1473 for( numthreads = 0 ; numthreads < thread_num && i < control_point_list.size( ) ; numthreads++, i++ )
1475 control_point_index_type &v = control_point_list[ i ];
1476 f[ numthreads ]->initialize( v.x, v.y, v.z );
1480 for( size_type t = 0 ; t < numthreads ; t++ )
1486 for( size_type t = 0 ; t < numthreads ; t++ )
1488 f[ t ]->wait( INFINITE );
1492 for( size_type t = 0 ; t < numthreads ; t++ )
1498 for( size_type t = 0 ; t < numthreads ; t++ )
1500 f[ t ]->apply_control_point_to_mesh( control_mesh );
1503 callback_( 100.0 / max_iteration_num * count++ );
1506 err = f[ 0 ]->evaluate_error( matrix_type::zero( 3, 1 ) );
1508 if( 2.0 * std::abs( old_err - err ) < tolerance * ( std::abs( old_err ) + std::abs( err ) ) )
1517 if( fine_step_loop < coarse_to_fine_step )
1520 control_mesh_type cmesh = control_mesh;
1521 difference_type w = control_mesh.width( ) * 2 - 1;
1522 difference_type h = control_mesh.height( ) * 2 - 1;
1523 difference_type d = control_mesh.depth( ) * 2 - 1;
1527 control_mesh.resize( w, h, d );
1529 double stepW = w == 1 ? 0 : source.width( ) /
static_cast< double >( w - 1 );
1530 double stepH = h == 1 ? 0 : source.height( ) /
static_cast< double >( h - 1 );
1531 double stepD = d == 1 ? 0 : source.depth( ) /
static_cast< double >( d - 1 );
1532 for( difference_type k = -2 ; k <= d + 1 ; k++ )
1534 for( difference_type j = -2 ; j <= h + 1 ; j++ )
1536 for( difference_type i = -2 ; i <= w + 1 ; i++ )
1539 v.
x = i * stepW * source.reso1( );
1540 v.
y = j * stepH * source.reso2( );
1541 v.
z = k * stepD * source.reso3( );
1546 for( difference_type k = 0 ; k < d ; k++ )
1548 bool k_is_odd = ( k % 2 ) == 1;
1549 difference_type kk = k / 2;
1551 for( difference_type j = 0 ; j < h ; j++ )
1553 bool j_is_odd = ( j % 2 ) == 1;
1554 difference_type jj = j / 2;
1556 for( difference_type i = 0 ; i < w ; i++ )
1558 bool i_is_odd = ( i % 2 ) == 1;
1559 difference_type ii = i / 2;
1561 if( i_is_odd && j_is_odd && k_is_odd )
1563 control_mesh( i, j, k ) = ( cmesh( ii , jj , kk ) + cmesh( ii , jj , kk + 1 ) +
1564 cmesh( ii , jj + 1, kk ) + cmesh( ii , jj + 1, kk + 1 ) +
1565 cmesh( ii + 1, jj , kk ) + cmesh( ii + 1, jj , kk + 1 ) +
1566 cmesh( ii + 1, jj + 1, kk ) + cmesh( ii + 1, jj + 1, kk + 1 ) ) / 8.0;
1568 else if( !i_is_odd && j_is_odd && k_is_odd )
1570 control_mesh( i, j, k ) = (
1571 cmesh( ii - 1, jj , kk ) + cmesh( ii - 1, jj , kk + 1 ) +
1572 cmesh( ii - 1, jj + 1, kk ) + cmesh( ii - 1, jj + 1, kk + 1 ) +
1573 cmesh( ii + 1, jj , kk ) + cmesh( ii + 1, jj , kk + 1 ) +
1574 cmesh( ii + 1, jj + 1, kk ) + cmesh( ii + 1, jj + 1, kk + 1 ) +
1576 cmesh( ii , jj , kk ) + cmesh( ii , jj , kk + 1 ) +
1577 cmesh( ii , jj + 1, kk ) + cmesh( ii , jj + 1, kk + 1 )
1581 else if( i_is_odd && !j_is_odd && k_is_odd )
1583 control_mesh( i, j, k ) = (
1584 cmesh( ii , jj - 1, kk ) + cmesh( ii , jj - 1, kk + 1 ) +
1585 cmesh( ii + 1, jj - 1, kk ) + cmesh( ii + 1, jj - 1, kk + 1 ) +
1586 cmesh( ii , jj + 1, kk ) + cmesh( ii , jj + 1, kk + 1 ) +
1587 cmesh( ii + 1, jj + 1, kk ) + cmesh( ii + 1, jj + 1, kk + 1 ) +
1589 cmesh( ii , jj , kk ) + cmesh( ii , jj , kk + 1 ) +
1590 cmesh( ii + 1, jj , kk ) + cmesh( ii + 1, jj , kk + 1 )
1594 else if( i_is_odd && j_is_odd && !k_is_odd )
1596 control_mesh( i, j, k ) = (
1597 cmesh( ii , jj , kk - 1 ) + cmesh( ii + 1, jj , kk - 1 ) +
1598 cmesh( ii , jj + 1, kk - 1 ) + cmesh( ii + 1, jj + 1, kk - 1 ) +
1599 cmesh( ii , jj , kk + 1 ) + cmesh( ii + 1, jj , kk + 1 ) +
1600 cmesh( ii , jj + 1, kk + 1 ) + cmesh( ii + 1, jj + 1, kk + 1 ) +
1602 cmesh( ii , jj , kk ) + cmesh( ii + 1, jj , kk ) +
1603 cmesh( ii , jj + 1, kk ) + cmesh( ii + 1, jj + 1, kk )
1607 else if( !i_is_odd && !j_is_odd && k_is_odd )
1609 control_mesh( i, j, k ) = (
1610 cmesh( ii - 1, jj - 1, kk ) + cmesh( ii - 1, jj + 1, kk ) +
1611 cmesh( ii + 1, jj - 1, kk ) + cmesh( ii + 1, jj + 1, kk ) +
1612 cmesh( ii - 1, jj - 1, kk + 1 ) + cmesh( ii - 1, jj + 1, kk + 1 ) +
1613 cmesh( ii + 1, jj - 1, kk + 1 ) + cmesh( ii + 1, jj + 1, kk + 1 ) +
1615 cmesh( ii - 1, jj , kk ) + cmesh( ii , jj - 1, kk ) +
1616 cmesh( ii + 1, jj , kk ) + cmesh( ii , jj + 1, kk ) +
1617 cmesh( ii - 1, jj , kk + 1 ) + cmesh( ii , jj - 1, kk + 1 ) +
1618 cmesh( ii + 1, jj , kk + 1 ) + cmesh( ii , jj + 1, kk + 1 )
1621 cmesh( ii , jj , kk ) + cmesh( ii , jj , kk + 1 )
1625 else if( !i_is_odd && j_is_odd && !k_is_odd )
1627 control_mesh( i, j, k ) = (
1628 cmesh( ii - 1, jj , kk - 1 ) + cmesh( ii - 1, jj , kk + 1 ) +
1629 cmesh( ii + 1, jj , kk - 1 ) + cmesh( ii + 1, jj , kk + 1 ) +
1630 cmesh( ii - 1, jj + 1, kk - 1 ) + cmesh( ii - 1, jj + 1, kk + 1 ) +
1631 cmesh( ii + 1, jj + 1, kk - 1 ) + cmesh( ii + 1, jj + 1, kk + 1 ) +
1633 cmesh( ii - 1, jj , kk ) + cmesh( ii , jj , kk - 1 ) +
1634 cmesh( ii + 1, jj , kk ) + cmesh( ii , jj , kk + 1 ) +
1635 cmesh( ii - 1, jj + 1, kk ) + cmesh( ii , jj + 1, kk - 1 ) +
1636 cmesh( ii + 1, jj + 1, kk ) + cmesh( ii , jj + 1, kk + 1 )
1639 cmesh( ii , jj , kk ) + cmesh( ii , jj + 1, kk )
1643 else if( i_is_odd && !j_is_odd && !k_is_odd )
1645 control_mesh( i, j, k ) = (
1646 cmesh( ii , jj - 1, kk - 1 ) + cmesh( ii , jj + 1, kk - 1 ) +
1647 cmesh( ii , jj - 1, kk + 1 ) + cmesh( ii , jj + 1, kk + 1 ) +
1648 cmesh( ii + 1, jj - 1, kk - 1 ) + cmesh( ii + 1, jj + 1, kk - 1 ) +
1649 cmesh( ii + 1, jj - 1, kk + 1 ) + cmesh( ii + 1, jj + 1, kk + 1 ) +
1651 cmesh( ii , jj , kk - 1 ) + cmesh( ii , jj - 1, kk ) +
1652 cmesh( ii , jj , kk + 1 ) + cmesh( ii , jj + 1, kk ) +
1653 cmesh( ii + 1, jj , kk - 1 ) + cmesh( ii + 1, jj - 1, kk ) +
1654 cmesh( ii + 1, jj , kk + 1 ) + cmesh( ii + 1, jj + 1, kk )
1657 cmesh( ii , jj , kk ) + cmesh( ii + 1, jj , kk )
1663 control_mesh( i, j, k ) = (
1664 cmesh( ii - 1, jj - 1, kk - 1 ) + cmesh( ii - 1, jj + 1, kk - 1 ) +
1665 cmesh( ii + 1, jj - 1, kk - 1 ) + cmesh( ii + 1, jj + 1, kk - 1 ) +
1666 cmesh( ii - 1, jj - 1, kk + 1 ) + cmesh( ii - 1, jj + 1, kk + 1 ) +
1667 cmesh( ii + 1, jj - 1, kk + 1 ) + cmesh( ii + 1, jj + 1, kk + 1 ) +
1669 cmesh( ii - 1, jj - 1, kk ) + cmesh( ii - 1, jj + 1, kk ) +
1670 cmesh( ii + 1, jj - 1, kk ) + cmesh( ii + 1, jj + 1, kk ) +
1671 cmesh( ii - 1, jj , kk - 1 ) + cmesh( ii , jj - 1, kk - 1 ) +
1672 cmesh( ii + 1, jj , kk - 1 ) + cmesh( ii , jj + 1, kk - 1 ) +
1673 cmesh( ii - 1, jj , kk + 1 ) + cmesh( ii , jj - 1, kk + 1 ) +
1674 cmesh( ii + 1, jj , kk + 1 ) + cmesh( ii , jj + 1, kk + 1 )
1677 cmesh( ii , jj , kk - 1 ) + cmesh( ii , jj , kk + 1 ) +
1678 cmesh( ii - 1, jj , kk ) + cmesh( ii , jj - 1, kk ) +
1679 cmesh( ii + 1, jj , kk ) + cmesh( ii , jj + 1, kk )
1681 cmesh( ii , jj , kk ) * 216.0
1689 for( size_type t = 0 ; t < thread_num ; t++ )
1691 f[ t ]->force_initialize( );
1696 for( size_type i = 0 ; i < thread_num ; i++ )
1715 template <
class SOURCETYPE,
class SOURCETYPEA,
class OUTTYPE,
class OUTTYPEA >
1718 __non_rigid_registration_utility__::transformation( out, source, control_mesh );
1731 template <
class SOURCETYPE,
class SOURCETYPEA,
class OUTTYPE,
class OUTTYPEA >
1734 __non_rigid_registration_utility__::transformation( out, source, control_mesh );
1748 template <
class SOURCETYPE,
class SOURCETYPEA,
class OUTTYPE,
class OUTTYPEA >
1751 __non_rigid_registration_utility__::transformation( out, source, control_mesh );
1753 difference_type w = control_mesh.width( );
1754 difference_type h = control_mesh.height( );
1755 difference_type d = control_mesh.depth( );
1756 difference_type i, j;
1757 double ax = out.
reso1( );
1758 double ay = out.
reso2( );
1760 for( j = 0 ; j < h - 1 ; j++ )
1762 for( i = 0 ; i < w - 1 ; i++ )
1768 size_type x0 =
static_cast< size_type
>( vec0.
x / ax );
1769 size_type y0 =
static_cast< size_type
>( vec0.
y / ay );
1770 size_type x1 =
static_cast< size_type
>( vec1.
x / ax );
1771 size_type y1 =
static_cast< size_type
>( vec1.
y / ay );
1772 size_type x2 =
static_cast< size_type
>( vec2.
x / ax );
1773 size_type y2 =
static_cast< size_type
>( vec2.
y / ay );
1774 draw_line( out, x0, y0, x1, y1, value );
1775 draw_line( out, x0, y0, x2, y2, value );
1780 size_type x0 =
static_cast< size_type
>( vec0.
x / ax );
1781 size_type y0 =
static_cast< size_type
>( vec0.
y / ay );
1782 size_type x2 =
static_cast< size_type
>( vec2.
x / ax );
1783 size_type y2 =
static_cast< size_type
>( vec2.
y / ay );
1784 draw_line( out, x0, y0, x2, y2, value );
1786 for( i = 0 ; i < w - 1 ; i++ )
1791 size_type x0 =
static_cast< size_type
>( vec0.
x / ax );
1792 size_type y0 =
static_cast< size_type
>( vec0.
y / ay );
1793 size_type x1 =
static_cast< size_type
>( vec1.
x / ax );
1794 size_type y1 =
static_cast< size_type
>( vec1.
y / ay );
1795 draw_line( out, x0, y0, x1, y1, value );
1810 template <
class SOURCETYPE,
class SOURCETYPEA,
class OUTTYPE,
class OUTTYPEA >
1813 __non_rigid_registration_utility__::transformation( out, source, control_mesh );
1815 difference_type w = control_mesh.width( );
1816 difference_type h = control_mesh.height( );
1817 difference_type d = control_mesh.depth( );
1818 double ax = out.
reso1( );
1819 double ay = out.
reso2( );
1820 double az = out.
reso3( );
1822 for( difference_type k = 0 ; k < d ; k++ )
1824 for( difference_type j = 0 ; j < h ; j++ )
1826 for( difference_type i = 0 ; i < w ; i++ )
1828 const vector_type &vec0 = control_mesh( i, j, k );
1830 size_type x0 =
static_cast< size_type
>( vec0.
x / ax );
1831 size_type y0 =
static_cast< size_type
>( vec0.
y / ay );
1832 size_type z0 =
static_cast< size_type
>( vec0.
z / az );
1836 const vector_type &vec1 = control_mesh( i + 1, j, k );
1837 size_type x1 =
static_cast< size_type
>( vec1.
x / ax );
1838 size_type y1 =
static_cast< size_type
>( vec1.
y / ay );
1839 size_type z1 =
static_cast< size_type
>( vec1.
z / az );
1840 draw_line( out, x0, y0, z0, x1, y1, z1, value );
1845 const vector_type &vec2 = control_mesh( i, j + 1, k );
1846 size_type x2 =
static_cast< size_type
>( vec2.
x / ax );
1847 size_type y2 =
static_cast< size_type
>( vec2.
y / ay );
1848 size_type z2 =
static_cast< size_type
>( vec2.
z / az );
1849 draw_line( out, x0, y0, z0, x2, y2, z2, value );
1854 const vector_type &vec3 = control_mesh( i, j, k + 1 );
1855 size_type x3 =
static_cast< size_type
>( vec3.
x / ax );
1856 size_type y3 =
static_cast< size_type
>( vec3.
y / ay );
1857 size_type z3 =
static_cast< size_type
>( vec3.
z / az );
1858 draw_line( out, x0, y0, z0, x3, y3, z3, value );
1870 template <
class T>
class point
1883 int width =image.
width();
1884 int height = image.
height();
1886 tmp.
resize( width , height );
1888 #pragma omp parallel for schedule( guided )
1889 for(
int h = 0 ; h < height ; h++)
1891 for(
int w = 0 ; w < width ; w++ )
1893 if( w < width / 2 && h < height / 2 )
1895 tmp( w + width / 2, h + height / 2 ) = image( w, h );
1897 else if( w < width / 2 && h >= height / 2 )
1899 tmp( w + width / 2, h - height / 2 ) = image( w, h );
1902 else if( w >= width / 2 && h < height / 2 )
1904 tmp( w - width / 2, h + height / 2 ) = image( w, h );
1906 else if( w >= width / 2 && h >= height / 2 )
1908 tmp( w - width / 2, h - height / 2 ) = image( w, h );
1919 int width =image.
width();
1920 int height = image.
height();
1922 tmp.
resize( width, height );
1923 std::complex< double > zero( 0 , 0 );
1925 int width1 = (int)(width * lowpass_range / 2);
1926 int width2 = (int)(width * (1-lowpass_range / 2));
1927 int height1 = (int)(height * lowpass_range / 2);
1928 int height2 = (int)(height * (1-lowpass_range / 2));
1929 #pragma omp parallel for schedule( guided )
1930 for(
int h = 0 ; h < height ; h++)
1932 for(
int w = 0 ; w < width ; w++ )
1934 if( !( ( w < width1 || w > width2 ) && ( h < height1 || h > height2 ) ) )
1939 tmp( w, h ) = image( w, h );
1947 inline void serch_peak(
const mist::array2< double > &poc_image, point< double > &peak, point< double > &x_peak, point< double > &y_peak )
1950 peak.value = poc_image( 0, 0 );
1951 peak.x = 0; peak.y = 0;
1952 for(
size_t h = 0 ; h < poc_image.
height() ; h++)
1954 for(
size_t w = 0 ; w < poc_image.
width() ; w++ )
1956 if( peak.value < poc_image( w, h ) )
1958 peak.value = poc_image( w, h );
1959 peak.x = w; peak.y = h;
1968 x_peak.value = poc_image( peak.x + 1, peak.y );
1969 x_peak.x = peak.x + 1;
1972 else if( peak.x == poc_image.
width() )
1974 x_peak.value = poc_image( peak.x - 1, peak.y );
1975 x_peak.x = peak.x - 1;
1978 else if( poc_image( peak.x + 1, peak.y ) >= poc_image( peak.x - 1, peak.y ) )
1980 x_peak.value = poc_image( peak.x + 1, peak.y );
1981 x_peak.x = peak.x + 1;
1986 x_peak.value = poc_image( peak.x - 1, peak.y );
1987 x_peak.x = peak.x - 1;
1994 y_peak.value = poc_image( peak.x, peak.y + 1 );
1996 y_peak.y = peak.y + 1;
1998 else if( peak.y == poc_image.
height() )
2000 y_peak.value = poc_image( peak.x, peak.y - 1 );
2002 y_peak.y = peak.y - 1;
2004 else if( poc_image( peak.x, peak.y + 1 ) >= poc_image( peak.x, peak.y - 1 ) )
2006 y_peak.value = poc_image( peak.x, peak.y + 1 );
2008 y_peak.y = peak.y + 1;
2012 y_peak.value = poc_image( peak.x, peak.y - 1 );
2014 y_peak.y = peak.y - 1;
2018 inline void PEF(
const mist::array2< double > &poc_image, point< double > &peak, point< double > &x_peak, point< double > &y_peak,
double &delta_x,
double &delta_y,
const int distance0,
const double lowpass_range )
2020 double ux, uy, vx, vy;
2021 double UUx = 0.0 , UVx = 0.0, UUy = 0.0, UVy = 0.0;
2022 int distance = distance0;
2023 int width = poc_image.
width();
2024 int height = poc_image.
height();
2027 if(distance > peak.x) distance = peak.x;
2028 if(distance > peak.y) distance = peak.y;
2029 if(distance > width - peak.x) distance = width - peak.x;
2030 if(distance > height - peak.y) distance = height - peak.y;
2032 for(
int d = 1; d <= distance; d++ )
2035 ux = poc_image( peak.x - d, peak.y ) + poc_image( peak.x + d, peak.y ) - 2 * cos( M_PI * d * lowpass_range ) * poc_image( peak.x, peak.y );
2036 vx = 2 * cos( M_PI * d * lowpass_range ) * poc_image( peak.x, peak.y ) * ( peak.x - width / 2 )
2037 - ( peak.x - width / 2 - d ) * poc_image( peak.x - d, peak.y )
2038 - ( peak.x - width / 2 + d ) * poc_image( peak.x + d, peak.y );
2043 uy = poc_image( peak.x, peak.y - d ) + poc_image( peak.x, peak.y + d ) - 2 * cos( M_PI * d * lowpass_range ) * poc_image( peak.x, peak.y );
2044 vy = 2 * cos( M_PI * d * lowpass_range ) * poc_image( peak.x, peak.y ) * ( peak.y - height / 2 )
2045 - ( peak.y - height / 2 - d ) * poc_image( peak.x, peak.y - d )
2046 - ( peak.y - height / 2 + d ) * poc_image( peak.x, peak.y + d );
2051 ux = poc_image( x_peak.x - d, x_peak.y ) + poc_image( x_peak.x + d, x_peak.y ) - 2 * cos( M_PI * d * lowpass_range ) * poc_image( x_peak.x, x_peak.y );
2052 vx = 2 * cos( M_PI * d * lowpass_range ) * poc_image( x_peak.x, x_peak.y ) * ( x_peak.x - width / 2 )
2053 - ( x_peak.x - width / 2 - d ) * poc_image( x_peak.x - d, x_peak.y )
2054 - ( x_peak.x - width / 2 + d ) * poc_image( x_peak.x + d, x_peak.y );
2059 uy = poc_image( y_peak.x, y_peak.y - d ) + poc_image( y_peak.x, y_peak.y + d ) - 2 * cos( M_PI * d * lowpass_range ) * poc_image( y_peak.x, y_peak.y );
2060 vy = 2 * cos( M_PI * d * lowpass_range ) * poc_image( y_peak.x, y_peak.y ) * ( y_peak.y - height / 2 )
2061 - ( y_peak.y - height / 2 - d ) * poc_image( y_peak.x, y_peak.y - d )
2062 - ( y_peak.y - height / 2 + d ) * poc_image( y_peak.x, y_peak.y + d );
2070 delta_x = - UVx / UUx;
2071 delta_y = - UVy / UUy;
2086 int width = reference.
width();
2087 int height = reference.
height();
2113 for(
size_t i = 0 ; i < reference.
size() ; i++)
2115 freq_poc[i] = freq_ref[i] * conj( freq_input[i] );
2116 norm = abs( freq_poc[i] );
2119 freq_poc[i] = freq_poc[i] / norm;
2125 freq_poc = lowpass_filter( freq_poc, lowpass_range );
2131 poc_image = shuffle_image( poc_image );
2134 point< double > peak;
2135 point< double > x_peak, y_peak;
2136 serch_peak( poc_image, peak, x_peak, y_peak );
2142 PEF( poc_image, peak, x_peak, y_peak, delta_x, delta_y, distance, lowpass_range );
2153 enum interpolate_type{ LINEAR, BICUBIC };
2166 template <
typename Value_type,
typename Allocator >
2168 const array2< Value_type, Allocator > &input,
2169 const array2< Value_type, Allocator > &reference,
2172 const double low_pass_range = 0.85,
2173 const int distance = 5)
2175 typedef array2< double > image_type;
2176 image_type tmp1, tmp2;
2179 return _poc_::poc( tmp1, tmp2, dx, dy, low_pass_range, distance );
2192 template <
typename Value_type,
typename Allocator >
2194 const array2< Value_type, Allocator > &input,
2195 const array2< Value_type, Allocator > &reference,
2196 vector2< double > &dvec,
2197 const double low_pass_range = 0.85,
2198 const int distance = 5)
2200 typedef array2< double > image_type;
2201 image_type tmp1, tmp2;
2204 return _poc_::poc( tmp1, tmp2, dvec.x, dvec.y, low_pass_range, distance );
2217 template<
class Value_type1,
class Allocator1,
class Value_type2,
class Allocator2 >
2219 const array2< Value_type1, Allocator1 > &in,
2220 array2< Value_type2, Allocator2 > &out,
2223 const double factor = -1,
2224 const int interpolate_type = BICUBIC)
2228 out.resize( (
size_t)( in.width() * factor ), (
size_t )( in.height() * factor ) );
2230 switch( interpolate_type )
2250 template<
class Value_type1,
class Allocator1,
class Value_type2,
class Allocator2 >
2252 const array2< Value_type1, Allocator1 > &in,
2253 array2< Value_type2, Allocator2 > &out,
2254 const vector2< double > &dvec,
2255 const double factor = -1,
2256 const int interpolate_type = BICUBIC)
2260 out.resize( (
size_t)( in.width() * factor ), (
size_t )( in.height() * factor ) );
2262 switch( interpolate_type )
2282 #endif // __INCLUDE_MIST_REGISTRATION__