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 #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) );
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
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
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
00465
00466
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
00496
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 }