Go to the documentation of this file.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 <Segmentation/cmtkEntropyMinimizationIntensityCorrectionFunctionalBase.h>
00034
00035 #include <System/cmtkThreadPool.h>
00036 #include <System/cmtkException.h>
00037
00038 #include <algorithm>
00039
00040 #ifdef CMTK_BUILD_DEMO
00041 # include <IO/cmtkVolumeIO.h>
00042 #endif // #ifdef CMTK_BUILD_DEMO
00043
00044 namespace cmtk
00045 {
00046
00049 void
00050 EntropyMinimizationIntensityCorrectionFunctionalBase
00051 ::SetInputImage( UniformVolume::SmartConstPtr& inputImage )
00052 {
00053 this->m_InputImage = inputImage;
00054 this->m_NumberOfPixels = this->m_InputImage->GetNumberOfPixels();
00055
00056 const Types::DataItemRange range = this->m_InputImage->GetData()->GetRange();
00057 this->m_InputImageRange = range.Width();
00058
00059 if ( this->m_UseLogIntensities )
00060 {
00061 this->m_EntropyHistogram = HistogramType::SmartPtr( new LogHistogramType( this->m_NumberOfHistogramBins ) );
00062 }
00063 else
00064 {
00065 this->m_EntropyHistogram = HistogramType::SmartPtr( new HistogramType( this->m_NumberOfHistogramBins ) );
00066 }
00067
00068 this->m_EntropyHistogram->SetRange( Types::DataItemRange( range.m_LowerBound - this->m_InputImageRange, range.m_UpperBound + this->m_InputImageRange ) );
00069
00070 if ( this->m_ForegroundMask.size() )
00071 this->UpdateCorrectionFactors();
00072
00073 this->m_BiasFieldAdd = FloatArray::Create( this->m_NumberOfPixels );
00074 this->m_BiasFieldAdd->Fill( 0.0 );
00075 this->m_BiasFieldMul = FloatArray::Create( this->m_NumberOfPixels );
00076 this->m_BiasFieldAdd->Fill( 1.0 );
00077
00078 this->m_OutputImage = UniformVolume::SmartPtr( this->m_InputImage->CloneGrid() );
00079 this->m_OutputImage->CreateDataArray( TYPE_FLOAT );
00080 }
00081
00082 void
00083 EntropyMinimizationIntensityCorrectionFunctionalBase
00084 ::SetForegroundMask( const UniformVolume& foregroundMask )
00085 {
00086 const size_t maskPixels = foregroundMask.GetNumberOfPixels();
00087
00088 if ( maskPixels != this->m_NumberOfPixels )
00089 {
00090 throw Exception( "Number of mask pixels does not match number of input image pixels." );
00091 }
00092
00093 this->m_ForegroundMask.resize( maskPixels );
00094 if ( (this->m_SamplingDensity > 0) && (this->m_SamplingDensity < 1) )
00095 {
00096 for ( size_t i = 0; i < maskPixels; ++i )
00097 {
00098 this->m_ForegroundMask[i] = (foregroundMask.GetDataAt( i ) > 0) && (MathUtil::UniformRandom() <= this->m_SamplingDensity);
00099 }
00100 }
00101 else
00102 {
00103 for ( size_t i = 0; i < maskPixels; ++i )
00104 {
00105 this->m_ForegroundMask[i] = (foregroundMask.GetDataAt( i ) > 0);
00106 }
00107 }
00108
00109 if ( this->m_InputImage )
00110 this->UpdateCorrectionFactors();
00111 }
00112
00113 UniformVolume::SmartPtr&
00114 EntropyMinimizationIntensityCorrectionFunctionalBase
00115 ::GetOutputImage( CoordinateVector& v, const bool foregroundOnly )
00116 {
00117 this->SetParamVector( v );
00118 this->UpdateBiasFields( foregroundOnly );
00119 this->UpdateOutputImage( foregroundOnly );
00120 return this->m_OutputImage;
00121 }
00122
00123 EntropyMinimizationIntensityCorrectionFunctionalBase::ReturnType
00124 EntropyMinimizationIntensityCorrectionFunctionalBase
00125 ::EvaluateAt( CoordinateVector& v )
00126 {
00127 this->SetParamVector( v );
00128 this->UpdateBiasFields();
00129 this->UpdateOutputImage();
00130 return this->Evaluate();
00131 }
00132
00133 #ifdef CMTK_BUILD_DEMO
00134 void
00135 EntropyMinimizationIntensityCorrectionFunctionalBase
00136 ::SnapshotAt( CoordinateVector& v )
00137 {
00138 this->SetParamVector( v );
00139 this->UpdateBiasFields();
00140
00141 static int it = 0;
00142 this->UpdateOutputImage( false );
00143 UniformVolume::SmartConstPtr slice = this->m_OutputImage->ExtractSlice( AXIS_Z, this->m_OutputImage->m_Dims[2] / 2 );
00144
00145 char path[PATH_MAX];
00146 snprintf( path, PATH_MAX, "mrbias-%03d.nii", it++ );
00147 VolumeIO::Write( *slice, path );
00148 }
00149 #endif
00150
00151
00152 void
00153 EntropyMinimizationIntensityCorrectionFunctionalBase
00154 ::UpdateOutputImage( const bool foregroundOnly )
00155 {
00156 ThreadPool& threadPool = ThreadPool::GetGlobalThreadPool();
00157 const size_t numberOfTasks = 4 * threadPool.GetNumberOfThreads() - 3;
00158
00159 std::vector<UpdateOutputImageThreadParameters> taskParameters( numberOfTasks );
00160 for ( size_t task = 0; task < numberOfTasks; ++task )
00161 {
00162 taskParameters[task].thisObject = this;
00163 taskParameters[task].m_ForegroundOnly = foregroundOnly;
00164 }
00165 threadPool.Run( UpdateOutputImageThreadFunc, taskParameters );
00166 }
00167
00168 void
00169 EntropyMinimizationIntensityCorrectionFunctionalBase
00170 ::UpdateOutputImageThreadFunc( void *args, const size_t taskIdx, const size_t taskCnt, const size_t, const size_t )
00171 {
00172 UpdateOutputImageThreadParameters* threadParameters = static_cast<UpdateOutputImageThreadParameters*>( args );
00173
00174 Self* This = threadParameters->thisObject;
00175 const Self* ThisConst = threadParameters->thisObject;
00176
00177 const UniformVolume* inputImage = ThisConst->m_InputImage;
00178 TypedArray::SmartPtr outputData = This->m_OutputImage->GetData();
00179 const size_t numberOfPixels = inputImage->GetNumberOfPixels();
00180
00181 const float* biasFieldPtrAdd = ThisConst->m_BiasFieldAdd->GetDataPtrTemplate();
00182 const float* biasFieldPtrMul = ThisConst->m_BiasFieldMul->GetDataPtrTemplate();
00183
00184 Types::DataItem value;
00185 for ( size_t ofs = taskIdx; ofs < numberOfPixels; ofs += taskCnt )
00186 {
00187 if ( !threadParameters->m_ForegroundOnly || ThisConst->m_ForegroundMask[ofs] )
00188 {
00189 if ( inputImage->GetDataAt( value, ofs ) )
00190 {
00191 outputData->Set( value * biasFieldPtrMul[ofs] + biasFieldPtrAdd[ofs], ofs );
00192 }
00193 else
00194 {
00195 outputData->SetPaddingAt( ofs );
00196 }
00197 }
00198 else
00199 {
00200 outputData->SetPaddingAt( ofs );
00201 }
00202 }
00203 }
00204
00205 }