aimsdata 6.0.0
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
40#include <cartodata/volume/volume.h>
41#include <cartobase/type/converter.h>
42#include <cartobase/containers/nditerator.h>
43
44namespace 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
62namespace 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>
186
187
188 template <class INP> inline
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
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>
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
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
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
445namespace 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
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
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 carto::VolumeRef< INP > * alloc(const carto::VolumeRef< INP > &in)
static carto::VolumeRef< OUTP > * alloc(const carto::VolumeRef< INP > &in)
static OUTP * alloc(const INP &in)
virtual void convert(const INP &in, OUTP &out) const
Converter(bool rescale=false)
std::string name()
std::string dataType()
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 carto::VolumeRef< INP > &in, carto::VolumeRef< INP > &out) const
void convert(const carto::VolumeRef< INP > &in, carto::VolumeRef< OUTP > &out) const
void convert(const INP &in, OUTP &out) const
void convert(const VolumeRef< AimsRGB > &in, VolumeRef< AimsVector< T, D > > &out) const
void convert(const VolumeRef< AimsVector< T, D > > &in, VolumeRef< AimsRGB > &out) const
void convert(const carto::VolumeRef< INP > &in, carto::VolumeRef< OUTP > &out) const
void convert(const INP &in, OUTP &out) const
virtual void convert(const carto::VolumeRef< INP > &in, carto::VolumeRef< INP > &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
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
std::vector< long > getStrides() const
const PropertySet & header() const
void fill(const T &value)
int getSizeX() const
const AllocatorContext & allocatorContext() const
VolumeRef< T > deepcopy() const
std::ptrdiff_t line_length() const
void inc_line_ptr(const T *&p) const
void inc_line_ptr(T *&p) const
void reset(T *p=NULL)
STL namespace.
carto::VoxelRGB AimsRGB
Definition rgb.h:43
static _Tp min()
static _Tp max()