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 #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 );
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
00107
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
00132
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,
00144 const TypedArray* localMeansMap,
00145 const TypedArray* localVariancesMap,
00146 CoupeBlock centerBlock )
00147 {
00148
00149
00150
00151
00152 const float Mu1 = 0.95;
00153 const float Sigma1SQ = 0.5;
00154
00155
00156
00157
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 )
00191 {
00192 GetCoupeBlock( curBlock, data, dims, i, j, k );
00193 localMeansMap->Get( curBlockMean, offset );
00194 localVariancesMap->Get( curBlockVariance, offset );
00195 ratioBlockMean = centerBlockMean / curBlockMean;
00196
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
00211
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
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
00243
00244
00245
00246 centerBlockPos = curNeighbor;
00247 }
00248 curNeighbor++;
00249 }
00250 }
00251 }
00252 }
00253 }
00254 int numNeighborsUsed = curNeighbor + 1;
00255
00256
00257
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
00269 neighborWeights[centerBlockPos] = maxWt;
00270 }
00271
00272
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
00282 if ( weightsSum != 0 )
00283 {
00284
00285
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
00304
00305
00306
00307 }
00308
00309 TypedArray::SmartPtr
00310 FilterVolume::CoupeFilter
00311 ( const UniformVolume* volume,
00312 const int windowRadius,
00313 const float beta )
00314 {
00315
00316
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
00345
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
00355
00356
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
00362 std::cout << "h:\t\t"<< sqrt(smoothingParam) << std::endl;
00363
00364
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
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
00404
00405
00406
00407
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 )
00417 {
00418
00419 Types::DataItem maxWeight = 0.0;
00420 Types::DataItem weightsSum = 0.0;
00421 Types::DataItem outputTmp = 0.0;
00422 Types::DataItem NLblock[COUPE_BLOCK_SIZE];
00423 Types::DataItem flattenedBlock[COUPE_BLOCK_SIZE];
00424
00425
00426
00427 if ( BLOCKWISE_NLM )
00428 for ( int i = 0; i < COUPE_BLOCK_SIZE; i++ ) NLblock[i] = 0.0;
00429
00430
00431
00432
00433 Types::DataItem centerMean, centerVariance;
00434 localMeansMap->Get( centerMean, windowOffset );
00435 localVariancesMap->Get( centerVariance, windowOffset );
00436
00437
00438
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;
00445 int neighborOffset = Nx + dimX * ( Ny + dimY * Nz );
00446 blockLocations->Get( blockAtCurVox, neighborOffset );
00447 if ( blockAtCurVox
00448 && ( ( Nx != Cx) || ( Ny != Cy ) || ( Nz != Cz ) ) )
00449 {
00450
00451
00452
00453
00454
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
00468
00469 if ( BLOCKWISE_NLM )
00470 for ( int i = 0; i < COUPE_BLOCK_SIZE; i++ ) flattenedBlock[i] = 0.0;
00471
00472
00473
00474
00475
00476
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
00511
00512
00513 for ( int ii = 0; ii < COUPE_BLOCK_SIZE; ii++)
00514 {
00515 NLblock[ii] += curWeight * flattenedBlock[ii];
00516
00517 }
00518 }
00519 else
00520 {
00521
00522
00523
00524 Types::DataItem neighbValue;
00525 inputData->Get( neighbValue, neighborOffset );
00526 outputTmp += curWeight * neighbValue;
00527 }
00528
00529 }
00530 }
00531 }
00532
00533
00534
00535
00536 Types::DataItem centerValue;
00537 inputData->Get( centerValue, windowOffset );
00538 outputTmp += maxWeight * centerValue;
00539 weightsSum += maxWeight;
00540
00541 if ( BLOCKWISE_NLM )
00542 {
00543
00544
00545
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
00560 NLsPerVoxel[Voffset]->push_back( NLblock[i] );
00561 i++;
00562 }
00563 }
00564 }
00565 }
00566 }
00567 else
00568 {
00569
00570
00571 filtered->Set( outputTmp / weightsSum, windowOffset );
00572 }
00573
00574 }
00575 }
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605 }
00606
00607
00608
00609 if ( BLOCKWISE_NLM )
00610 {
00611
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
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
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 }