1 /*============================================================================
3 The Medical Imaging Interaction Toolkit (MITK)
5 Copyright (c) German Cancer Research Center (DKFZ)
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
11 ============================================================================*/
12 #ifndef _itkAdaptiveThresholdIterator_txx
13 #define _itkAdaptiveThresholdIterator_txx
15 #include "itkAdaptiveThresholdIterator.h"
16 #include "mitkProgressBar.h"
21 template <class TImage, class TFunction>
22 AdaptiveThresholdIterator<TImage, TFunction>::AdaptiveThresholdIterator(ImageType *imagePtr,
25 : m_FineDetectionMode(false), m_DetectionStop(false)
27 this->m_OutputImage = imagePtr;
29 m_StartIndices.push_back(startIndex);
31 // Set up the temporary image
32 this->InitializeIterator();
35 template <class TImage, class TFunction>
36 AdaptiveThresholdIterator<TImage, TFunction>::AdaptiveThresholdIterator(ImageType *imagePtr,
38 std::vector<IndexType> &startIndex)
39 : m_FineDetectionMode(false), m_DetectionStop(false)
41 this->m_OutputImage = imagePtr;
44 for (i = 0; i < startIndex.size(); i++)
46 m_StartIndices.push_back(startIndex[i]);
49 // Set up the temporary image
50 this->InitializeIterator();
53 template <class TImage, class TFunction>
54 AdaptiveThresholdIterator<TImage, TFunction>::AdaptiveThresholdIterator(ImageType *imagePtr, FunctionType *fnPtr)
55 : m_FineDetectionMode(false), m_DetectionStop(false)
57 this->m_OutputImage = imagePtr; // here we store the image, we have to wite the result to
60 // Set up the temporary image
61 this->InitializeIterator();
64 template <class TImage, class TFunction>
65 void AdaptiveThresholdIterator<TImage, TFunction>::InitializeIterator()
67 // Get the origin and spacing from the image in simple arrays
68 m_ImageOrigin = this->m_OutputImage->GetOrigin();
69 m_ImageSpacing = this->m_OutputImage->GetSpacing();
70 m_ImageRegion = this->m_OutputImage->GetBufferedRegion();
72 this->InitRegionGrowingState();
75 m_LastVoxelNumber = 0;
76 m_CurrentLeakageRatio = 0;
77 m_DetectedLeakagePoint = 0;
80 template <class TImage, class TFunction>
81 void AdaptiveThresholdIterator<TImage, TFunction>::SetExpansionDirection(bool upwards)
83 m_UpwardsExpansion = upwards;
86 template <class TImage, class TFunction>
87 void AdaptiveThresholdIterator<TImage, TFunction>::IncrementRegionGrowingState()
89 // make the progressbar go one step further
90 if (!m_FineDetectionMode)
91 mitk::ProgressBar::GetInstance()->Progress();
93 // updating the thresholds
94 if (m_UpwardsExpansion)
96 this->ExpandThresholdUpwards();
100 this->ExpandThresholdDownwards();
104 int criticalValue = 2000; // calculate a bit more "intelligent"
106 if (!m_FineDetectionMode)
108 int diff = m_VoxelCounter - m_LastVoxelNumber;
109 if (diff > m_CurrentLeakageRatio)
111 m_CurrentLeakageRatio = diff;
112 m_DetectedLeakagePoint = m_RegionGrowingState;
114 m_LastVoxelNumber = m_VoxelCounter;
117 else // fine leakage detection
119 // counting voxels over interations; if above a critical value (to be extended) then set this to leakage
120 int diff = m_VoxelCounter - m_LastVoxelNumber;
121 // std::cout<<"diff is: "<<diff<<"\n";
122 if (diff <= criticalValue && (!m_DetectionStop))
124 // m_CurrentLeakageRatio = diff;
125 m_DetectedLeakagePoint = m_RegionGrowingState + 1; // TODO check why this is needed
126 // std::cout<<"setting CurrentLeakageRatio to: "<<diff<<" and leakagePoint to: "<<m_DetectedLeakagePoint<<"\n";
130 m_DetectionStop = true;
131 // std::cout<<"\n\n[ITERATOR] detection stop!!!\n";
133 m_LastVoxelNumber = m_VoxelCounter;
136 // increment the counter
137 m_RegionGrowingState++;
140 template <class TImage, class TFunction>
141 void AdaptiveThresholdIterator<TImage, TFunction>::ExpandThresholdUpwards()
143 int upper = (int)m_Function->GetUpper();
145 m_Function->ThresholdBetween(m_MinTH, upper);
148 template <class TImage, class TFunction>
149 void AdaptiveThresholdIterator<TImage, TFunction>::ExpandThresholdDownwards()
151 int lower = (int)m_Function->GetLower();
153 m_Function->ThresholdBetween(lower, m_MaxTH);
156 template <class TImage, class TFunction>
157 void AdaptiveThresholdIterator<TImage, TFunction>::InitRegionGrowingState()
159 this->m_RegionGrowingState = 1;
162 template <class TImage, class TFunction>
163 int AdaptiveThresholdIterator<TImage, TFunction>::EstimateDistance(IndexType tempIndex)
165 PixelType value = this->m_Function->GetInputImage()->GetPixel(tempIndex);
166 PixelType minPixel = PixelType(m_MinTH);
167 PixelType maxPixel = PixelType(m_MaxTH);
169 if (value > maxPixel || value < minPixel)
173 if (m_UpwardsExpansion)
175 return (int)(value - m_SeedPointValue);
179 return (int)(m_SeedPointValue - value);
183 template <class TImage, class TFunction>
184 void AdaptiveThresholdIterator<TImage, TFunction>::SetMinTH(int min)
189 template <class TImage, class TFunction>
190 void AdaptiveThresholdIterator<TImage, TFunction>::SetMaxTH(int max)
195 template <class TImage, class TFunction>
196 int AdaptiveThresholdIterator<TImage, TFunction>::GetSeedPointValue()
198 return this->m_SeedPointValue;
201 template <class TImage, class TFunction>
202 void AdaptiveThresholdIterator<TImage, TFunction>::GoToBegin()
206 m_SeedPointValue = 0;
208 IndexType seedIndex = m_StartIndices[0];
210 bool doAverage = false; // enable or disable manually!
213 // loops for creating the sum of the N27-neighborhood around the seedpoint
214 for (int i = -1; i <= 1; i++)
216 for (int j = -1; j <= 1; j++)
218 for (int k = -1; k <= 1; k++)
220 seedIndex[0] = seedIndex[0] + i;
221 seedIndex[1] = seedIndex[1] + j;
222 seedIndex[2] = seedIndex[2] + k;
224 m_SeedPointValue += (int)m_Function->GetInputImage()->GetPixel(seedIndex);
229 // value of seedpoint computed from mean of N27-neighborhood
230 m_SeedPointValue = m_SeedPointValue / 27;
234 m_SeedPointValue = (int)m_Function->GetInputImage()->GetPixel(seedIndex);
237 this->CheckSeedPointValue();
239 m_InitializeValue = (this->CalculateMaxRGS() + 1);
240 if (!m_FineDetectionMode)
241 mitk::ProgressBar::GetInstance()->AddStepsToDo(m_InitializeValue - 1);
243 // only initialize with zeros for the first segmention (raw segmentation mode)
244 if (!m_FineDetectionMode)
246 this->m_OutputImage->FillBuffer((PixelType)0);
248 if (m_UpwardsExpansion)
250 m_Function->ThresholdBetween(m_MinTH, m_SeedPointValue);
254 m_Function->ThresholdBetween(m_SeedPointValue, m_MaxTH);
257 this->m_IsAtEnd = true;
259 seedIndex = m_StartIndices[0]; // warum noch mal? Steht doch schon in Zeile 224
261 if (this->m_OutputImage->GetBufferedRegion().IsInside(seedIndex) && this->m_SeedPointValue > this->m_MinTH &&
262 this->m_SeedPointValue < this->m_MaxTH)
264 // Push the seed onto the queue
265 this->InsertIndexTypeIntoQueueMap(m_RegionGrowingState, seedIndex);
267 // Obviously, we're at the beginning
268 this->m_IsAtEnd = false;
270 this->m_OutputImage->SetPixel(seedIndex, (m_InitializeValue - m_RegionGrowingState));
274 template <class TImage, class TFunction>
275 void AdaptiveThresholdIterator<TImage, TFunction>::CheckSeedPointValue()
277 // checks, if the value, that has been averaged over the N-27 neighborhood aorund the seedpoint is still inside
278 // the thresholds-ranges. if not, the actual value of the seedpoint (not averaged) is used
279 if (m_SeedPointValue < m_MinTH || m_SeedPointValue > m_MaxTH)
281 m_SeedPointValue = (int)m_Function->GetInputImage()->GetPixel(m_StartIndices[0]);
285 template <class TImage, class TFunction>
286 unsigned int AdaptiveThresholdIterator<TImage, TFunction>::CalculateMaxRGS()
288 if (m_UpwardsExpansion)
290 return (m_MaxTH - m_SeedPointValue);
294 return (m_SeedPointValue - m_MinTH);
298 template <class TImage, class TFunction>
299 bool AdaptiveThresholdIterator<TImage, TFunction>::IsPixelIncluded(const IndexType &index) const
301 // checks, if grayvalue of current voxel is inside the currently used thresholds
302 return this->m_Function->EvaluateAtIndex(index);
305 template <class TImage, class TFunction>
306 void AdaptiveThresholdIterator<TImage, TFunction>::InsertIndexTypeIntoQueueMap(unsigned int key, IndexType index)
308 // first check if the key-specific queue already exists
309 if (m_QueueMap.count(key) == 0)
311 // if queue doesn´t exist, create it, push the IndexType onto it
312 // and insert it into the map
314 IndexQueueType newQueue;
315 newQueue.push(index);
317 typedef typename QueueMapType::value_type KeyIndexQueue;
319 m_QueueMap.insert(KeyIndexQueue(key, newQueue));
323 // if queue already exists in the map, push IndexType onto its specific queue
324 (*(m_QueueMap.find(key))).second.push(index);
328 template <class TImage, class TFunction>
329 void AdaptiveThresholdIterator<TImage, TFunction>::DoExtendedFloodStep()
331 // The index in the front of the queue should always be
332 // valid and be inside since this is what the iterator
333 // uses in the Set/Get methods. This is ensured by the
334 // GoToBegin() method.
336 typename QueueMapType::iterator currentIt = m_QueueMap.find(m_RegionGrowingState);
338 if (currentIt == m_QueueMap.end())
340 this->IncrementRegionGrowingState();
344 IndexQueueType *currentQueue = &(*currentIt).second;
346 // Take the index in the front of the queue
347 const IndexType &topIndex = currentQueue->front();
349 // Iterate through all possible dimensions
350 // NOTE: Replace this with a ShapeNeighborhoodIterator
351 for (unsigned int i = 0; i < NDimensions; i++)
353 // The j loop establishes either left or right neighbor (+-1)
354 for (int j = -1; j <= 1; j += 2)
358 // build the index of a neighbor
359 for (unsigned int k = 0; k < NDimensions; k++)
363 tempIndex.m_Index[k] = topIndex[k];
367 tempIndex.m_Index[k] = topIndex[k] + j;
369 } // end build the index of a neighbor
371 // If this is a valid index and have not been tested,
373 if (m_ImageRegion.IsInside(tempIndex))
375 // check if voxel hasn´t already been processed
376 if (this->m_OutputImage->GetPixel(tempIndex) == 0)
378 // if it is inside, push it into the queue
379 if (this->IsPixelIncluded(tempIndex))
381 // hier wird Voxel in momentan aktiven Stack und ins OutputImage geschrieben
382 this->InsertIndexTypeIntoQueueMap((m_RegionGrowingState), tempIndex);
383 this->m_OutputImage->SetPixel(tempIndex, (m_InitializeValue - m_RegionGrowingState));
385 else // If the pixel is not inside the current threshold
387 int distance = this->EstimateDistance(
388 tempIndex); // [!] sollte nicht estimateDistance sondern calculateDistance() heißen!
391 // hier wird Voxel in entsprechenden Stack und ins OutputImage geschrieben
392 this->InsertIndexTypeIntoQueueMap((distance), tempIndex);
393 this->m_OutputImage->SetPixel(tempIndex, (m_InitializeValue - distance));
398 } // end left/right neighbor loop
399 } // end check all neighbors
401 // Now that all the potential neighbors have been
402 // inserted we can get rid of the pixel in the front
406 if (currentQueue->empty())
408 // if currently used queue is empty
409 this->IncrementRegionGrowingState();
412 if (m_RegionGrowingState >= (m_InitializeValue) || m_DetectionStop)
414 this->m_IsAtEnd = true;
415 // std::cout << "RegionGrowing finished !" << std::endl;
416 // std::cout << "Detected point of leakage: " << m_DetectedLeakagePoint << std::endl;
420 } // end namespace itk