cmtkFilterVolume_Coupe.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: 2425 $
00026 //
00027 //  $LastChangedDate: 2010-10-07 16:14:23 -0700 (Thu, 07 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include "cmtkFilterVolume.h"
00034 
00035 namespace
00036 cmtk
00037 {
00038 
00039 Types::DataItem
00040 FilterVolume::Mean
00041 ( CoupeBlock items )
00042 {
00043   Types::DataItem sum = 0.0;
00044   for ( int i = 0; i < COUPE_BLOCK_SIZE; i++ )
00045     sum += items[i];
00046   return sum / COUPE_BLOCK_SIZE;
00047 }
00048 
00049 Types::DataItem
00050 FilterVolume::Variance
00051 ( CoupeBlock items, const Types::DataItem mean )
00052 {
00053   Types::DataItem sum = 0.0;
00054   for ( int i = 0; i < COUPE_BLOCK_SIZE; i++ )
00055     sum += pow( items[i] - mean, 2 );
00056   return sum / COUPE_BLOCK_SIZE;
00057 }
00058 
00059 void
00060 FilterVolume::BlockAddInPlace
00061 ( CoupeBlock v1, CoupeBlock v2 )
00062 {
00063   
00064   for ( int i = 0; i < COUPE_BLOCK_SIZE; i++ )
00065     v1[i] += v2[i] ;
00066 }
00067 
00068 void
00069 FilterVolume::BlockSubtract
00070 ( CoupeBlock diff, CoupeBlock v1, CoupeBlock v2 )
00071 {
00072   for ( int i = 0; i < COUPE_BLOCK_SIZE; i++ )
00073     diff[i] = v1[i] - v2[i];
00074 }
00075 
00076 void
00077 FilterVolume::BlockConstMult
00078 ( CoupeBlock prod, CoupeBlock items, const Types::DataItem mult )
00079 {
00080   for ( int i = 0; i < COUPE_BLOCK_SIZE; i++ )
00081     prod[i] = items[i] * mult;
00082 }
00083 
00084 double
00085 FilterVolume::BlockSquaredDistance
00086 ( CoupeBlock centerBlock, CoupeBlock outerBlock )
00087 {
00088   CoupeBlock diff; 
00089   BlockSubtract( diff, centerBlock, outerBlock );   
00090   
00091   Types::DataItem sum = 0.0;
00092   for ( int i = 0; i < COUPE_BLOCK_SIZE; i++ )
00093     sum += pow( diff[i], 2 );
00094   return ( sum );  // Coupe paper uses squared distance
00095 }
00096 
00097 void
00098 FilterVolume::GetCoupeBlock
00099 ( CoupeBlock block,
00100   const TypedArray* data, const int* dims,
00101   const int x, const int y, const int z )
00102 {
00103 
00104   const int blockRadius = COUPE_BLOCK_RADIUS;
00105   int curBlockSlot = 0;
00106   /*  No bounds-checking here.  The program should fail if 
00107    *  a block is requested too close to the edge of the image.
00108    */
00109   for ( int k = z - blockRadius; k <= z + blockRadius; ++k )
00110     for ( int j = y - blockRadius; j <= y + blockRadius; ++j )
00111       for ( int i = x - blockRadius; i <= x + blockRadius; ++i ) 
00112         {
00113         int offset = i + dims[AXIS_X] * ( j + dims[AXIS_Y] * k );
00114         Types::DataItem value;
00115         data->Get( value, offset );
00116         block[curBlockSlot++] = value;
00117         }
00118 }
00119 
00120 double 
00121 FilterVolume::ComputeCoupeWeight
00122 ( const Types::DataItem smoothingParam, 
00123   CoupeBlock centerBlock, 
00124   CoupeBlock outerBlock )
00125 {
00126   const double numerator = BlockSquaredDistance( centerBlock, outerBlock );
00127   
00128   double weight = 1.0;
00129   if ( numerator != 0 )
00130     weight = exp( -(log(numerator) / smoothingParam) );
00131   //std::cout << numerator << ", " << smoothingParam << std::endl;
00132   //std::cout << weight << "\n";
00133   return weight;
00134 }
00135 
00136 void
00137 FilterVolume::ComputeNLWithinWindow
00138 ( CoupeBlock NL,
00139   const TypedArray* blockLocations,
00140   const TypedArray* data, const int* dims, const Types::DataItem smoothingParam,
00141   const int x, const int y, const int z, 
00142   const int windowRadius, 
00143   const float, // beta 
00144   const TypedArray* localMeansMap, 
00145   const TypedArray* localVariancesMap, 
00146   CoupeBlock centerBlock )
00147 {
00148 
00149   /*  These two constants were determined experimentally
00150    *  by Coupe, et al.  (Section V-C, Fig. 8.)
00151    */
00152   const float Mu1 = 0.95;
00153   const float Sigma1SQ = 0.5;
00154   
00155   /*  In this loop, build a set of weights from only
00156    *  that portion of the neighborhood-window that falls
00157    *  within the image boundaries.
00158    */
00159   int curNeighbor = 0;
00160   int centerBlockPos = -1;
00161   const int windowSize = (2 * windowRadius + 1) * (2 * windowRadius + 1) * (2 * windowRadius + 1);
00162   const int blockRadius = COUPE_BLOCK_RADIUS;
00163   int centerOffset = x + dims[AXIS_X] * ( y + dims[AXIS_Y] * z );
00164   Types::DataItem centerBlockMean, centerBlockVariance;
00165   localMeansMap->Get( centerBlockMean, centerOffset );
00166   localVariancesMap->Get( centerBlockVariance, centerOffset );
00167   CoupeBlock curBlock;
00168   int offset = 0;
00169   Types::DataItem blockAtCurVox = 0.0;
00170 #ifdef CMTK_VAR_AUTO_ARRAYSIZE
00171   Types::DataItem neighborBlocks[windowSize][COUPE_BLOCK_SIZE];
00172   Types::DataItem neighborWeights[windowSize];
00173 #else
00174   Matrix2D<Types::DataItem> neighborBlocks( windowSize, COUPE_BLOCK_SIZE );
00175   std::vector<Types::DataItem> neighborWeights( windowSize );
00176 #endif
00177   Types::DataItem curBlockMean, curBlockVariance;
00178   Types::DataItem ratioBlockMean, ratioBlockVariance;
00179   for ( int k = z - windowRadius; k <= z + windowRadius; k++ )
00180     if ( ( k >= blockRadius ) && ( k < dims[AXIS_Z] - blockRadius ) )
00181       {
00182       for ( int j = y - windowRadius; j <= y + windowRadius; j++ )
00183         if ( ( j >= blockRadius ) && ( j < dims[AXIS_Y] - blockRadius ) )
00184           {
00185           for ( int i = x - windowRadius; i <= x + windowRadius; i++ )
00186             if ( ( i >= blockRadius ) && ( i < dims[AXIS_X] - blockRadius ) )
00187               {
00188               offset = i + dims[AXIS_X] * ( j + dims[AXIS_Y] * k );
00189               blockLocations->Get( blockAtCurVox, offset ); 
00190               if ( blockAtCurVox ) // if there's a block here
00191                 {
00192                 GetCoupeBlock( curBlock, data, dims, i, j, k );
00193                 localMeansMap->Get( curBlockMean, offset );
00194                 localVariancesMap->Get( curBlockVariance, offset );
00195                 ratioBlockMean = centerBlockMean / curBlockMean;
00196                 /*  This block is to handle the 0:0 ratio without divide-by-zero
00197                  */
00198                 if ( curBlockVariance != 0 ) 
00199                   {
00200                   ratioBlockVariance = centerBlockVariance / curBlockVariance;
00201                   }
00202                 else
00203                   {
00204                   ratioBlockVariance = ( centerBlockVariance == 0 ) ? 1.0 : 0.0;
00205                   }
00206 
00207                 if ( ( Mu1 <= ratioBlockMean ) && ( ratioBlockMean <= ( 1 / Mu1 ) )
00208                   && ( Sigma1SQ <= ratioBlockVariance ) && ( ratioBlockVariance <= ( 1 / Sigma1SQ ) ) )
00209                   {
00210                   /*  Handle blocks that aren't the center block here,
00211                    *  handle the center block in 'else' below
00212                    */
00213                   if ( ( ( i != x ) || ( j != y ) || ( k != z ) ) ) 
00214                     {
00215                     double weight = ComputeCoupeWeight( smoothingParam, centerBlock, curBlock );
00216                     if ( weight > 0 )
00217                       {
00218                       if ( ( i == 91 ) && ( j == 1 ) && ( k == 93 ) ) 
00219                         {
00220                         Types::DataItem tmp;
00221                         data->Get( tmp, offset );
00222                         std::cout << i << "," << j << "," << k << "\t";
00223                         std::cout << tmp << "\t" << curBlockMean << "\t" << weight << "\n";
00224                         }
00225                       memcpy( neighborBlocks[curNeighbor], curBlock, sizeof( curBlock ) );
00226                       neighborWeights[curNeighbor] = weight;
00227                       }
00228                     }
00229                   /*  Handle center block
00230                    */
00231                   else
00232                     {
00233                     if ( ( i == 91 ) && ( j == 1 ) && ( k == 93 ) ) 
00234                       {
00235                       Types::DataItem tmp;
00236                       data->Get( tmp, offset );
00237                       std::cout << i << "," << j << "," << k << "\t" << tmp << "\t";
00238                       std::cout << curBlockMean << "\t..." << "\n";
00239                       }
00240                     memcpy( neighborBlocks[curNeighbor], curBlock, sizeof( curBlock ) );
00241                     
00242                     /*  Store the position of the center block
00243                      *  w.r.t. the list of used neighbors, for use
00244                      *  in the weighting clause below.
00245                      */
00246                     centerBlockPos = curNeighbor;
00247                     }
00248                   curNeighbor++;
00249                   }
00250                 }
00251               }
00252           }
00253       }
00254   int numNeighborsUsed = curNeighbor + 1;
00255 
00256   /*  As per Manjon et al, 2008, set the weight of the center
00257    *  block to equal the largest of the neighbor-weights.
00258    */
00259   if ( numNeighborsUsed < 2 )
00260     {
00261     neighborWeights[centerBlockPos] = 1.0;
00262     }
00263   else
00264     {
00265     Types::DataItem maxWt = 0.0;
00266     for ( int i = 0; i < numNeighborsUsed; i++ )
00267       maxWt = ( neighborWeights[i] > maxWt ) ? neighborWeights[i] : maxWt;
00268     //neighborWeights[centerBlockPos] = 1.0;
00269     neighborWeights[centerBlockPos] = maxWt;
00270     }
00271 
00272   /*  Sum the weights for normalization
00273    */
00274   Types::DataItem weightsSum = 0.0;
00275   for ( int i = 0; i < numNeighborsUsed; i++ )
00276     weightsSum += neighborWeights[i];
00277 
00278   for ( int i = 0; i < COUPE_BLOCK_SIZE; i++ )
00279     NL[i] = 0.0;
00280 
00281   //if ( weightsSum > 1e-9 ) 
00282   if ( weightsSum != 0 ) 
00283     {
00284     /*  Multiply each neighborBlock by its normalized weight,
00285      *  then add that to the output NL value.
00286      */  
00287     CoupeBlock weightedCurBlock;
00288     Types::DataItem tmp = 0.0;
00289     for ( int i = 0; i < numNeighborsUsed; i++ )
00290       {
00291       Types::DataItem normalizedWeight = 0;
00292         normalizedWeight = neighborWeights[i] / weightsSum;
00293 
00294       tmp += normalizedWeight;
00295       BlockConstMult( weightedCurBlock, neighborBlocks[i], normalizedWeight );
00296       BlockAddInPlace( NL, weightedCurBlock );
00297       }
00298     }
00299   else
00300     {
00301     BlockAddInPlace( NL, neighborBlocks[centerBlockPos] );
00302     }
00303     //std::cout <<x<< ","<<y<<","<<z<<"\t"<< (weightsSum-neighborWeights[centerBlockPos])/(numNeighborsUsed-1);
00304     //std::cout << "\t" << neighborWeights[centerBlockPos] <<"\n";
00305     //std::cout <<x<< ","<<y<<","<<z<<"\t"<<weightsSum<<"\t"<<tmp<<"\t";
00306     //std::cout << numNeighborsUsed<< "\n";
00307 }
00308 
00309 TypedArray::SmartPtr
00310 FilterVolume::CoupeFilter
00311 ( const UniformVolume* volume, 
00312   const int windowRadius,
00313   const float beta )
00314 {
00315   /*  This algorithm requires that blocks be smaller
00316    *  than the search neighborhood / window.
00317    */
00318   assert ( COUPE_BLOCK_RADIUS < windowRadius );
00319 
00320   bool BLOCKWISE_NLM = true;
00321 
00322   const TypedArray* inputData = volume->GetData();
00323   if ( ! inputData ) 
00324     return TypedArray::SmartPtr( NULL );
00325 
00326   TypedArray::SmartPtr filtered = TypedArray::Create( inputData->GetType(), inputData->GetDataSize() );
00327   const int* dims = volume->GetDims().begin();
00328   const int dimX = dims[AXIS_X];
00329   const int dimY = dims[AXIS_Y];
00330   const int dimZ = dims[AXIS_Z];
00331   const int blockRadius = COUPE_BLOCK_RADIUS;
00332   const int stepSize = BLOCKWISE_NLM ? 2 : 1;
00333   
00334   std::cout << "Block radius:\t" << COUPE_BLOCK_RADIUS << "\n";
00335   std::cout << "Window radius:\t" << windowRadius << "\n";
00336   std::cout << "Beta:\t\t" << beta << std::endl;
00337   std::cout << "Dimensions:\t" 
00338             << dimX << " x " 
00339             << dimY << " x " 
00340             << dimZ << std::endl;
00341   
00342   std::vector< std::vector<Types::DataItem>* > NLsPerVoxel;
00343 
00344   /*  Initialize an array with a vector for each voxel,
00345    *  to store a set of NL estimates for each voxel.
00346    */
00347   for ( int i = 0; i < ( dimX * dimY * dimZ ); i++ )
00348     {
00349     std::vector<Types::DataItem>* tmp;
00350     NLsPerVoxel.push_back( tmp );
00351     NLsPerVoxel[i] = new std::vector<Types::DataItem>();
00352     } 
00353  
00354   /*  Compute the smoothing parameter 
00355    */
00356   //Types::DataItem varianceEst = ( EstimateNoiseVariance( inputData, dims ) );
00357   Types::DataItem stdDevEst = (Types::DataItem)3.70101;
00358   Types::DataItem varianceEst = stdDevEst * stdDevEst;
00359   std::cout << "varianceEst:\t" << varianceEst << std::endl;
00360   Types::DataItem smoothingParam = 2 * beta * varianceEst * COUPE_BLOCK_SIZE;
00361   //Types::DataItem smoothingParam = pow( 2.19037, 2 );
00362   std::cout << "h:\t\t"<< sqrt(smoothingParam) << std::endl;
00363   
00364   /*  Figure out where the blocks will be
00365    */
00366   TypedArray::SmartPtr blockLocations = TypedArray::Create(  TYPE_INT, inputData->GetDataSize() );
00367   int blockCount = 0;
00368   for ( int z = blockRadius; z < dimZ - blockRadius; z++ )
00369     for ( int y = blockRadius; y < dimY - blockRadius ; y++ )
00370       for ( int x = blockRadius; x < dimX - blockRadius; x++ )
00371         {
00372         int offset = x + dimX * ( y + dimY * z );
00373         if ( ( ( x % stepSize ) == 0 ) && ( ( y % stepSize ) == 0 ) && ( ( z % stepSize ) == 0 ) ) 
00374           {
00375           blockLocations->Set( 1.0, offset );
00376           blockCount++;
00377           }
00378         else
00379           {
00380           blockLocations->Set( 0.0, offset );
00381           }
00382         }
00383   std::cout << "Block count:\t" << blockCount << std::endl;
00384 
00385 
00386   /*  Precompute the local means and local variances maps
00387    */
00388   CoupeBlock curBlock;
00389   TypedArray::SmartPtr localMeansMap = TypedArray::Create( TYPE_DOUBLE, inputData->GetDataSize() );
00390   TypedArray::SmartPtr localVariancesMap = TypedArray::Create( TYPE_DOUBLE, inputData->GetDataSize() );
00391   for ( int z = blockRadius; z < dimZ - blockRadius; z++ )
00392     for ( int y = blockRadius; y < dimY - blockRadius ; y++ )
00393       for ( int x = blockRadius; x < dimX - blockRadius; x++ )
00394         {
00395         int offset = x + dimX * ( y + dimY * z );
00396         FilterVolume::GetCoupeBlock( curBlock, inputData, dims, x, y, z );
00397         Types::DataItem mean = FilterVolume::Mean( curBlock );
00398         Types::DataItem variance = FilterVolume::Variance( curBlock, mean );
00399         localMeansMap->Set( mean, offset);
00400         localVariancesMap->Set( variance, offset);
00401         }
00402 
00403   /*  Loop through the image, computing NL estimates
00404    *  for each voxel.
00405    */
00406 //  CoupeBlock centerBlock;
00407 //  CoupeBlock curNL;
00408   Types::DataItem blockAtCurVox = 0.0;
00409   for ( int Cz = blockRadius; Cz < dimZ - blockRadius; Cz ++ )
00410     {
00411     for ( int Cy = blockRadius; Cy < dimY - blockRadius; Cy ++ )
00412       for ( int Cx = blockRadius; Cx < dimX - blockRadius; Cx ++ ) 
00413         {
00414         int windowOffset = Cx + dimX * ( Cy + dimY * Cz );
00415         blockLocations->Get( blockAtCurVox, windowOffset ); 
00416         if ( blockAtCurVox ) // if there's a block here
00417           {
00418          
00419           Types::DataItem maxWeight = 0.0; // to hold the highest neighbor-weight below
00420           Types::DataItem weightsSum = 0.0; // to hold the sum of the neighbor weights below
00421           Types::DataItem outputTmp = 0.0; // to accumulate the neighbor weights in voxel-wise case
00422           Types::DataItem NLblock[COUPE_BLOCK_SIZE]; // to accumulate the weighted sum of neighbor blocks in block-wise case
00423           Types::DataItem flattenedBlock[COUPE_BLOCK_SIZE]; // to store 1-D representation of neighbor block in block-wise case
00424           
00425           /*  Initialize accumulator block for current neighborhood
00426            */
00427           if ( BLOCKWISE_NLM )
00428             for ( int i = 0; i < COUPE_BLOCK_SIZE; i++ ) NLblock[i] = 0.0;
00429 
00430           /*  Gather statistics on current voxel for use in the
00431            *  similarity threshold below
00432            */
00433           Types::DataItem centerMean, centerVariance;
00434           localMeansMap->Get( centerMean, windowOffset );
00435           localVariancesMap->Get( centerVariance, windowOffset );
00436 
00437           /*  Iterate through the blocks of the window centered at Cx,Cy,Cz
00438            *  ( Nx, Ny, Nz are the x,y,z coordinates of the current neighbor block )
00439            */
00440           for ( int Nz = std::max( Cz - windowRadius, 0 ); Nz < std::min( Cz + windowRadius, dimZ ); Nz++ )
00441             for ( int Ny = std::max( Cy - windowRadius, 0 ); Ny < std::min( Cy + windowRadius, dimZ ); Ny++ )
00442               for ( int Nx = std::max( Cx - windowRadius, 0 ); Nx < std::min( Cx + windowRadius, dimZ ); Nx++ )
00443                 {
00444                 Types::DataItem neighborDist = 0.0;  // Will hold Euclidean dist. of center and current neighbor intensities
00445                 int neighborOffset = Nx + dimX * ( Ny + dimY * Nz );
00446                 blockLocations->Get( blockAtCurVox, neighborOffset ); 
00447                 if ( blockAtCurVox 
00448                     && ( ( Nx != Cx) || ( Ny != Cy ) || ( Nz != Cz ) ) ) // skip center block for now
00449                   {
00450                   /*  Only use blocks falling within the similarity range.
00451                    *  So here, compute the ratio of the means of the center
00452                    *  block and the neighbor block, and the ratio of their
00453                    *  variances.  Then proceed only if those values fall
00454                    *  within the desired range.
00455                    */
00456                   Types::DataItem nbMean, nbVariance;
00457                   localMeansMap->Get( nbMean, neighborOffset );
00458                   localVariancesMap->Get( nbVariance, neighborOffset );
00459                   Types::DataItem ratioMeans = centerMean / nbMean;
00460                   Types::DataItem ratioVariance = centerVariance / nbVariance;
00461                   Types::DataItem mu1 = (Types::DataItem)0.5;
00462                                   Types::DataItem sigma1 = (Types::DataItem)0.95;
00463                   if ( ( ratioMeans > mu1 ) && ( ratioMeans <= 1 / mu1 )
00464                        && ( ratioVariance > sigma1 ) && ( ratioVariance <= 1 / sigma1 ) )
00465                     {
00466                    
00467                     /*  Initialize 1-D array for applicaton of weight to current block
00468                      */
00469                     if ( BLOCKWISE_NLM )
00470                       for ( int i = 0; i < COUPE_BLOCK_SIZE; i++ ) flattenedBlock[i] = 0.0;
00471 
00472                     /*  Iterate through center block and neighbor block in parallel,
00473                      *  calculating the squared Euclidean distance between the two.
00474                      *  Only use blocks that fall completely within the image.
00475                      *  ( Ix,Iy,Iz are the x,y,z coordinates of the center block voxels,
00476                      *    Jx,Jx,jZ are the x,y,z coordinates of the neighbor block voxels. )
00477                      */
00478                     int i = 0;
00479                     for ( int Bz = -blockRadius; Bz <= blockRadius; Bz++ )
00480                       {
00481                       int Iz = Cz + Bz; int Jz = Nz + Bz;
00482                       if ( ( Iz >= 0 ) && ( Iz < dimZ ) && ( Jz >= 0 ) && ( Jz < dimZ ) ) 
00483                       for ( int By = -blockRadius; By <= blockRadius; By++ )
00484                         {
00485                         int Iy = Cy + By; int Jy = Ny + By;
00486                         if ( ( Iy >= 0 ) && ( Iy < dimY ) && ( Jy >= 0 ) && ( Jy < dimY ) ) 
00487                         for ( int Bx = -blockRadius; Bx <= blockRadius; Bx++ )
00488                           {
00489                           int Ix = Cx + Bx; int Jx = Nx + Bx;
00490                           if ( ( Ix >= 0 ) && ( Ix < dimX ) && ( Jx >= 0 ) && ( Jx < dimX ) ) 
00491                             {
00492                             int BIoffset = Ix + dimX * ( Iy + dimY * Iz );
00493                             int BJoffset = Jx + dimX * ( Jy + dimY * Jz );
00494                             Types::DataItem BI, BJ;
00495                             inputData->Get( BI, BIoffset );
00496                             inputData->Get( BJ, BJoffset );
00497                             Types::DataItem distIJ = BI - BJ;
00498                             neighborDist += distIJ * distIJ;
00499                             if ( BLOCKWISE_NLM ) flattenedBlock[i++] = BJ;
00500                             }
00501                           }
00502                         }
00503                       }
00504                     Types::DataItem curWeight = exp( log(neighborDist) / smoothingParam );
00505                     weightsSum += curWeight;
00506                     maxWeight = ( curWeight > maxWeight ) ? curWeight : maxWeight;
00507                    
00508                     if ( BLOCKWISE_NLM )
00509                       {
00510                       /*  Weight the neighbor block and add that 
00511                        *  to the accumulator block
00512                        */
00513                       for ( int ii = 0; ii < COUPE_BLOCK_SIZE; ii++)
00514                         {
00515                         NLblock[ii] += curWeight * flattenedBlock[ii];
00516           //std::cout << curWeight << "\t" << flattenedBlock[ii] << "\n";
00517                         }
00518                       }
00519                       else  // voxel-wise case
00520                         {
00521                         /*  Weight the neighbor voxel and add that 
00522                          *  to the accumulator value
00523                          */
00524                         Types::DataItem neighbValue;
00525                         inputData->Get( neighbValue, neighborOffset );
00526                         outputTmp += curWeight * neighbValue;
00527                         }
00528 
00529                     } // end similarity-threshold test
00530                   } // end test for J != I
00531                 } // end loop through blocks of current window
00532           
00533           /*  Current center block gets weighted by
00534            *  the maximum neighbor-weight
00535            */ 
00536           Types::DataItem centerValue;
00537           inputData->Get( centerValue, windowOffset );     
00538           outputTmp += maxWeight * centerValue;
00539           weightsSum += maxWeight;
00540 
00541           if ( BLOCKWISE_NLM )
00542             {
00543             /*  Push the accumulator block into place for averaging  
00544              *  later 
00545              *  ( Ix,Iy,Iz are the coordinates the center block voxels )
00546              */
00547             int i = 0;
00548             for ( int Iz = Cz - blockRadius; Iz <= Cz + blockRadius; Iz++ )
00549               {
00550               if ( ( Iz >= 0 ) && ( Iz < dimZ ) )
00551               for ( int Iy = Cy - blockRadius; Iy <= Cy + blockRadius; Iy++ )
00552                 {
00553                 if ( ( Iy >= 0 ) && ( Iy < dimY ) )
00554                 for ( int Ix = Cx - blockRadius; Ix <= Cx + blockRadius; Ix++ )
00555                   {
00556                   if ( ( Ix >= 0 ) && ( Ix < dimX ) )
00557                     {
00558                     int Voffset = Ix + dimX * ( Iy + dimY * Iz );
00559           //std::cout << Voffset << "\t" << NLblock[i] << "\n";
00560                     NLsPerVoxel[Voffset]->push_back( NLblock[i] );
00561                     i++;
00562                     }
00563                   }
00564                 }
00565               }
00566             }
00567           else
00568             {
00569             /*  Set the output voxel
00570              */
00571             filtered->Set( outputTmp / weightsSum, windowOffset );
00572             }
00573 
00574           } // end if ( blockAtCurVox )
00575         } // end loop through pixels of image 
00576 
00577 //                    FilterVolume::ComputeNLWithinWindow( curNL, blockLocations, inputData, dims, smoothingParam,
00578 //                                                            Cx, Cy, Cz, 
00579 //                                                            windowRadius, 
00580 //                                                            beta,
00581 //                                                            localMeansMap, 
00582 //                                                            localVariancesMap, 
00583 //                                                            centerBlock );
00584 //                    /*  Push the values from curNL into the vector
00585 //                    *  containing the NL estimates for the respective
00586 //                    *  corresponding voxels.  (curNL contains an NL
00587 //                    *  estimate for each voxel in this block).
00588 //                    */
00589 //                    int curNLIndex = 0;
00590 //                    for ( int k = z - blockRadius; k <= z + blockRadius; ++k )
00591 //                      if ( ( k >= 0 ) && ( k < dimZ ) )
00592 //                        {
00593 //                        for ( int j = y - blockRadius; j <= y + blockRadius; ++j )
00594 //                          if ( ( j >= 0 ) && ( j < dimY ) )
00595 //                            {
00596 //                            for ( int i = x - blockRadius; i <= x + blockRadius; ++i )
00597 //                              if ( ( i >= 0 ) && ( i < dimX ) )
00598 //                                {
00599 //                                int offset = i + dimX * ( j + dimY * k );
00600 //                                NLsPerVoxel[offset]->push_back( curNL[curNLIndex] ); 
00601 //                                curNLIndex++;
00602 //                                }
00603 //                            }
00604 //                        }
00605     }
00606 
00607 
00608 
00609   if ( BLOCKWISE_NLM )
00610     {
00611     /*  Take the average of the NL estimates for each voxel
00612     */
00613     int NLsPerVoxelHist[40] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
00614     for ( int z = 0; z < dimZ; ++z )
00615       for ( int y = 0; y < dimY; ++y )
00616         for ( int x = 0; x < dimX; ++x ) 
00617           {
00618           int offset = x + dimX * ( y + dimY * z );
00619           NLsPerVoxelHist[NLsPerVoxel.at( offset )->size()]++;
00620           Types::DataItem curNLSum = 0.0;
00621           for ( std::vector<Types::DataItem>::iterator it = NLsPerVoxel.at( offset )->begin(); it != NLsPerVoxel.at( offset )->end(); it++ )
00622             curNLSum += *it;
00623 
00624           Types::DataItem restoredVoxel = curNLSum / NLsPerVoxel.at( offset )->size();
00625           //std::cout << offset << "\t" << curNLSum << "\t" << NLsPerVoxel.at( offset )->size() << "\n";
00626 
00627           filtered->Set( restoredVoxel , offset );
00628 
00629           if ( ( x == 91 ) && ( y == 1 ) && ( z == 93 ) ) 
00630             {
00631             std::cout << std::endl;
00632             std::cout << std::endl;
00633             for ( std::vector<Types::DataItem>::iterator it = NLsPerVoxel.at( offset )->begin(); it != NLsPerVoxel.at( offset )->end(); it++ )
00634               {
00635               std::cout << *it << "..." << "\n";
00636               }
00637             std::cout << restoredVoxel << "." << "\n";
00638             }
00639 
00640           }
00641 
00642     /*  Print out the histogram of NL counts
00643      */ 
00644     std::cout << std::endl;
00645     std::cout << "NL-count histogram:" << std::endl;
00646     std::cout << "0\t1\t2\t3\t4\t5\t6\t7\t8\t9\t10\t11\t12\t13\t14\t15\t16\t17\t18\t19" << std::endl;
00647     for ( int i = 0; i < 20; i++ )
00648       std::cout << NLsPerVoxelHist[i] << "\t";
00649     std::cout << std::endl;
00650     std::cout << std::endl;
00651     std::cout << "20\t21\t22\t23\t24\t25\t26\t27\t28\t29\t30\t31\t32\t33\t34\t35\t36\t37\t38\t39" << std::endl;
00652     for ( int i = 20; i < 40; i++ )
00653       std::cout << NLsPerVoxelHist[i] << "\t";
00654     std::cout << std::endl;
00655     std::cout << std::endl;
00656     }
00657  
00658 
00659   return filtered;
00660 }
00661 
00662 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines