cmtkFilterVolume.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: 2464 $
00026 //
00027 //  $LastChangedDate: 2010-10-19 09:54:33 -0700 (Tue, 19 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torsten_at_home $
00030 //
00031 */
00032 
00033 #include "cmtkFilterVolume.h"
00034 
00035 #include <Base/cmtkMathUtil.h>
00036 #include <Base/cmtkFilterMask.h>
00037 #include <Base/cmtkHistogram.h>
00038 #include <Base/cmtkJointHistogram.h>
00039 
00040 #include <System/cmtkProgress.h>
00041 #include <System/cmtkThreads.h>
00042 #include <System/cmtkException.h>
00043 
00044 #ifdef _OPENMP
00045 #  include <omp.h>
00046 #endif
00047 
00048 namespace
00049 cmtk
00050 {
00051 
00054 
00055 TypedArray::SmartPtr
00056 FilterVolume::GaussianFilter
00057 ( const UniformVolume* volume, const Units::GaussianSigma& kernelWidth, const Types::Coordinate radius, const TypedArray* maskData )
00058 {
00059   const TypedArray* inputData = volume->GetData();
00060   if ( ! inputData ) 
00061     throw( Exception( "Missing image data" ) );
00062   
00063   TypedArray::SmartPtr filtered = TypedArray::Create( inputData->GetType(), inputData->GetDataSize() );
00064   
00065   const DataGrid::IndexType& dims = volume->m_Dims;
00066   FilterMask<3> filter( dims, volume->Deltas(), radius, FilterMask<3>::Gaussian( kernelWidth ) );
00067 
00068   const int dimsX = dims[AXIS_X];
00069   const int dimsY = dims[AXIS_Y];
00070   const int dimsZ = dims[AXIS_Z];
00071   
00072   Progress::Begin( 0, dimsZ, 1, "Gaussian Filter" );
00073 
00074 #pragma omp parallel for
00075   for ( int z = 0; z < dimsZ; ++z )
00076     {
00077     size_t offset = z * dimsX * dimsY;
00078     Progress::SetProgress( z );
00079     for ( int y = 0; y < dimsY; ++y )
00080       for ( int x = 0; x < dimsX; ++x, ++offset ) 
00081         {
00082         Types::DataItem average = 0.0, weight = 0.0;
00083           
00084         Types::DataItem maskValue = 0.0;
00085         if ( maskData )
00086           {
00087           maskData->Get( maskValue, offset );
00088           }
00089         else
00090           {
00091           maskValue = 1.0;
00092           }
00093           
00094         if ( maskValue ) 
00095           {
00096           FilterMask<3>::const_iterator it = filter.begin();
00097           while ( it != filter.end() ) 
00098             {
00099             const int xx = x + it->Location[0];
00100             const int yy = y + it->Location[1];
00101             const int zz = z + it->Location[2];
00102                     
00103             if ( (xx>=0) && (yy>=0) && (zz>=0) && (xx < (int)dimsX) && (yy < (int)dimsY) && (zz < (int)dimsZ) ) 
00104               {
00105               const size_t srcOffset = volume->GetOffsetFromIndex( xx, yy, zz );
00106               Types::DataItem value;
00107               if ( inputData->Get( value, srcOffset ) ) 
00108                 {
00109                 average += it->Coefficient * value;
00110                 weight += it->Coefficient;
00111                 }
00112               }
00113             ++it;           
00114             }
00115           }
00116         if ( weight > 0.0 ) 
00117           {
00118           filtered->Set( average / weight, offset );
00119           } 
00120         else 
00121           {
00122           filtered->SetPaddingAt( offset );
00123           }
00124         }
00125     }
00126   
00127   Progress::Done();
00128 
00129   return filtered;
00130 }
00131 
00132 void 
00133 printBlock
00134 ( Types::DataItem block[COUPE_BLOCK_SIZE] )
00135 {
00136   for ( int i = 0; i < COUPE_BLOCK_SIZE; i++ )
00137     std::cout << block[i] << "   ";
00138 }
00139 
00140 TypedArray::SmartPtr
00141 FilterVolume
00142 ::RohlfingFilter
00143 ( const UniformVolume* volume, const TypedArray* subjectData,
00144   const TypedArray* maskData, const Units::GaussianSigma& iFilterSigma,
00145   const Units::GaussianSigma& filterWidth, const Types::Coordinate filterRadius )
00146 {
00147   const TypedArray* inputData = volume->GetData();
00148   if ( ! inputData )
00149     throw( Exception( "Missing image data" ) );
00150  
00151   const Types::DataItemRange rangeSubj = subjectData->GetRange();
00152   
00153   const size_t numBins = 1024;
00154 #ifdef _OPENMP
00155   const size_t maxThreads = omp_get_max_threads();
00156   std::vector<Histogram<Types::DataItem>::SmartPtr> histograms( maxThreads );
00157   for ( size_t thread = 0; thread < maxThreads; ++thread )
00158     {
00159     histograms[thread] = Histogram<Types::DataItem>::SmartPtr( new Histogram<Types::DataItem>( numBins ) );
00160     histograms[thread]->SetRange( rangeSubj );
00161     }
00162 #else // #ifdef _OPENMP
00163   Histogram<Types::DataItem> histogram( numBins );
00164   histogram.SetRange( rangeSubj );
00165 #endif // #ifdef _OPENMP
00166 
00167   const size_t iKernelRadius = 1 + static_cast<size_t>( 2 * iFilterSigma.Value() * numBins );
00168   std::vector<Types::DataItem> iKernel( iKernelRadius );
00169   if ( iKernelRadius > 1 )
00170     {
00171     const Types::DataItem normFactor = static_cast<Types::DataItem>( 1.0/(sqrt(2*M_PI) * iFilterSigma.Value() * numBins) ); // not really necessary since we normalize during convolution
00172     for ( size_t i = 0; i < iKernelRadius; ++i )
00173       {
00174       iKernel[i] = static_cast<Types::DataItem>( normFactor * exp( -MathUtil::Square( 1.0 * i / (iFilterSigma.Value()*numBins) ) / 2 ) );
00175       }
00176     }
00177   else
00178     {
00179     iKernel[0] = 1.0;
00180     }
00181   
00182   TypedArray::SmartPtr filtered = TypedArray::Create( inputData->GetType(), inputData->GetDataSize() );
00183   
00184   const DataGrid::IndexType& dims = volume->GetDims();
00185   FilterMask<3> filter( dims, volume->Deltas(), filterRadius, FilterMask<3>::Gaussian( filterWidth ) );
00186   
00187   const unsigned int dimsX = dims[AXIS_X];
00188   const unsigned int dimsY = dims[AXIS_Y];
00189   const unsigned int dimsZ = dims[AXIS_Z];
00190   
00191   Progress::Begin( 0, dimsZ, 1, "Rohlfing Intensity-Consistent Filter" );
00192 
00193 #pragma omp parallel for
00194   for ( unsigned int z = 0; z < dimsZ; ++z ) 
00195     {      
00196     size_t offset = z * dimsX * dimsY;
00197 
00198 #ifdef _OPENMP
00199     const size_t threadIdx = omp_get_thread_num();
00200     Histogram<Types::DataItem>& histogram = *(histograms[threadIdx]);
00201     if ( ! threadIdx )
00202 #endif // #ifdef _OPENMP
00203       Progress::SetProgress( z );
00204 
00205     for ( unsigned int y = 0; y < dimsY; ++y )
00206       for ( unsigned int x = 0; x < dimsX; ++x, ++offset ) 
00207         {
00208         Types::DataItem average = 0.0, weight = 0.0;
00209             
00210         Types::DataItem maskValue = 1.0;
00211         if ( maskData )
00212           maskData->Get( maskValue, offset );
00213             
00214         Types::DataItem valueSubj;
00215         if ( maskValue && subjectData->Get( valueSubj, offset ) ) 
00216           {
00217           histogram.Reset();
00218           histogram.AddWeightedSymmetricKernel( histogram.ValueToBin( valueSubj ), iKernelRadius, &(iKernel[0]) );
00219           
00220           for (  FilterMask<3>::const_iterator it = filter.begin(); it != filter.end(); ++it ) 
00221             {
00222             const int xx = x + it->Location[0];
00223             const int yy = y + it->Location[1];
00224             const int zz = z + it->Location[2];
00225                     
00226             if ( (xx>=0) && (yy>=0) && (zz>=0) && (xx < (int)dimsX) && (yy < (int)dimsY) && (zz < (int)dimsZ) ) 
00227               {
00228               Types::DataItem value;
00229               const size_t srcOffset = it->RelativeIndex + offset;
00230               if ( inputData->Get( value, srcOffset ) ) 
00231                 {                           
00232                 Types::DataItem valueSubj;
00233                 if ( subjectData->Get( valueSubj, srcOffset ) )
00234                   {
00235                   const size_t bin = histogram.ValueToBin( valueSubj );
00236                   const Types::DataItem prob = it->Coefficient * histogram[bin];
00237                   
00238                   average += value * prob;
00239                   weight += prob;
00240                   }
00241                 }
00242               }
00243             }
00244           }
00245         
00246         if ( weight > 0.0 )
00247           {
00248           filtered->Set( average / weight, offset );
00249           } 
00250         else
00251           {
00252           filtered->SetPaddingAt( offset );
00253           }
00254         }
00255     }
00256   
00257   Progress::Done();
00258 
00259   return filtered;
00260 }
00261 
00262 TypedArray::SmartPtr
00263 FilterVolume::StudholmeFilter
00264 ( const UniformVolume* volume, const TypedArray* subjectData,
00265   const TypedArray* averageData, const TypedArray* maskData,
00266   std::list<TypedArray::SmartPtr> imgList, const Types::DataItem binWidth, 
00267   const Units::GaussianSigma& filterWidth, const Types::Coordinate filterRadius )
00268 {
00269   const TypedArray* inputData = volume->GetData();
00270   if ( ! inputData )
00271     throw( Exception( "Missing image data" ) );
00272  
00273   const Types::DataItemRange range = averageData->GetRange();
00274   const size_t numBins = std::min( 128, 1 + static_cast<int>((range.Width()) / binWidth) );
00275 
00276   TypedArray::SmartPtr filtered = TypedArray::Create( inputData->GetType(), inputData->GetDataSize() );
00277   
00278   const DataGrid::IndexType& dims = volume->GetDims();
00279   const unsigned int dimsX = dims[AXIS_X];
00280   const unsigned int dimsY = dims[AXIS_Y];
00281   const unsigned int dimsZ = dims[AXIS_Z];
00282   const unsigned int numberOfRows = dimsY * dimsZ;
00283   
00284   const size_t numberOfThreads = Threads::GetNumberOfThreads();
00285   std::vector< JointHistogram<Types::DataItem> > histogramByThread( numberOfThreads );
00286   std::vector<FilterMask<3>::SmartPtr> filterByThread( numberOfThreads );
00287   
00288   for ( size_t idx = 0; idx < numberOfThreads; ++idx )
00289     {
00290     histogramByThread[idx].Resize( numBins, numBins );
00291     histogramByThread[idx].SetRangeX( range );
00292     histogramByThread[idx].SetRangeY( range );
00293     
00294     FilterMask<3>::SmartPtr filter( new FilterMask<3>( dims, volume->Deltas(), filterRadius, FilterMask<3>::Gaussian( filterWidth ) ) );    
00295     filterByThread[idx] = filter;
00296     }
00297   
00298   Progress::Begin( 0, numberOfRows, 1, "Studholme Intensity-Consistent Filter" );
00299 #pragma omp parallel for
00300   for ( unsigned int row = 0; row < numberOfRows; ++row ) 
00301     {
00302     const unsigned int y = row % dimsY;
00303     const unsigned int z = row / dimsY;
00304     
00305     Progress::SetProgress( z );
00306     size_t offset = row * dimsX;
00307      
00308 #ifdef _OPENMP
00309     const int thread = omp_get_thread_num();
00310 #else
00311     const int thread = 0;
00312 #endif
00313 
00314     JointHistogram<Types::DataItem>& histogram = histogramByThread[thread];
00315     FilterMask<3>& filter = *(filterByThread[thread]);
00316  
00317     for ( unsigned int x = 0; x < dimsX; ++x, ++offset ) 
00318       {
00319       Types::DataItem average = 0.0, weight = 0.0;
00320       histogram.Reset();
00321             
00322       Types::DataItem maskValue = 1.0;
00323       if ( maskData )
00324         maskData->Get( maskValue, offset );
00325             
00326       Types::DataItem valueAvg;
00327       if ( maskValue && averageData->Get( valueAvg, offset ) ) 
00328         {
00329                 
00330         // first iteration over filter: compute consistency histogram
00331         FilterMask<3>::iterator it = filter.begin();
00332         for ( ; it != filter.end(); ++it ) 
00333           {
00334           const int xx = x + it->Location[0];
00335           const int yy = y + it->Location[1];
00336           const int zz = z + it->Location[2];
00337                     
00338           if ( (xx>=0) && (yy>=0) && (zz>=0) && (xx < (int)dimsX) && (yy < (int)dimsY) && (zz < (int)dimsZ) ) 
00339             {
00340             it->Valid = true;         
00341 
00342             const size_t srcOffset = it->RelativeIndex + offset;
00343             it->PixelIndex = srcOffset;
00344                         
00345             Types::DataItem valueAvgSrc, valueSubj;
00346             if ( averageData->Get( valueAvgSrc, srcOffset ) ) 
00347               {                     
00348               const size_t binAvg = histogram.ValueToBinX( valueAvgSrc );
00349               for ( std::list<TypedArray::SmartPtr>::iterator itImg = imgList.begin(); itImg != imgList.end(); ++itImg ) 
00350                 {
00351                 if ( (*itImg)->Get( valueSubj, srcOffset ) ) 
00352                   {
00353                   histogram.Increment( binAvg, histogram.ValueToBinY( valueSubj ) );
00354                   }
00355                 }
00356                 
00357               }
00358             }
00359           else
00360             {
00361             it->Valid = false;
00362             }               
00363           }
00364           
00365         const size_t binX = histogram.ValueToBinX( valueAvg );
00366         const Types::DataItem avgHistogramValueInv = static_cast<Types::DataItem>( 1.0/histogram.ProjectToX( binX ) );
00367           
00368         for ( it = filter.begin(); it != filter.end(); ++it ) 
00369           {
00370           if ( it->Valid ) 
00371             {
00372             Types::DataItem value;
00373             if ( inputData->Get( value, it->PixelIndex ) ) 
00374               {                     
00375               Types::DataItem valueSubj;
00376               if ( subjectData->Get( valueSubj, it->PixelIndex ) )
00377                 {
00378                 const size_t binY = histogram.ValueToBinY( valueSubj );
00379                   
00380                 const Types::DataItem prob = static_cast<Types::DataItem>( it->Coefficient * avgHistogramValueInv * histogram.GetBin( binX, binY ) );
00381                   
00382                 average += value * prob;
00383                 weight += prob;
00384                 }
00385               }
00386             }
00387           }
00388         }
00389         
00390       if ( weight > 0.0 )
00391         {
00392         filtered->Set( average / weight, offset );
00393         } 
00394       else
00395         {
00396         filtered->SetPaddingAt( offset );
00397         }
00398       }
00399     }
00400   
00401   Progress::Done();
00402   
00403   return filtered;
00404 }
00405 
00406 TypedArray::SmartPtr
00407 FilterVolume::StudholmeFilter
00408 ( const UniformVolume* volume, 
00409   std::list<TypedArray::SmartPtr> subjectData,
00410   const TypedArray* averageData, const TypedArray* maskData,
00411   std::list<TypedArray::SmartPtr> imgList, const Types::DataItem binWidth, 
00412   const Units::GaussianSigma& filterWidth, const Types::Coordinate filterRadius )
00413 {
00414   const TypedArray* inputData = volume->GetData();
00415   if ( ! inputData ) 
00416     throw( Exception( "Missing image data" ) );
00417  
00418   const Types::DataItemRange range = averageData->GetRange();
00419 
00420   const size_t numBins = std::min( 128, 1 + static_cast<int>( range.Width() / binWidth ) );
00421   JointHistogram<Types::DataItem> histogram( numBins, numBins );
00422   histogram.SetRangeX( range );
00423   histogram.SetRangeY( range );
00424  
00425   TypedArray::SmartPtr filtered = TypedArray::Create( inputData->GetType(), inputData->GetDataSize() );
00426   
00427   const DataGrid::IndexType& dims = volume->GetDims();
00428   FilterMask<3> filter( dims, volume->Deltas(), filterRadius, FilterMask<3>::Gaussian( filterWidth ) );
00429   
00430   const unsigned int dimsX = dims[AXIS_X];
00431   const unsigned int dimsY = dims[AXIS_Y];
00432   const unsigned int dimsZ = dims[AXIS_Z];
00433 
00434   Progress::Begin( 0, dimsZ, 1, "Studholme Intensity-Consistent Filter" );
00435 
00436   size_t offset = 0;
00437   for ( unsigned int z = 0; z < dimsZ; ++z ) 
00438     {
00439     Progress::SetProgress( z );
00440       
00441     for ( unsigned int y = 0; y < dimsY; ++y )
00442       for ( unsigned int x = 0; x < dimsX; ++x, ++offset ) 
00443         {
00444         Types::DataItem average = 0.0, weight = 0.0;
00445         histogram.Reset();
00446             
00447         Types::DataItem maskValue = 1.0;
00448         if ( maskData )
00449           maskData->Get( maskValue, offset );
00450             
00451         Types::DataItem valueAvg;
00452         if ( maskValue && averageData->Get( valueAvg, offset ) ) 
00453           {
00454           // first iteration over filter: compute consistency histogram
00455           for ( FilterMask<3>::iterator it = filter.begin(); it != filter.end(); ++it ) 
00456             {
00457             const unsigned int xx = x + it->Location[0];
00458             const unsigned int yy = y + it->Location[1];
00459             const unsigned int zz = z + it->Location[2];
00460                     
00461             if ( (xx < dimsX) && (yy < dimsY) && (zz < dimsZ) ) 
00462               {
00463               it->Valid = true;       
00464               // since xx, yy, zz are unsigned, we need not check 
00465               // for >= 0; this is taken care of by overflow (we 
00466               // hope ;)
00467               const size_t srcOffset = volume->GetOffsetFromIndex( xx, yy, zz );
00468               Types::DataItem valueAvgSrc, valueSubj;
00469               if ( averageData->Get( valueAvgSrc, srcOffset ) ) 
00470                 {
00471                 const size_t binAvg = histogram.ValueToBinX( valueAvgSrc );
00472                 for ( std::list<TypedArray::SmartPtr>::iterator itImg = imgList.begin(); itImg != imgList.end(); ++itImg ) 
00473                   {
00474                   if ( (*itImg)->Get( valueSubj, srcOffset ) ) 
00475                     {
00476                     histogram.Increment( binAvg, histogram.ValueToBinY( valueSubj ) );
00477                     }
00478                   }             
00479                 }
00480               }
00481             }
00482           
00483           Histogram<Types::DataItem>* avgHistogram = histogram.GetMarginalX();
00484           const size_t binX = histogram.ValueToBinX( valueAvg );
00485           
00486           for ( FilterMask<3>::iterator it = filter.begin(); it != filter.end(); ++it ) 
00487             {
00488             const unsigned int xx = x + it->Location[0];
00489             const unsigned int yy = y + it->Location[1];
00490             const unsigned int zz = z + it->Location[2];
00491             
00492             if ( it->Valid ) 
00493               {
00494               it->Valid = false;
00495               // since xx, yy, zz are unsigned, we need not check for
00496               // >= 0; this is taken care of by overflow (we hope ;)
00497               const size_t srcOffset = volume->GetOffsetFromIndex( xx, yy, zz );
00498               Types::DataItem value;
00499               if ( inputData->Get( value, srcOffset ) ) 
00500                 {
00501                 float prob = it->Coefficient;
00502                 
00503                 std::list<TypedArray::SmartPtr>::iterator subjectIt = subjectData.begin();
00504                 while ( subjectIt != subjectData.end() ) 
00505                   {
00506                   Types::DataItem valueSubj;
00507                   if ( (*subjectIt)->Get( valueSubj, srcOffset ) )
00508                     {
00509                     const size_t binY = histogram.ValueToBinY( valueSubj );
00510                     prob *= histogram.GetBin( binX, binY ) / (*avgHistogram)[binX];
00511                     }
00512                   ++subjectIt;
00513                   }
00514                 
00515                 average += value * prob;
00516                 weight += prob;
00517                 }
00518               }
00519             }
00520           
00521           delete avgHistogram;
00522           }
00523             
00524         if ( weight > 0.0 ) 
00525           {
00526           filtered->Set( average / weight, offset );
00527           } 
00528         else 
00529           {
00530           filtered->SetPaddingAt( offset );
00531           }
00532         }
00533     }
00534   
00535   Progress::Done();
00536   
00537   return filtered;
00538 }
00539 
00540 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines