cmtkDataGrid.cxx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2009 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2010 SRI International
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2471 $
00026 //
00027 //  $LastChangedDate: 2010-10-20 12:46:04 -0700 (Wed, 20 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkDataGrid.h"
00034 
00035 #include <stdlib.h>
00036 
00037 #include <System/cmtkConsole.h>
00038 #include <System/cmtkProgress.h>
00039 
00040 namespace
00041 cmtk
00042 {
00043 
00046 
00047 const DataGrid::RegionType
00048 DataGrid::GetWholeImageRegion() const
00049 {
00050   const int zeroes[3] = {0,0,0};
00051   return Self::RegionType( Self::IndexType( zeroes ), Self::IndexType( this->m_Dims ) );
00052 }
00053 
00054 TypedArray::SmartPtr
00055 DataGrid::CreateDataArray( const ScalarDataType dataType, const bool setToZero )
00056 {
00057   TypedArray::SmartPtr data( TypedArray::Create( dataType, this->GetNumberOfPixels() ) );
00058   if ( setToZero )
00059     data->ClearArray();
00060   this->SetData( data );
00061   return data;
00062 }
00063 
00064 DataGrid* 
00065 DataGrid::GetDownsampledAndAveraged( const int (&downsample)[3] ) const
00066 {
00067   const int newDims[3] = { (this->m_Dims[0]-1) / downsample[0] + 1, (this->m_Dims[1]-1) / downsample[1] + 1, (this->m_Dims[2]-1) / downsample[2] + 1 };
00068 
00069   DataGrid* newDataGrid = new DataGrid;
00070   newDataGrid->SetDims( Self::IndexType( newDims ) );
00071   
00072   const TypedArray* thisData = this->GetData();
00073   if ( thisData )
00074     {
00075     TypedArray::SmartPtr newData = TypedArray::Create( thisData->GetType(), newDataGrid->GetNumberOfPixels() );
00076 
00077 #pragma omp parallel for
00078     for ( int z = 0; z < newDims[2]; ++z )
00079       {
00080       size_t toOffset = z * newDims[0] * newDims[1];
00081       int oldZ = z * downsample[2];
00082       int oldY = 0;
00083       for ( int y = 0; y < newDims[1]; ++y, oldY += downsample[1] ) 
00084         {
00085         int oldX = 0;
00086         for ( int x = 0; x < newDims[0]; ++x, oldX += downsample[0], ++toOffset ) 
00087           {
00088           Types::DataItem sum = 0;
00089           int count = 0;
00090           for ( int zz = 0; (zz < downsample[2]) && (oldZ+zz<this->m_Dims[2]); ++zz )
00091             {
00092             const size_t ofsZ = (oldZ+zz)*this->nextK;
00093             for ( int yy = 0; (yy < downsample[1]) && (oldY+yy<this->m_Dims[1]); ++yy )
00094               {
00095               const size_t ofsYZ = ofsZ + (oldY+yy)*this->nextJ;
00096               for ( int xx = 0; (xx < downsample[0]) && (oldX+xx<this->m_Dims[0]); ++xx )
00097                 {
00098                 Types::DataItem value;
00099                 if ( thisData->Get( value, (oldX+xx) + ofsYZ  ) )
00100                   {
00101                   sum += value;
00102                   ++count;
00103                   }
00104                 }
00105               }
00106             }
00107           if ( count )
00108             {
00109             newData->Set( sum / count, toOffset );
00110             }
00111           else
00112             {
00113             newData->SetPaddingAt( toOffset );
00114             }
00115           }
00116         }
00117       } // end for (z)
00118     newDataGrid->SetData( TypedArray::SmartPtr( newData ) );
00119     }
00120 
00121   newDataGrid->m_MetaInformation[META_IMAGE_ORIENTATION]  = this->m_MetaInformation[META_IMAGE_ORIENTATION];
00122   newDataGrid->m_MetaInformation[META_IMAGE_ORIENTATION_ORIGINAL]  = this->m_MetaInformation[META_IMAGE_ORIENTATION_ORIGINAL];
00123   
00124   return newDataGrid;
00125 }
00126 
00127 const DataGrid::SmartPtr
00128 DataGrid::GetReoriented( const char* newOrientation ) const
00129 {
00130   std::string curOrientation = this->m_MetaInformation[META_IMAGE_ORIENTATION];
00131   if ( curOrientation.length() != 3 ) 
00132     {
00133     curOrientation = std::string( AnatomicalOrientation::ORIENTATION_STANDARD );
00134     }
00135 
00136   if ( !newOrientation )
00137     {
00138     newOrientation = AnatomicalOrientation::ORIENTATION_STANDARD;
00139     }
00140 
00141   // 1. get a permutation matrix
00142   AnatomicalOrientation::PermutationMatrix pmatrix( this->m_Dims, curOrientation, newOrientation );
00143   
00144   Self::IndexType newDims = pmatrix.GetPermutedArray( this->m_Dims );
00145   DataGrid* newDataGrid = new DataGrid( newDims );
00146   
00147   const TypedArray* oldData = this->GetData();
00148   if ( oldData )
00149     {
00150     newDataGrid->CreateDataArray( oldData->GetType() );  
00151     TypedArray* newData = newDataGrid->GetData().GetPtr();
00152     
00153     if ( oldData->GetPaddingFlag() ) 
00154       {
00155       newData->SetPaddingValue( oldData->GetPaddingValue() );
00156       }
00157     
00158     const char* fromPtr = static_cast<const char*>( oldData->GetDataPtr() );
00159     char* toPtr = static_cast<char*>( newData->GetDataPtr() );
00160     
00161     // 2. loop through the data, applying transformation
00162     const size_t bytesPerPixel = oldData->GetItemSize();
00163 
00164     int fromPoint[3];
00165     for ( fromPoint[2] = 0; fromPoint[2] < this->m_Dims[2]; fromPoint[2]++ )
00166       {
00167       for ( fromPoint[1] = 0; fromPoint[1] < this->m_Dims[1]; fromPoint[1]++ )
00168         {
00169         for ( fromPoint[0] = 0; fromPoint[0] < this->m_Dims[0]; fromPoint[0]++, fromPtr += bytesPerPixel )
00170           {
00171           memcpy( toPtr + bytesPerPixel * pmatrix.NewOffsetFromPoint( fromPoint ), fromPtr, bytesPerPixel );
00172           }
00173         }
00174       }
00175     }
00176   
00177   newDataGrid->m_MetaInformation = this->m_MetaInformation;
00178   newDataGrid->m_MetaInformation[META_IMAGE_ORIENTATION] = newOrientation;
00179   newDataGrid->m_MetaInformation[META_IMAGE_ORIENTATION_ORIGINAL] = this->m_MetaInformation[META_IMAGE_ORIENTATION_ORIGINAL];
00180 
00181   return Self::SmartPtr( newDataGrid );
00182 }
00183 
00184 void
00185 DataGrid::SetDims( const Self::IndexType& dims )
00186 {
00187   this->m_Dims = dims;
00188   this->m_CropRegion = this->GetWholeImageRegion();
00189 
00190   nextI = 1;
00191   nextJ = nextI * this->m_Dims[0];
00192   nextK = nextJ * this->m_Dims[1];
00193   nextIJ = nextI + nextJ;
00194   nextIK = nextI + nextK;
00195   nextJK = nextJ + nextK;
00196   nextIJK = nextI + nextJ + nextK;
00197 }
00198 
00199 bool
00200 DataGrid::TrilinearInterpolation
00201 ( Types::DataItem& value, const int X, const int Y, const int Z,
00202   const Self::SpaceVectorType& Location, const Types::Coordinate* from, 
00203   const Types::Coordinate* to ) const
00204 {
00205   Types::DataItem corners[8];
00206 
00207   const size_t offset = this->GetOffsetFromIndex( X, Y, Z );
00208 
00209   const TypedArray* data = this->GetData();
00210   bool data_present = data->Get( corners[0], offset );
00211   
00212   if ( X<this->m_Dims[0]-1 ) 
00213     {
00214     data_present &= data->Get( corners[1] , offset+nextI );
00215     
00216     if ( Y<this->m_Dims[1]-1 ) 
00217       {
00218       data_present &= data->Get( corners[3], offset+nextIJ );
00219       
00220       if ( Z<this->m_Dims[2]-1 )
00221         data_present &= data->Get( corners[7], offset+nextIJK );
00222       else
00223         return false;
00224       } 
00225     else
00226       {
00227       return false;
00228       }
00229     data_present &= data->Get( corners[5], offset+nextIK );
00230     } 
00231   else
00232     {
00233     return false;
00234     }
00235   
00236   data_present &= data->Get( corners[2], offset+nextJ );
00237   data_present &= data->Get( corners[6], offset+nextJK );
00238   data_present &= data->Get( corners[4], offset+nextK );
00239 
00240   if (data_present) 
00241     {
00242     const Types::Coordinate deltaX=1/(to[0]-from[0]), deltaY=1/(to[1]-from[1]), deltaZ=1/(to[2]-from[2]);
00243     
00244     const Types::Coordinate revX = deltaX*(Location[0]-from[0]);
00245     const Types::Coordinate revY = deltaY*(Location[1]-from[1]);
00246     const Types::Coordinate revZ = deltaZ*(Location[2]-from[2]);
00247     const Types::Coordinate offsX = 1-revX;
00248     const Types::Coordinate offsY = 1-revY;
00249     const Types::Coordinate offsZ = 1-revZ;
00250     
00251     value = 
00252       static_cast<Types::DataItem>( offsZ*(offsY*(offsX*corners[0]+revX*corners[1])+ 
00253                                    revY*(offsX*corners[2]+revX*corners[3]))+
00254                             revZ*(offsY*(offsX*corners[4]+revX*corners[5])+ 
00255                                   revY*(offsX*corners[6]+revX*corners[7])));
00256     
00257     return true;
00258   }
00259 
00260   return false;
00261 }
00262 
00263 TypedArray::SmartPtr
00264 DataGrid::GetDataMirrorPlane( const int axis ) const
00265 {
00266   TypedArray::SmartPtr result( this->GetData()->Clone() );
00267   this->MirrorPlaneInPlace( *result, this->m_Dims, axis );
00268   
00269   return result;
00270 }
00271 
00272 void
00273 DataGrid::ApplyMirrorPlane( const int axis )
00274 {
00275   this->MirrorPlaneInPlace( *(this->GetData()), this->m_Dims, axis );
00276 }
00277 
00278 void
00279 DataGrid::MirrorPlaneInPlace
00280 ( TypedArray& data, const Self::IndexType& dims, const int axis )
00281 {
00282   switch ( axis ) 
00283     {
00284     case AXIS_X: 
00285     {
00286     int offset = 0;
00287     for ( int z = 0; z < dims[2]; ++z )
00288       for ( int y = 0; y < dims[1]; ++y, offset += dims[0] )
00289         data.BlockReverse( offset, dims[0] );
00290     }
00291     break;
00292     case AXIS_Y: 
00293     {
00294     size_t zOffset = 0;
00295     for ( int z = 0; z < dims[2]; ++z, zOffset += dims[0] * dims[1] ) 
00296       {
00297       for ( int y = 0; y < (dims[1] / 2); ++y )
00298         data.BlockSwap( zOffset + y * dims[0], zOffset + (dims[1] - 1 - y) * dims[0], dims[0] );
00299       }
00300     }
00301     break;
00302     case AXIS_Z: 
00303     {
00304     size_t blockSize = dims[0] * dims[1];
00305     for ( int z = 0; z < (dims[2] / 2); ++z ) 
00306       {
00307       data.BlockSwap( z * blockSize, (dims[2] - 1 - z) * blockSize, blockSize );
00308       }
00309     }
00310     break;
00311     }
00312 }
00313 
00314 TypedArray::SmartPtr
00315 DataGrid::GetDataMirrored
00316 ( const int axis ) const
00317 {
00318   const TypedArray* dataArray = this->GetData();
00319   if ( ! dataArray ) 
00320     throw( Exception( "No input data in DataGrid::GetDataMirrored()" ) );
00321   
00322   TypedArray::SmartPtr mirroredArray = TypedArray::Create( dataArray->GetType(), dataArray->GetDataSize() );
00323   
00324   Progress::Begin( 0, this->m_Dims[2], 1, "Mirror image" );
00325 
00326   size_t offset = 0;
00327   switch ( axis )
00328     {
00329     case AXIS_X:
00330       for ( int z = 0; z < this->m_Dims[2]; ++z ) 
00331         {
00332         Progress::SetProgress( z );
00333         for ( int y = 0; y < this->m_Dims[1]; ++y ) 
00334           {
00335           for ( int x = 0; x < this->m_Dims[0]; ++x, ++offset ) 
00336             {
00337             dataArray->BlockCopy( *mirroredArray, offset, offset, this->m_Dims[0] );
00338             mirroredArray->BlockReverse( offset, this->m_Dims[0] );
00339             }      
00340           }
00341         }
00342       break;
00343     case AXIS_Y:
00344     case AXIS_Z:
00345     default:
00346       StdErr << "DataGrid::GetDataMirrored: Flip not yet implemented\n";
00347       break;
00348     }
00349   
00350   Progress::Done();
00351      
00352   return mirroredArray;
00353 }
00354 
00355 ScalarImage*
00356 DataGrid::GetOrthoSlice
00357 ( const int axis, const unsigned int plane ) const
00358 {
00359   unsigned int dims[2], depth, incX, incY, incZ;
00360 
00361   switch ( axis ) 
00362     {
00363     case AXIS_X:
00364       dims[0] = this->m_Dims[1];
00365       dims[1] = this->m_Dims[2];
00366       depth = this->m_Dims[0];
00367       incX = this->m_Dims[0];
00368       incY = this->m_Dims[0] * this->m_Dims[1];
00369       incZ = 1;
00370       break;
00371     case AXIS_Y:
00372       dims[0] = this->m_Dims[0];
00373       dims[1] = this->m_Dims[2];
00374       depth = this->m_Dims[1];
00375       incX = 1;
00376       incY = this->m_Dims[0] * this->m_Dims[1];
00377       incZ = this->m_Dims[0];
00378       break;
00379     case AXIS_Z:
00380     default:
00381       dims[0] = this->m_Dims[0];
00382       dims[1] = this->m_Dims[1];
00383       depth = this->m_Dims[2];
00384       incX = 1;
00385       incY = this->m_Dims[0];
00386       incZ = this->m_Dims[0] * this->m_Dims[1];
00387       break;
00388     }
00389   
00390   const TypedArray* data = this->GetData();
00391   TypedArray::SmartPtr sliceData = TypedArray::Create( data->GetType(), dims[0] * dims[1] );
00392   if ( data->GetPaddingFlag() ) 
00393     {
00394     sliceData->SetPaddingValue( data->GetPaddingValue() );
00395     }
00396 
00397   //  if ( (plane < 0) || (plane >= depth) ) {
00398   if ( (plane >= depth) ) 
00399     { // need not check < 0 for unsigned int
00400     sliceData->ClearArray( true /* PaddingData */ );
00401     } 
00402   else
00403     {
00404     const unsigned int itemSize = data->GetItemSize();
00405     
00406     unsigned int sliceOffset = 0;
00407     unsigned int offset = plane * incZ;
00408     for ( unsigned int y = 0; y < dims[1]; ++y ) 
00409       {
00410       unsigned int offsetY = offset + incY;
00411       for ( unsigned int x = 0; x < dims[0]; ++x, ++sliceOffset ) 
00412         {
00413         unsigned int offsetX = offset + incX;
00414         
00415         memcpy( sliceData->GetDataPtr( sliceOffset ), data->GetDataPtr( offset ), itemSize );
00416         offset = offsetX;
00417         }
00418       offset = offsetY;
00419       }
00420     }
00421   
00422   ScalarImage* sliceImage = new ScalarImage( dims[0], dims[1] );
00423   sliceImage->SetPixelData( TypedArray::SmartPtr( sliceData ) );
00424   
00425   return sliceImage;
00426 }
00427 
00428 DataGrid*
00429 DataGrid::ExtractSliceVirtual
00430 ( const int axis, const int plane ) const
00431 {
00432   unsigned int dims[2], depth, incX, incY, incZ;
00433 
00434   switch ( axis ) 
00435     {
00436     case AXIS_X:
00437       dims[0] = this->m_Dims[1];
00438       dims[1] = this->m_Dims[2];
00439       depth = this->m_Dims[0];
00440       incX = this->m_Dims[0];
00441       incY = this->m_Dims[0] * this->m_Dims[1];
00442       incZ = 1;
00443       break;
00444     case AXIS_Y:
00445       dims[0] = this->m_Dims[0];
00446       dims[1] = this->m_Dims[2];
00447       depth = this->m_Dims[1];
00448       incX = 1;
00449       incY = this->m_Dims[0] * this->m_Dims[1];
00450       incZ = this->m_Dims[0];
00451       break;
00452     case AXIS_Z:
00453     default:
00454       dims[0] = this->m_Dims[0];
00455       dims[1] = this->m_Dims[1];
00456       depth = this->m_Dims[2];
00457       incX = 1;
00458       incY = this->m_Dims[0];
00459       incZ = this->m_Dims[0] * this->m_Dims[1];
00460       break;
00461     }
00462   
00463   const TypedArray& data = *(this->GetData());
00464   TypedArray::SmartPtr sliceData = TypedArray::Create( data.GetType(), dims[0] * dims[1] );
00465   if ( data.GetPaddingFlag() ) 
00466     {
00467     sliceData->SetPaddingValue( data.GetPaddingValue() );
00468     }
00469 
00470   if ( plane >= this->m_Dims[axis] ) 
00471     { 
00472     sliceData->ClearArray( true /* PaddingData */ );
00473     } 
00474   else
00475     {
00476     const unsigned int itemSize = data.GetItemSize();
00477     
00478     unsigned int sliceOffset = 0;
00479     unsigned int offset = plane * incZ;
00480     for ( unsigned int y = 0; y < dims[1]; ++y ) 
00481       {
00482       unsigned int offsetY = offset + incY;
00483       for ( unsigned int x = 0; x < dims[0]; ++x, ++sliceOffset ) 
00484         {
00485         unsigned int offsetX = offset + incX;
00486         
00487         memcpy( sliceData->GetDataPtr( sliceOffset ), data.GetDataPtr( offset ), itemSize );
00488         offset = offsetX;
00489         }
00490       offset = offsetY;
00491       }
00492     }
00493   
00494   IndexType newDims = this->m_Dims;
00495   newDims[axis] = 1;
00496 
00497   return new DataGrid( newDims, sliceData );
00498 }
00499 
00500 void 
00501 DataGrid::SetOrthoSlice
00502 ( const int axis, const unsigned int idx, const ScalarImage* slice )
00503 {
00504   const TypedArray* sliceData = slice->GetPixelData();
00505   if ( ! sliceData ) return;
00506 
00507   TypedArray::SmartPtr data = this->GetData();
00508   if ( ! data )
00509     {
00510     data = this->CreateDataArray( sliceData->GetType() );
00511     }
00512 
00513   unsigned int dims[2], depth, incX, incY, incZ;
00514 
00515   switch ( axis ) 
00516     {
00517     case AXIS_X:
00518       dims[0] = this->m_Dims[1];
00519       dims[1] = this->m_Dims[2];
00520       depth = this->m_Dims[0];
00521       incX = this->m_Dims[0];
00522       incY = this->m_Dims[0] * this->m_Dims[1];
00523       incZ = 1;
00524       break;
00525     case AXIS_Y:
00526       dims[0] = this->m_Dims[0];
00527       dims[1] = this->m_Dims[2];
00528       depth = this->m_Dims[1];
00529       incX = 1;
00530       incY = this->m_Dims[0] * this->m_Dims[1];
00531       incZ = this->m_Dims[0];
00532       break;
00533     case AXIS_Z:
00534     default:
00535       dims[0] = this->m_Dims[0];
00536       dims[1] = this->m_Dims[1];
00537       depth = this->m_Dims[2];
00538       incX = 1;
00539       incY = this->m_Dims[0];
00540       incZ = this->m_Dims[0] * this->m_Dims[1];
00541       break;
00542     }
00543   
00544   if ( (idx < depth) )
00545     { // need not check > 0 for unsigned int
00546     unsigned int sliceOffset = 0;
00547     unsigned int offset = idx * incZ;
00548     for ( unsigned int y = 0; y < dims[1]; ++y ) 
00549       {
00550       unsigned int offsetY = offset + incY;
00551       for ( unsigned int x = 0; x < dims[0]; ++x, ++sliceOffset ) 
00552         {
00553         unsigned int offsetX = offset + incX;
00554         
00555         sliceData->BlockCopy( *data, offset, sliceOffset, 1 );
00556         offset = offsetX;
00557         }
00558       offset = offsetY;
00559       }
00560     }
00561 }
00562 
00563 FixedVector<3,Types::Coordinate>
00564 DataGrid
00565 ::GetCenterOfMassGrid() const
00566 {
00567   FixedVector<3,Types::Coordinate> com( FixedVector<3,Types::Coordinate>::Init( 0 ) );
00568 
00569   double sumOfSamples = 0;
00570   size_t ofs = 0;
00571   for ( int z = 0; z < this->m_Dims[2]; ++z )
00572     for ( int y = 0; y < this->m_Dims[1]; ++y )
00573       for ( int x = 0; x < this->m_Dims[0]; ++x, ++ofs )
00574         {
00575         Types::DataItem value;
00576         if ( this->GetDataAt( value, x, y, z ) )
00577           {
00578           const Types::Coordinate pixelCOM[3] = { value * x, value * y, value * z };
00579           com += Self::SpaceVectorType( pixelCOM );
00580           sumOfSamples += value;
00581           }
00582         }
00583 
00584   com *= (1.0 / sumOfSamples);
00585 
00586   return com;
00587 }
00588 
00589 FixedVector<3,Types::Coordinate>
00590 DataGrid
00591 ::GetCenterOfMassGrid(  FixedVector<3,Types::Coordinate>& firstOrderMoment ) const
00592 {
00593   FixedVector<3,Types::Coordinate> com = this->Self::GetCenterOfMassGrid(); // do not use overloaded function
00594   firstOrderMoment = FixedVector<3,Types::Coordinate>( FixedVector<3,Types::Coordinate>::Init( 0 ) );
00595 
00596   double sumOfSamples = 0;
00597   size_t ofs = 0;
00598   for ( int z = 0; z < this->m_Dims[2]; ++z )
00599     for ( int y = 0; y < this->m_Dims[1]; ++y )
00600       for ( int x = 0; x < this->m_Dims[0]; ++x, ++ofs )
00601         {
00602         Types::DataItem value;
00603         if ( this->GetDataAt( value, x, y, z ) )
00604           {
00605           const Types::Coordinate pixelMoment[3] = { value * fabs(x - com[0]), value * fabs(y - com[1]), value * fabs(z - com[2]) };
00606           firstOrderMoment += Self::SpaceVectorType( pixelMoment );
00607           sumOfSamples += value;
00608           }
00609         }
00610   
00611   firstOrderMoment *= (1.0 / sumOfSamples);
00612 
00613   return com;
00614 }
00615 
00616 void 
00617 DataGrid::Print() const
00618 {
00619   StdErr.printf( "DataGrid at %p\n", this );
00620 
00621   StdErr.printf( "\tthis->m_Dims: [%d,%d,%d])\n", this->m_Dims[0], this->m_Dims[1], this->m_Dims[2] );
00622   StdErr.printf( "\tData array at %p\n", this );
00623 }
00624 
00625 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines