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
00034
00035 #include "cmtkUniformDistanceMap.h"
00036
00037 #include <Base/cmtkDataTypeTraits.h>
00038
00039 #include <System/cmtkThreadPool.h>
00040
00041 namespace
00042 cmtk
00043 {
00044
00047
00048 template<class TDistanceDataType>
00049 UniformDistanceMap<TDistanceDataType>
00050 ::UniformDistanceMap
00051 ( const UniformVolume& volume, const byte flags, const Types::DataItem value, const Types::DataItem window )
00052 {
00053 this->BuildDistanceMap( volume, flags, value, window );
00054
00055 this->m_DistanceMap->m_IndexToPhysicalMatrix = volume.m_IndexToPhysicalMatrix;
00056
00057 this->m_DistanceMap->SetOffset( volume.m_Offset );
00058 this->m_DistanceMap->m_MetaInformation = volume.m_MetaInformation;
00059 }
00060
00061 template<class TDistanceDataType>
00062 void
00063 UniformDistanceMap<TDistanceDataType>
00064 ::BuildDistanceMap
00065 ( const UniformVolume& volume, const byte flags, const Types::DataItem value, const Types::DataItem window )
00066 {
00067 this->m_DistanceMap = UniformVolume::SmartPtr( new UniformVolume( volume.m_Dims, volume.Size ) );
00068
00069 TypedArray::SmartPtr distanceArray = TypedArray::SmartPtr( TypedArray::Create( DataTypeTraits<DistanceDataType>::DataTypeID, volume.GetNumberOfPixels() ) );
00070 DistanceDataType *Distance = static_cast<DistanceDataType*>( distanceArray->GetDataPtr() );
00071
00072 byte inside = ( flags & UniformDistanceMap::INSIDE ) ? 0 : 1;
00073 byte outside = 1 - inside;
00074
00075 const TypedArray* Feature = volume.GetData();
00076
00077 Types::DataItem c;
00078 DistanceDataType *p = Distance;
00079 if ( flags & UniformDistanceMap::VALUE_EXACT )
00080 {
00081 for ( size_t i = 0; i < volume.GetNumberOfPixels(); i++, p++ )
00082 {
00083 if ( Feature->Get( c, i ) )
00084 {
00085 *p = (c == value) ? inside : outside;
00086 }
00087 else
00088 {
00089 *p = outside;
00090 }
00091 }
00092 }
00093 else if ( flags & UniformDistanceMap::VALUE_THRESHOLD )
00094 {
00095 for ( size_t i = 0; i < volume.GetNumberOfPixels(); i++, p++ )
00096 {
00097 if ( Feature->Get( c, i ) )
00098 {
00099 *p = (c >= value) ? inside : outside;
00100 }
00101 else
00102 {
00103 *p = outside;
00104 }
00105 }
00106 }
00107 else if ( flags & UniformDistanceMap::VALUE_WINDOW )
00108 {
00109 for ( size_t i = 0; i < volume.GetNumberOfPixels(); i++, p++ )
00110 {
00111 if ( Feature->Get( c, i ) )
00112 {
00113 *p = (fabs(c - value)<=window) ? inside : outside;
00114 }
00115 else
00116 {
00117 *p = outside;
00118 }
00119 }
00120 }
00121 else
00122 {
00123 for ( size_t i = 0; i < volume.GetNumberOfPixels(); i++, p++ )
00124 {
00125 if ( Feature->Get( c, i ) )
00126 {
00127 *p = (c) ? inside : outside;
00128 }
00129 else
00130 {
00131 *p = outside;
00132 }
00133 }
00134 }
00135
00136 this->ComputeEDT( Distance );
00137
00138 p = Distance;
00139 for ( size_t i = 0; i < volume.GetNumberOfPixels(); ++i, ++p )
00140 {
00141 #if defined(_MSC_VER) || defined(__SUNPRO_CC)
00142 *p = static_cast<DistanceDataType>( sqrt( (double)*p ) );
00143 #else
00144 *p = static_cast<DistanceDataType>( sqrt( *p ) );
00145 #endif
00146 }
00147 this->m_DistanceMap->SetData( distanceArray );
00148 }
00149
00150 template<class TDistanceDataType>
00151 void
00152 UniformDistanceMap<TDistanceDataType>
00153 ::ComputeEDT( DistanceDataType *const distance )
00154 {
00155 ThreadPool& threadPool = ThreadPool::GetGlobalThreadPool();
00156 const size_t numberOfThreads = threadPool.GetNumberOfThreads();
00157 const size_t numberOfTasks = 4 * numberOfThreads - 3;
00158
00159 this->m_G.resize( numberOfThreads );
00160 this->m_H.resize( numberOfThreads );
00161
00162 std::vector<typename Self::ThreadParametersEDT> params( numberOfTasks );
00163 for ( size_t idx = 0; idx < numberOfTasks; ++idx )
00164 {
00165 params[idx].thisObject = this;
00166 params[idx].m_Distance = distance;
00167 }
00168
00169 threadPool.Run( ComputeEDTThreadPhase1, params );
00170 threadPool.Run( ComputeEDTThreadPhase2, params );
00171 }
00172
00173 template<class TDistanceDataType>
00174 void
00175 UniformDistanceMap<TDistanceDataType>
00176 ::ComputeEDTThreadPhase1
00177 ( void *const args, const size_t taskIdx, const size_t taskCnt, const size_t threadIdx, const size_t )
00178 {
00179 ThreadParametersEDT* params = static_cast<ThreadParametersEDT*>( args );
00180 Self* This = params->thisObject;
00181 const Self* ThisConst = This;
00182
00183
00184
00185 const size_t nXY = ThisConst->m_DistanceMap->m_Dims[0] * ThisConst->m_DistanceMap->m_Dims[1];
00186
00187
00188
00189 DistanceDataType *p = params->m_Distance + nXY * taskIdx;
00190 for ( int k = taskIdx; k < ThisConst->m_DistanceMap->m_Dims[2]; k += taskCnt, p += nXY * taskCnt )
00191 {
00192 This->ComputeEDT2D( p, This->m_G[threadIdx], This->m_H[threadIdx] );
00193 }
00194 }
00195
00196 template<class TDistanceDataType>
00197 void
00198 UniformDistanceMap<TDistanceDataType>
00199 ::ComputeEDTThreadPhase2
00200 ( void *const args, const size_t taskIdx, const size_t taskCnt, const size_t threadIdx, const size_t )
00201 {
00202 ThreadParametersEDT* params = static_cast<ThreadParametersEDT*>( args );
00203 Self* This = params->thisObject;
00204 const Self* ThisConst = This;
00205
00206 const size_t nXY = ThisConst->m_DistanceMap->m_Dims[0] * ThisConst->m_DistanceMap->m_Dims[1];
00207
00208
00209 std::vector<DistanceDataType> f( This->m_DistanceMap->m_Dims[2] );
00210
00211 for ( size_t i = taskIdx; i < nXY; i += taskCnt )
00212 {
00213
00214
00215 DistanceDataType *p = params->m_Distance + i;
00216 DistanceDataType *q = &f[0];
00217 for ( int k = 0; k < ThisConst->m_DistanceMap->m_Dims[2]; k++, p += nXY, q++)
00218 {
00219 *q = *p;
00220 }
00221
00222
00223 if ( This->VoronoiEDT( &f[0], ThisConst->m_DistanceMap->m_Dims[2], static_cast<DistanceDataType>( ThisConst->m_DistanceMap->m_Delta[2] ), This->m_G[threadIdx], This->m_H[threadIdx] ) )
00224 {
00225 p = params->m_Distance + i;
00226 DistanceDataType *q = &f[0];
00227 for ( int k = 0; k < ThisConst->m_DistanceMap->m_Dims[2]; k++, p += nXY, q++ )
00228 {
00229 *p = *q;
00230 }
00231 }
00232 }
00233 }
00234
00235 template<class TDistanceDataType>
00236 void
00237 UniformDistanceMap<TDistanceDataType>
00238 ::ComputeEDT2D
00239 ( DistanceDataType *const plane, std::vector<DistanceDataType>& gTemp, std::vector<DistanceDataType>& hTemp )
00240
00241
00242
00243
00244
00245
00246
00247 {
00248
00249
00250
00251
00252
00253 DistanceDataType *p;
00254 for ( int j = 0; j < this->m_DistanceMap->m_Dims[1]; j++ )
00255 {
00256
00257 p = plane + j * this->m_DistanceMap->m_Dims[0];
00258 DistanceDataType d = static_cast<DistanceDataType>( EDT_MAX_DISTANCE_SQUARED );
00259 for ( int i = 0; i < this->m_DistanceMap->m_Dims[0]; i++, p++ )
00260 {
00261
00262 if ( *p )
00263 {
00264 *p = d = 0;
00265 }
00266
00267 else
00268 if ( d != EDT_MAX_DISTANCE_SQUARED )
00269 {
00270 *p = ++d;
00271 }
00272
00273 else
00274 {
00275 *p = static_cast<DistanceDataType>( EDT_MAX_DISTANCE_SQUARED );
00276 }
00277 }
00278
00279
00280 if ( *(--p) != EDT_MAX_DISTANCE_SQUARED )
00281 {
00282 DistanceDataType d = static_cast<DistanceDataType>( EDT_MAX_DISTANCE_SQUARED );
00283 for ( int i = this->m_DistanceMap->m_Dims[0] - 1; i >= 0; i--, p-- )
00284 {
00285
00286 if ( *p == 0 )
00287 {
00288 d = 0;
00289 }
00290
00291 else
00292 if ( d != EDT_MAX_DISTANCE_SQUARED )
00293 {
00294
00295 if ( ++d < *p )
00296 {
00297 *p = d;
00298 }
00299 }
00300
00301
00302
00303 *p = static_cast<DistanceDataType>( *p * this->m_DistanceMap->m_Delta[0] );
00304 *p *= *p;
00305 }
00306 }
00307 }
00308
00309
00310
00311 std::vector<DistanceDataType> f( this->m_DistanceMap->m_Dims[1] );
00312 for ( int i = 0; i < this->m_DistanceMap->m_Dims[0]; i++ )
00313 {
00314
00315
00316 DistanceDataType *p = plane + i;
00317 DistanceDataType *q = &f[0];
00318 for ( int j = 0; j < this->m_DistanceMap->m_Dims[1]; j++, p += this->m_DistanceMap->m_Dims[0], q++)
00319 {
00320 *q = *p;
00321 }
00322
00323
00324 if ( this->VoronoiEDT( &f[0], this->m_DistanceMap->m_Dims[1], static_cast<DistanceDataType>( this->m_DistanceMap->m_Delta[1] ), gTemp, hTemp ) )
00325 {
00326 DistanceDataType *p = plane + i;
00327 DistanceDataType *q = &f[0];
00328 for ( int j = 0; j < this->m_DistanceMap->m_Dims[1]; j++, p += this->m_DistanceMap->m_Dims[0], q++ )
00329 {
00330 *p = *q;
00331 }
00332 }
00333 }
00334
00335 }
00336
00337 template<class TDistanceDataType>
00338 bool
00339 UniformDistanceMap<TDistanceDataType>
00340 ::VoronoiEDT
00341 ( DistanceDataType *const distanceSoFar, const int nSize, const DistanceDataType delta,
00342 std::vector<DistanceDataType>& gTemp, std::vector<DistanceDataType>& hTemp )
00343 {
00344 long i, l, n_S;
00345 DistanceDataType a, b, c, v, lhs, rhs;
00346
00347
00348
00349 gTemp.resize( nSize );
00350 hTemp.resize( nSize );
00351
00352 DistanceDataType* g = &(gTemp[0]);
00353 DistanceDataType* h = &(hTemp[0]);
00354
00355
00356
00357
00358 DistanceDataType deltai = 0;
00359 for (i = 0, l = -1; i < nSize; i++, deltai += delta)
00360 {
00361
00362 if ( distanceSoFar[i] != EDT_MAX_DISTANCE_SQUARED )
00363 {
00364
00365 if ( l < 1 )
00366 {
00367
00368 g[++l] = distanceSoFar[i];
00369 h[l] = deltai;
00370 }
00371
00372 else
00373 {
00374
00375 while (l >= 1)
00376 {
00377
00378 v = h[l];
00379 a = v - h[l-1];
00380 b = deltai - v;
00381 c = a + b;
00382
00383 if ((c*g[l] - b*g[l-1] - a*distanceSoFar[i] - a*b*c) > 0)
00384 {
00385
00386 l--;
00387 }
00388 else
00389 {
00390 break;
00391 }
00392 }
00393
00394 g[++l] = distanceSoFar[i];
00395 h[l] = deltai;
00396 }
00397 }
00398 }
00399
00400
00401
00402 if ((n_S = l + 1) == 0)
00403 {
00404 return false;
00405 }
00406
00407
00408 deltai = 0;
00409 for (i = 0, l = 0; i < nSize; i++, deltai += delta)
00410 {
00411
00412
00413
00414
00415 a = h[l] - deltai;
00416 lhs = g[l] + a * a;
00417 while (l < n_S - 1)
00418 {
00419 a = h[l+1] - deltai;
00420 rhs = g[l+1] + a * a;
00421 if (lhs > rhs)
00422 {
00423
00424 l++;
00425 lhs = rhs;
00426 }
00427 else
00428 {
00429 break;
00430 }
00431 }
00432
00433
00434
00435
00436 distanceSoFar[i] = lhs;
00437 }
00438
00439
00440
00441 return true;
00442 }
00443
00445
00446 }
00447
00448 template class cmtk::UniformDistanceMap<float>;
00449 template class cmtk::UniformDistanceMap<double>;
00450 template class cmtk::UniformDistanceMap<long int>;