aimsdata  5.1.2
Neuroimaging data handling
converter_volume.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 
34 /*
35  * Converter between the different A.I.M.S. types
36  */
37 #ifndef AIMS_UTILITY_CONVERTER_VOLUME_H
38 #define AIMS_UTILITY_CONVERTER_VOLUME_H
39 
43 
44 namespace std
45 {
46 
47  template<typename _Tp>
48  struct numeric_limits<carto::Volume<_Tp> > : public numeric_limits<_Tp>
49  {
50  public:
51  };
52 
53 
54  template<typename _Tp>
55  struct numeric_limits<carto::VolumeRef<_Tp> > : public numeric_limits<_Tp>
56  {
57  public:
58  };
59 
60 }
61 
62 namespace carto
63 {
64 
65  template <typename INP,typename OUTP>
67  {
68  public:
69  void convert( const carto::VolumeRef<INP> &in,
70  carto::VolumeRef<OUTP> & out ) const;
71  };
72 
73 
74  template<typename INP, typename OUTP>
76  {
77  public:
78  Rescaler();
79  Rescaler( const RescalerInfo & info );
80 
81  void convert( const carto::VolumeRef<INP> &in,
82  carto::VolumeRef<OUTP> & out ) const;
83 
84  private:
85  RescalerInfo _info;
86  };
87 
88 
89  // special case of same input and output types
90 
91  template <typename INP>
93  {
94  public:
95  RawConverter( bool shallowcopy = false ) : _shallowcopy( shallowcopy ) {}
96  void convert( const carto::VolumeRef<INP> &in, carto::VolumeRef<INP> & out ) const;
97 
98  private:
99  bool _shallowcopy;
100  };
101 
102 
103  template <typename INP>
105  : public Converter<carto::VolumeRef<INP>, carto::VolumeRef<INP> >
106  {
107  public:
108  ShallowConverter( bool rescale = false )
109  : Converter<carto::VolumeRef<INP>, carto::VolumeRef<INP> >( rescale ) {}
110  ShallowConverter( bool rescale, const RescalerInfo & info )
111  : Converter<carto::VolumeRef<INP>, carto::VolumeRef<INP> >( rescale, info ) {}
112  virtual void convert( const carto::VolumeRef<INP> &in, carto::VolumeRef<INP> & out ) const;
113  };
114 
115 
116  template <class INP,class OUTP>
118  {
119  public:
121  };
122 
123 
124  template <class INP>
126  {
127  public:
129  };
130 
131 
132  template<typename INP>
134  : public RawConverter<carto::VolumeRef<INP>, carto::VolumeRef<INP> >
135  {
136  public:
137  ConverterSwitch( bool shallowcopy = false )
138  : RawConverter<carto::VolumeRef<INP>, carto::VolumeRef<INP> >(
139  shallowcopy ) {}
140  ConverterSwitch( const RescalerInfo&, bool shallowcopy = false )
141  : RawConverter<carto::VolumeRef<INP>, carto::VolumeRef<INP> >(
142  shallowcopy ) {}
143  };
144 
145 
146  template<typename INP>
148  : public Rescaler<carto::VolumeRef<INP>, carto::VolumeRef<INP> >
149  {
150  public:
151  ConverterSwitch( bool = false )
152  : Rescaler<carto::VolumeRef<INP>, carto::VolumeRef<INP> >() {}
153  ConverterSwitch( const RescalerInfo& info, bool )
154  : Rescaler<carto::VolumeRef<INP>, carto::VolumeRef<INP> >(info) {}
155  };
156 
157 
158  template<typename INP>
160  : public ConverterSwitch<carto::VolumeRef<INP>, carto::VolumeRef<INP>,
161  std::numeric_limits<INP>::is_specialized
162  && std::numeric_limits<INP>::is_bounded >
163  {
164  public:
165  SmartConverter( bool shallowcopy = false )
167  std::numeric_limits<INP>::is_specialized
168  && std::numeric_limits<INP>::is_bounded >( shallowcopy ) {}
169  SmartConverter( const RescalerInfo& info, bool shallowcopy = false )
171  std::numeric_limits<INP>::is_specialized
172  && std::numeric_limits<INP>::is_bounded >( info, shallowcopy ) {}
173  };
174 
175 
176  // implementation
177 
178  template <class INP,class OUTP>
181  ( const carto::VolumeRef<INP> &in )
182  {
183  return new VolumeRef<OUTP>( in.getSizeX(), in.getSizeY(), in.getSizeZ(),
184  in.getSizeT() );
185  }
186 
187 
188  template <class INP> inline
191  ( const carto::VolumeRef<INP> & )
192  {
193  return new carto::VolumeRef<INP>( 0 );
194  }
195 
196 
197  // inline is a bit abusive here...
198  template <typename INP, typename OUTP>
200  ( const carto::VolumeRef<INP> &in, carto::VolumeRef<OUTP> & out ) const
201  {
202  out.setVoxelSize( in.getVoxelSize() );
203  out.copyHeaderFrom( in.header() );
204 
205  std::vector<int> isz = in.getSize();
206  std::vector<int> osz = out.getSize();
207  bool erased = false;
208 
209  int i, n = isz.size(), m = osz.size();
210  for( i=0; i<std::min(n, m); ++i )
211  if( isz[i] < osz[i] && !erased )
212  {
213  out.fill( OUTP( 0 ) );
214  erased = true;
215  }
216  else if( isz[i] > osz[i] )
217  throw std::runtime_error(
218  "Converter output volume should be as large as input" );
219  if( !erased )
220  for( ; i<n; ++i ) // input is larger in more dimensions
221  if( isz[i] > 1 )
222  {
223  out.fill( OUTP( 0 ) );
224  break;
225  }
226  for( ; i<m; ++i )
227  if( osz[i] > 1 ) // output is larger in more dimensions
228  throw std::runtime_error(
229  "Converter output volume should be as large as input" );
230 
231  RawConverter<INP,OUTP> itemconv;
232 
233  carto::const_line_NDIterator<INP> it( &in.at( 0 ), in.getSize(),
234  in.getStrides() );
235  carto::line_NDIterator<OUTP> oit( &out.at( 0 ), out.getSize(),
236  out.getStrides() );
237  const INP *p, *pp;
238  OUTP *op;
239 
240  for( ; !it.ended(); ++it, ++oit )
241  {
242  p = &*it;
243  op = &out->at( it.position() );
244  for( pp=p + it.line_length(); p!=pp;
245  it.inc_line_ptr( p ), oit.inc_line_ptr( op ) )
246  itemconv.convert( *p, *op );
247  }
248 
249  out.header().setProperty( "data_type", DataTypeCode<OUTP>::dataType() );
250  if( out.header().hasProperty( "disk_data_type" ) )
251  out.header().removeProperty( "disk_data_type" );
252  }
253 
254 
255  template<typename INP, typename OUTP>
257  : _info()
258  {
259  }
260 
261 
262  template<typename INP, typename OUTP>
264  ( const RescalerInfo & info )
265  : _info( info )
266  {
267  }
268 
269 
270  // inline is a bit abusive here...
271  template<typename INP, typename OUTP>
273  ( const carto::VolumeRef<INP> &in, carto::VolumeRef<OUTP> &out ) const
274  {
275  // Accommodate the case where out is allocated with zero size by
276  // AllocatorConverter. This happens when the INP and OUTP types are equal.
277  if( out.getSizeX() == 0 )
278  out.reset( new Volume<OUTP>( in.getSize(), in.getBorders(),
279  out.allocatorContext() ) );
280 
281  out.setVoxelSize( in.getVoxelSize() );
282  out.copyHeaderFrom( in.header() );
283 
284  RescalerInfo info( _info );
285  if( std::isnan( info.vmin ) )
286  {
287  if ( ! info.usevtypelimits )
288  {
289  info.vmin = (double) in.min();
290  }
291  }
292 
293  if( std::isnan( info.vmax ) )
294  {
295  if ( ! info.usevtypelimits )
296  {
297  info.vmax = (double) in.max();
298  }
299  }
300 
301  std::vector<int> isz = in.getSize();
302  std::vector<int> osz = out.getSize();
303  bool erased = false;
304 
305  int i, n = isz.size(), m = osz.size();
306  for( i=0; i<std::min(n, m); ++i )
307  if( isz[i] < osz[i] && !erased )
308  {
309  out.fill( OUTP( 0 ) );
310  erased = true;
311  }
312  else if( isz[i] > osz[i] )
313  throw std::runtime_error(
314  "Converter output volume should be as large as input" );
315  if( !erased )
316  for( ; i<n; ++i ) // input is larger in more dimensions
317  if( isz[i] > 1 )
318  {
319  out.fill( OUTP( 0 ) );
320  break;
321  }
322  for( ; i<m; ++i )
323  if( osz[i] > 1 ) // output is larger in more dimensions
324  throw std::runtime_error(
325  "Converter output volume should be as large as input" );
326 
327  DefaultedRescalerInfo<INP, OUTP> defaultedinfo( info );
328 
329  carto::const_line_NDIterator<INP> it( &in.at( 0 ), in.getSize(),
330  in.getStrides() );
331  carto::line_NDIterator<OUTP> oit( &out.at( 0 ), out.getSize(),
332  out.getStrides() );
333  const INP *p, *pp;
334  OUTP *op;
335 
336  for( ; !it.ended(); ++it, ++oit )
337  {
338  p = &*it;
339  op = &out->at( it.position() );
340  for( pp=p + it.line_length(); p!=pp;
341  it.inc_line_ptr( p ), oit.inc_line_ptr( op ) )
342  *op = defaultedinfo.getScaledValue( *p );
343  }
344 
345  float scf = 1.;
346  out.header().getProperty( "scale_factor", scf );
347  scf *= defaultedinfo.getScale();
348  out.header().setProperty( "scale_factor", scf );
349  out.header().setProperty( "data_type", DataTypeCode<OUTP>::dataType() );
350  if( out.header().hasProperty( "disk_data_type" ) )
351  out.header().removeProperty( "disk_data_type" );
352  }
353 
354  template<class INP> inline
356  ( const carto::VolumeRef<INP> &in, carto::VolumeRef<INP> &out ) const
357  {
358  if( out.getSizeX() == 0
359  || ( in.getSize() == out.getSize()
360  && in.getBorders() == out.getBorders() ) )
361  {
362  if( this->_shallowcopy )
363  out = in;
364  else
365  {
366  // using deep-copy to be consistent with other cases
367  out = in.deepcopy();
368  // keep the same UUID
369  out->copyUuid( *in );
370  }
371  }
372  else
373  {
374  out.copyHeaderFrom( in.header() );
375  out.setVoxelSize( in.getVoxelSize() );
376 
377  std::vector<int> isz = in.getSize();
378  std::vector<int> osz = out.getSize();
379  bool erased = false;
380 
381  int i, n = isz.size(), m = osz.size();
382  for( i=0; i<std::min(n, m); ++i )
383  if( isz[i] < osz[i] && !erased )
384  {
385  out.fill( INP( 0 ) );
386  erased = true;
387  }
388  else if( isz[i] > osz[i] )
389  throw std::runtime_error(
390  "Converter output volume should be as large as input" );
391  if( !erased )
392  for( ; i<n; ++i ) // input is larger in more dimensions
393  if( isz[i] > 1 )
394  {
395  out.fill( INP( 0 ) );
396  break;
397  }
398  for( ; i<m; ++i )
399  if( osz[i] > 1 ) // output is larger in more dimensions
400  throw std::runtime_error(
401  "Converter output volume should be as large as input" );
402 
403  carto::const_line_NDIterator<INP> it( &in.at( 0 ), in.getSize(),
404  in.getStrides() );
405  carto::line_NDIterator<INP> oit( &out.at( 0 ), out.getSize(),
406  out.getStrides() );
407  const INP *p, *pp;
408  INP *op;
409 
410  for( ; !it.ended(); ++it, ++oit )
411  {
412  p = &*it;
413  op = &out->at( it.position() );
414  for( pp=p + it.line_length(); p!=pp;
415  it.inc_line_ptr( p ), oit.inc_line_ptr( op ) )
416  *op = *p;
417  }
418  }
419  }
420 
421  template<class INP>
422  inline void
424  ( const carto::VolumeRef<INP> &in, carto::VolumeRef<INP> & out ) const
425  {
426  if( this->_rescale )
427  {
429  sc( this->_info, true );
430  sc.convert( in, out );
431  }
432  else
433  {
435  rc.convert( in, out );
436  }
437  }
438 
439 }
440 
441 
442 // RGB conversion
443 #include <aims/rgb/rgb.h>
444 
445 namespace carto
446 {
447 
448  template <typename T, int D>
450  {
451  public:
452  Rescaler();
453  Rescaler( const RescalerInfo & info );
454 
455  void convert( const VolumeRef<AimsVector<T,D> > &in, VolumeRef<AimsRGB> & out ) const;
456 
457  private:
458  RescalerInfo _info;
459  };
460 
461  template <typename T, int D>
462  inline
464  _info()
465  {}
466 
467  template <typename T, int D>
468  inline
470  const RescalerInfo & info ):
471  _info(info)
472  {}
473 
474  template <typename T, int D>
475  void
477  const VolumeRef<AimsVector<T,D> > &in, VolumeRef<AimsRGB> &out ) const
478  {
479  if( out.getSizeX() == 0 )
480  out.reset( new Volume<AimsRGB>( in.getSize(), in.getBorders(),
481  out.allocatorContext() ) );
482 
483  out.setVoxelSize( in.getVoxelSize() );
484  out.copyHeaderFrom( in.header() );
485 
486  std::vector<int> isz = in.getSize();
487  std::vector<int> osz = out.getSize();
488  bool erased = false;
489 
490  int i, n = isz.size(), m = osz.size();
491  for( i=0; i<std::min(n, m); ++i )
492  if( isz[i] < osz[i] && !erased )
493  {
494  out.fill( AimsRGB( 0 ) );
495  erased = true;
496  }
497  else if( isz[i] > osz[i] )
498  throw std::runtime_error(
499  "Converter output volume should be as large as input" );
500  if( !erased )
501  for( ; i<n; ++i ) // input is larger in more dimensions
502  if( isz[i] > 1 )
503  {
504  out.fill( AimsRGB( 0 ) );
505  break;
506  }
507  for( ; i<m; ++i )
508  if( osz[i] > 1 ) // output is larger in more dimensions
509  throw std::runtime_error(
510  "Converter output volume should be as large as input" );
511 
513  it( &in.at( 0 ), in.getSize(), in.getStrides() );
514  const AimsVector<T,D> *p, *pp;
515 
516  RescalerInfo info( _info );
517  if( std::isnan( info.vmin ) )
518  {
519  if ( ! info.usevtypelimits )
520  {
522  for( ; !it.ended(); ++it )
523  {
524  p = &*it;
525  for( pp=p + it.line_length(); p!=pp; it.inc_line_ptr( p ) )
526  {
527  for( int c = 0; c < D; ++c )
528  if( (double) (*p)[c] < info.vmin )
529  info.vmin = (double) (*p)[c];
530  }
531  }
532  }
533  }
534 
535  if( std::isnan( info.vmax ) )
536  {
537  if ( ! info.usevtypelimits )
538  {
540  for( it.reset(); !it.ended(); ++it )
541  {
542  p = &*it;
543  for( pp=p + it.line_length(); p!=pp; it.inc_line_ptr( p ) )
544  {
545  for( int c = 0; c < D; ++c )
546  if( (double) (*p)[c] > info.vmin )
547  info.vmax = (double) (*p)[c];
548  }
549  }
550  }
551  }
552 
553  DefaultedRescalerInfo<T, uint8_t> defaultedinfo( info );
554 
555  carto::line_NDIterator<AimsRGB> oit( &out.at( 0 ), out.getSize(),
556  out.getStrides() );
557  AimsRGB *op;
558 
559  for( it.reset(); !it.ended(); ++it, ++oit )
560  {
561  p = &*it;
562  op = &out->at( it.position() );
563  for( pp=p + it.line_length(); p!=pp;
564  it.inc_line_ptr( p ), oit.inc_line_ptr( op ) )
565  for( int c=0; c < D && c<3; ++c )
566  (*op)[c] = defaultedinfo.getScaledValue( (*p)[c] );
567  }
568 
569  float scf = 1.;
570  out.header().getProperty( "scale_factor", scf );
571  scf *= defaultedinfo.getScale();
572  out.header().setProperty( "scale_factor", scf );
573  out.header().setProperty( "data_type", DataTypeCode<AimsRGB>::name() );
574  if( out.header().hasProperty( "disk_data_type" ) )
575  out.header().removeProperty( "disk_data_type" );
576  }
577 
578  template <typename T, int D>
580  {
581  public:
582  Rescaler();
583  Rescaler( const RescalerInfo & info );
584 
585  void convert( const VolumeRef<AimsRGB> &in, VolumeRef<AimsVector<T,D> > & out ) const;
586 
587  private:
588  RescalerInfo _info;
589  };
590 
591  template <typename T, int D>
592  inline
594  _info()
595  {}
596 
597  template <typename T, int D>
598  inline
600  const RescalerInfo & info ):
601  _info(info)
602  {}
603 
604  template <typename T, int D>
605  void
607  const VolumeRef<AimsRGB> &in, VolumeRef<AimsVector<T,D> > &out ) const
608  {
609  if( out.getSizeX() == 0 )
610  out.reset( new Volume<AimsVector<T,D> >(
611  in.getSize(), in.getBorders(), out.allocatorContext() ) );
612 
613  out.setVoxelSize( in.getVoxelSize() );
614  out.copyHeaderFrom( in.header() );
615 
616  std::vector<int> isz = in.getSize();
617  std::vector<int> osz = out.getSize();
618  bool erased = false;
619 
620  int i, n = isz.size(), m = osz.size();
621  for( i=0; i<std::min(n, m); ++i )
622  if( isz[i] < osz[i] && !erased )
623  {
624  out.fill( AimsVector<T,D>( 0 ) );
625  erased = true;
626  }
627  else if( isz[i] > osz[i] )
628  throw std::runtime_error(
629  "Converter output volume should be as large as input" );
630  if( !erased )
631  for( ; i<n; ++i ) // input is larger in more dimensions
632  if( isz[i] > 1 )
633  {
634  out.fill( AimsVector<T,D>( 0 ) );
635  break;
636  }
637  for( ; i<m; ++i )
638  if( osz[i] > 1 ) // output is larger in more dimensions
639  throw std::runtime_error(
640  "Converter output volume should be as large as input" );
641 
643  it( &in.at( 0 ), in.getSize(), in.getStrides() );
644  const AimsRGB *p, *pp;
645 
646  RescalerInfo info( _info );
647  if( std::isnan( info.vmin ) )
648  {
649  if ( ! info.usevtypelimits )
650  {
652  for( ; !it.ended(); ++it )
653  {
654  p = &*it;
655  for( pp=p + it.line_length(); p!=pp; it.inc_line_ptr( p ) )
656  {
657  for( int c = 0; c < 3; ++c )
658  if( (double) (*p)[c] < info.vmin )
659  info.vmin = (double) (*p)[c];
660  }
661  }
662  }
663  }
664 
665  if( std::isnan( info.vmax ) )
666  {
667  if ( ! info.usevtypelimits )
668  {
670  for( it.reset(); !it.ended(); ++it )
671  {
672  p = &*it;
673  for( pp=p + it.line_length(); p!=pp; it.inc_line_ptr( p ) )
674  {
675  for( int c = 0; c < 3; ++c )
676  if( (double) (*p)[c] > info.vmin )
677  info.vmax = (double) (*p)[c];
678  }
679  }
680  }
681  }
682 
683  DefaultedRescalerInfo<uint8_t, T> defaultedinfo( info );
684 
685  carto::line_NDIterator<AimsVector<T,D> > oit( &out.at( 0 ), out.getSize(),
686  out.getStrides() );
687  AimsVector<T,D> *op;
688 
689  for( it.reset(); !it.ended(); ++it, ++oit )
690  {
691  p = &*it;
692  op = &out->at( it.position() );
693  for( pp=p + it.line_length(); p!=pp;
694  it.inc_line_ptr( p ), oit.inc_line_ptr( op ) )
695  for( int c=0; c < D && c<3; ++c )
696  (*op)[c] = defaultedinfo.getScaledValue( (*p)[c] );
697  }
698 
699  float scf = 1.;
700  out.header().getProperty( "scale_factor", scf );
701  scf *= defaultedinfo.getScale();
702  out.header().setProperty( "scale_factor", scf );
703  out.header().setProperty( "data_type",
704  DataTypeCode<AimsVector<T, D> >::name() );
705  if( out.header().hasProperty( "disk_data_type" ) )
706  out.header().removeProperty( "disk_data_type" );
707  }
708 
709 }
710 
711 
712 // // maintain header compatibility for now (temporary)
713 // #include <aims/utility/converter_aimsdata.h>
714 
715 #endif
static OUTP * alloc(const INP &in)
virtual void convert(const INP &in, OUTP &out) const
OUTP getScaledValue(INP value) const
const std::vector< int > & position() const
void setProperty(const std::string &, const T &)
virtual bool removeProperty(const std::string &key)
virtual bool hasProperty(const std::string &) const
bool getProperty(const std::string &, T &) const
void convert(const INP &in, OUTP &out) const
void convert(const INP &in, OUTP &out) const
SmartConverter(const RescalerInfo &info, bool shallowcopy=false)
int getSizeZ() const
std::vector< int > getBorders() const
void setVoxelSize(float vx, float vy=1., float vz=1., float vt=1.)
std::vector< float > getVoxelSize() const
VolumeRef< T > deepcopy() const
virtual void copyHeaderFrom(const PropertySet &other)
int getSizeT() const
std::vector< int > getSize() const
const T & at(long x, long y=0, long z=0, long t=0) const
int getSizeY() const
const PropertySet & header() const
void fill(const T &value)
int getSizeX() const
std::vector< size_t > getStrides() const
const AllocatorContext & allocatorContext() const
void inc_line_ptr(const T *&p) const
void inc_line_ptr(T *&p) const
void reset(T *p=NULL)
carto::VoxelRGB AimsRGB
Definition: rgb.h:43
static _Tp min()
static _Tp max()