00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #ifndef __cmtkUniformVolume_h_included_
00034 #define __cmtkUniformVolume_h_included_
00035
00036 #include <cmtkconfig.h>
00037
00038 #include <Base/cmtkVolume.h>
00039
00040 #include <System/cmtkSmartPtr.h>
00041 #include <System/cmtkSmartConstPtr.h>
00042
00043 #include <algorithm>
00044
00045 namespace
00046 cmtk
00047 {
00048
00051
00053 class VolumeGridToGridLookup;
00054
00058 class UniformVolume :
00060 public Volume
00061 {
00062 public:
00064 typedef UniformVolume Self;
00065
00067 typedef Volume Superclass;
00068
00070 typedef SmartPointer<Self> SmartPtr;
00071
00073 typedef SmartConstPointer<Self> SmartConstPtr;
00074
00076 typedef Superclass:: CoordinateRegionType CoordinateRegionType;
00077
00079 typedef Superclass::CoordinateVectorType CoordinateVectorType;
00080
00082 CoordinateVectorType m_Delta;
00083
00085 const CoordinateVectorType& Deltas() const
00086 {
00087 return this->m_Delta;
00088 }
00089
00091 CoordinateVectorType& Deltas()
00092 {
00093 return this->m_Delta;
00094 }
00095
00097 virtual ~UniformVolume() {}
00098
00106 UniformVolume( const UniformVolume& other, const Types::Coordinate resolution = 0, const bool allowUpsampling = false );
00107
00113 UniformVolume( const DataGrid::IndexType& dims, const Self::CoordinateVectorType& size, TypedArray::SmartPtr& data = TypedArray::SmartPtr::Null );
00114
00122 UniformVolume( const DataGrid::IndexType& dims, const Types::Coordinate deltaX, const Types::Coordinate deltaY, const Types::Coordinate deltaZ, TypedArray::SmartPtr& data = TypedArray::SmartPtr::Null );
00123
00125 bool GridMatches( const Self& other ) const
00126 {
00127 return Superclass::GridMatches( other ) && ((this->m_Delta-other.m_Delta).MaxAbsValue() < 1e-5) && ((this->m_Offset-other.m_Offset).MaxAbsValue() < 1e-5);
00128 }
00129
00137 AffineXform::MatrixType m_IndexToPhysicalMatrix;
00138
00143 virtual void ChangeCoordinateSpace( const std::string& newSpace );
00144
00147 std::string GetOrientationFromDirections() const;
00148
00152 virtual void CreateDefaultIndexToPhysicalMatrix();
00153
00158 virtual AffineXform::MatrixType GetImageToPhysicalMatrix() const;
00159
00163 Self::SmartPtr Clone( const bool copyData )
00164 {
00165 return Self::SmartPtr( this->CloneVirtual( copyData ) );
00166 }
00167
00168 Self::SmartPtr Clone() const
00169 {
00170 return Self::SmartPtr( this->CloneVirtual() );
00171 }
00172
00174 Self::SmartPtr CloneGrid() const
00175 {
00176 return Self::SmartPtr( this->CloneGridVirtual() );
00177 }
00178
00180 virtual Types::Coordinate GetDelta( const int axis ) const
00181 {
00182 return this->m_Delta[axis];
00183 }
00184
00189 virtual Types::Coordinate GetMinDelta () const
00190 {
00191 return this->m_Delta.MinValue();
00192 }
00193
00198 virtual Types::Coordinate GetMaxDelta () const
00199 {
00200 return this->m_Delta.MaxValue();
00201 }
00202
00210 virtual TypedArray::SmartPtr Resample ( const UniformVolume& ) const;
00211
00213 const UniformVolume::SmartPtr GetReoriented ( const char* newOrientation = AnatomicalOrientation::ORIENTATION_STANDARD ) const;
00214
00221 virtual UniformVolume* GetDownsampledAndAveraged( const int downsample, const bool approxIsotropic = false ) const;
00222
00226 virtual UniformVolume* GetDownsampledAndAveraged( const int (&downsample)[3] ) const;
00227
00233 UniformVolume* GetInterleavedSubVolume( const int axis, const int factor, const int idx ) const;
00234
00240 UniformVolume* GetInterleavedPaddedSubVolume( const int axis, const int factor, const int idx ) const;
00241
00243 virtual void Mirror ( const int axis = AXIS_X );
00244
00251 virtual ScalarImage* GetOrthoSlice( const int axis, const unsigned int plane ) const;
00252
00255 Self::SmartPtr ExtractSlice( const int axis, const int plane ) const
00256 {
00257 return Self::SmartPtr( this->ExtractSliceVirtual( axis, plane ) );
00258 }
00259
00266 virtual ScalarImage* GetOrthoSliceInterp( const int axis, const Types::Coordinate location ) const;
00267
00274 virtual ScalarImage* GetNearestOrthoSlice( const int axis, const Types::Coordinate location ) const;
00275
00282 virtual const Self::CoordinateVectorType GetGradientAt( const int i, const int j, const int k );
00283
00290 virtual void GetHessianAt( Matrix3x3<Types::DataItem>& H, const int i, const int j, const int k );
00291
00293 template<class TData> inline bool ProbeData( TData& result, const TData* dataPtr, const Self::CoordinateVectorType& location ) const;
00294
00296 inline bool ProbeNoXform ( ProbeInfo&, const Self::CoordinateVectorType& ) const;
00297
00310 inline bool FindVoxel( const Self::CoordinateVectorType& location, int *const idx, Types::Coordinate *const from, Types::Coordinate *const to ) const;
00311
00322 inline bool FindVoxel( const Self::CoordinateVectorType& location, int *const idx ) const;
00323
00331 inline void GetVoxelIndexNoBounds( const Self::CoordinateVectorType& location, int *const idx ) const;
00332
00341 inline bool FindVoxelByIndex( const Self::CoordinateVectorType& fracIndex, int *const idx, Types::Coordinate *const frac ) const;
00342
00344 const UniformVolume::RegionType GetGridRange( const Self::CoordinateVectorType& fromVOI, const Self::CoordinateVectorType& toVOI ) const;
00345
00347 virtual Types::Coordinate GetPlaneCoord( const int axis, const int plane ) const
00348 {
00349 return this->m_Offset[axis] + plane * this->m_Delta[axis];
00350 }
00351
00356 virtual int GetCoordIndex( const int axis, const Types::Coordinate location ) const
00357 {
00358 return std::max<int>( 0, std::min<int>( (int) ((location-this->m_Offset[axis]) / this->m_Delta[axis]), this->m_Dims[axis]-1 ) );
00359 }
00360
00365 virtual int GetClosestCoordIndex( const int axis, const Types::Coordinate location ) const
00366 {
00367 const int idx = (int)MathUtil::Round((location-this->m_Offset[axis]) / this->m_Delta[axis]);
00368 return std::max<int>( 0, std::min<int>( idx, this->m_Dims[axis]-1 ) );
00369 }
00370
00374 virtual bool GetClosestGridPointIndex( const Self::CoordinateVectorType v, int *const xyz ) const
00375 {
00376 for ( int dim = 0; dim < 3; ++dim )
00377 {
00378 xyz[dim] = (int) MathUtil::Round((v[dim]-this->m_Offset[dim]) / this->m_Delta[dim]);
00379 if ( (xyz[dim] < 0) || ( xyz[dim] > this->m_Dims[dim]-1) )
00380 return false;
00381 }
00382 return true;
00383 }
00384
00389 virtual int GetTruncCoordIndex( const int axis, const Types::Coordinate location ) const
00390 {
00391 const int idx = static_cast<int>((location-this->m_Offset[axis]) / this->m_Delta[axis]);
00392 return std::max<int>( 0, std::min<int>( idx, this->m_Dims[axis]-1 ) );
00393 }
00394
00398 virtual bool GetTruncGridPointIndex( const Self::CoordinateVectorType v ,
00399 int *const xyz ) const
00400 {
00401 for ( int dim = 0; dim < 3; ++dim )
00402 {
00403 xyz[dim] = static_cast<int>((v[dim]-this->m_Offset[dim]) / this->m_Delta[dim]);
00404 if ( (xyz[dim] < 0) || ( xyz[dim] > this->m_Dims[dim]-1) )
00405 return false;
00406 }
00407 return true;
00408 }
00409
00415 virtual const Self::CoordinateVectorType GetGridLocation( const int x, const int y, const int z ) const
00416 {
00417 const Types::Coordinate loc[3] = { this->m_Offset[0] + x * this->m_Delta[0], this->m_Offset[1] + y * this->m_Delta[1], this->m_Offset[2] + z * this->m_Delta[2] };
00418 return Self::CoordinateVectorType( loc );
00419 }
00420
00426 virtual const Self::CoordinateVectorType IndexToPhysical( const Self::CoordinateVectorType& idxV ) const
00427 {
00428 const Self::CoordinateVectorType v( idxV );
00429 return v * this->m_IndexToPhysicalMatrix;
00430 }
00431
00439 virtual const Self::CoordinateVectorType GetGridLocation( const size_t idx ) const
00440 {
00441 const Types::Coordinate loc[3] = { this->m_Offset[0] + (idx % this->nextJ) * this->m_Delta[0],
00442 this->m_Offset[1] + (idx % this->nextK) / this->nextJ * this->m_Delta[1],
00443 this->m_Offset[2] + (idx / this->nextK) * this->m_Delta[2] };
00444 return Self::CoordinateVectorType( loc );
00445 }
00446
00448
00451 void SetHighResCropRegion( const Self::CoordinateRegionType& crop );
00452
00455 const Self::CoordinateRegionType GetHighResCropRegion() const;
00456
00458 virtual void SetCropRegion( const Self::RegionType& region )
00459 {
00460 this->m_HighResCropRegion = Self::CoordinateRegionType::SmartPtr( NULL );
00461 Superclass::SetCropRegion( region );
00462 }
00463
00467 Self::CoordinateVectorType GetCenterCropRegion() const
00468 {
00469 const Self::CoordinateRegionType region = this->GetHighResCropRegion();
00470 return 0.5 * ( region.From() + region.To() );
00471 }
00472
00475 Self::SmartPtr GetCroppedVolume() const;
00476
00483 template<class TAccumulator>
00484 ScalarImage* ComputeProjection( const int axis ) const;
00485
00487 virtual Self::CoordinateVectorType GetCenterOfMass() const
00488 {
00489 Self::CoordinateVectorType com = this->Superclass::GetCenterOfMassGrid();
00490 for ( int dim = 0; dim < 3; ++dim )
00491 (com[dim] *= this->m_Delta[dim]) += this->m_Offset[dim];
00492 return com;
00493 }
00494
00496 virtual Self::CoordinateVectorType GetCenterOfMass( Self::CoordinateVectorType& firstOrderMoment ) const
00497 {
00498 Self::CoordinateVectorType com = this->Superclass::GetCenterOfMassGrid( firstOrderMoment );
00499 for ( int dim = 0; dim < 3; ++dim )
00500 {
00501 (com[dim] *= this->m_Delta[dim]) += this->m_Offset[dim];
00502 firstOrderMoment[dim] *= this->m_Delta[dim];
00503 }
00504 return com;
00505 }
00506
00515 void GetPrincipalAxes( Matrix3x3<Types::Coordinate>& directions, Self::CoordinateVectorType& centerOfMass ) const;
00516
00517 protected:
00521 virtual Self* CloneVirtual( const bool copyData );
00522 virtual Self* CloneVirtual() const;
00523
00525 virtual Self* CloneGridVirtual() const;
00526
00527 private:
00534 Self::CoordinateRegionType::SmartPtr m_HighResCropRegion;
00535
00540 friend class WarpXform;
00541
00543 friend class VolumeAxesHash;
00544
00546 friend class VolumeGridToGridLookup;
00547
00548 class ResampleThreadInfo;
00549
00551 friend class ResampleThreadInfo;
00552
00558 class ResampleTaskInfo :
00559 public ThreadParameters<const Self>
00560 {
00561 public:
00563 Types::DataItem *ResampledData;
00565 const VolumeGridToGridLookup *GridLookup;
00567 const Self* OtherVolume;
00569 const TypedArray* FromData;
00570 };
00571
00573 static void ResampleThreadPoolExecuteGrey( void *const arg, const size_t taskIdx, const size_t taskCnt, const size_t threadIdx, const size_t threadCnt );
00574
00576 static void ResampleThreadPoolExecuteLabels( void *const arg, const size_t taskIdx, const size_t taskCnt, const size_t threadIdx, const size_t threadCnt );
00577
00580 virtual Self* ExtractSliceVirtual( const int axis, const int plane ) const;
00581 };
00582
00584
00585 }
00586
00587 #include "cmtkUniformVolume.txx"
00588
00589 #endif // #ifndef __cmtkUniformVolume_h_included_