1 #ifndef __clitkInvertVFFilter_txx
2 #define __clitkInvertVFFilter_txx
6 //=========================================================================================================================
7 //helper class 1 to allow a threaded execution: add contributions of input to output and update weights
8 //=========================================================================================================================
9 template<class InputImageType, class OutputImageType> class ITK_EXPORT HelperClass1 : public itk::ImageToImageFilter<InputImageType, OutputImageType>
13 /** Standard class typedefs. */
14 typedef HelperClass1 Self;
15 typedef itk::ImageToImageFilter<InputImageType,OutputImageType> Superclass;
16 typedef itk::SmartPointer<Self> Pointer;
17 typedef itk::SmartPointer<const Self> ConstPointer;
19 /** Method for creation through the object factory. */
22 /** Run-time type information (and related methods) */
23 itkTypeMacro( HelperClass1, ImageToImageFilter );
25 /** Constants for the image dimensions */
26 itkStaticConstMacro(ImageDimension, unsigned int,InputImageType::ImageDimension);
30 typedef typename OutputImageType::PixelType PixelType;
31 typedef itk::Image<double, ImageDimension > WeightsImageType;
32 typedef itk::Image<itk::SimpleFastMutexLock, ImageDimension > MutexImageType;
34 //===================================================================================
36 void SetWeights(const typename WeightsImageType::Pointer input)
41 void SetMutexImage(const typename MutexImageType::Pointer input)
49 typename WeightsImageType::Pointer GetWeights(){return m_Weights;}
51 /** Typedef to describe the output image region type. */
52 typedef typename OutputImageType::RegionType OutputImageRegionType;
58 //the actual processing
59 void BeforeThreadedGenerateData();
60 void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId );
63 typename WeightsImageType::Pointer m_Weights;
64 typename MutexImageType::Pointer m_MutexImage;
71 //=========================================================================================================================
72 //Member functions of the helper class 1
73 //=========================================================================================================================
76 //=========================================================================================================================
78 template<class InputImageType, class OutputImageType >
79 HelperClass1<InputImageType, OutputImageType>::HelperClass1()
84 //=========================================================================================================================
85 //Before threaded data
86 template<class InputImageType, class OutputImageType >
87 void HelperClass1<InputImageType, OutputImageType>::BeforeThreadedGenerateData()
89 //Since we will add, put to zero!
90 this->GetOutput()->FillBuffer(itk::NumericTraits<double>::Zero);
91 this->GetWeights()->FillBuffer(itk::NumericTraits<double>::Zero);
94 //=========================================================================================================================
95 //update the output for the outputRegionForThread
96 template<class InputImageType, class OutputImageType>
97 void HelperClass1<InputImageType, OutputImageType>::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId )
100 //Get pointer to the input
101 typename InputImageType::ConstPointer inputPtr = this->GetInput();
103 //Get pointer to the output
104 typename OutputImageType::Pointer outputPtr = this->GetOutput();
105 typename OutputImageType::SizeType size=outputPtr->GetLargestPossibleRegion().GetSize();
107 //Iterator over input
108 typedef itk::ImageRegionConstIteratorWithIndex<InputImageType> InputImageIteratorType;
110 //define them over the outputRegionForThread
111 InputImageIteratorType inputIt(inputPtr, outputRegionForThread);
114 typename InputImageType::IndexType index;
115 itk::ContinuousIndex<double,ImageDimension> contIndex;
116 typename InputImageType::PointType ipoint;
117 typename OutputImageType::PointType opoint;
118 typedef typename OutputImageType::PixelType DisplacementType;
119 DisplacementType displacement;
122 //define some temp variables
123 signed long baseIndex[ImageDimension];
124 double distance[ImageDimension];
125 unsigned int dim, counter, upper;
126 double totalOverlap,overlap;
127 typename OutputImageType::IndexType neighIndex;
129 //Find the number of neighbors
130 unsigned int neighbors = 1 << ImageDimension;
132 //==================================================================================================
133 //Loop over the region and add the intensities to the output and the weight to the weights
134 //==================================================================================================
135 while( !inputIt.IsAtEnd() )
137 // get the input image index
138 index = inputIt.GetIndex();
139 inputPtr->TransformIndexToPhysicalPoint( index,ipoint );
141 // get the required displacement
142 displacement = inputIt.Get();
144 // compute the required output image point
145 for(unsigned int j = 0; j < ImageDimension; j++ ) opoint[j] = ipoint[j] + (double)displacement[j];
147 // Update the output and the weights
148 if(outputPtr->TransformPhysicalPointToContinuousIndex(opoint, contIndex ) )
150 for(dim = 0; dim < ImageDimension; dim++)
152 // The following block is equivalent to the following line without
153 // having to call floor. (Only for positive inputs, we already now that is in the image)
154 // baseIndex[dim] = (long) vcl_floor(contIndex[dim] );
156 baseIndex[dim] = (long) contIndex[dim];
157 distance[dim] = contIndex[dim] - double( baseIndex[dim] );
160 //Add contribution for each neighbor
161 totalOverlap = itk::NumericTraits<double>::Zero;
162 for( counter = 0; counter < neighbors ; counter++ )
164 overlap = 1.0; // fraction overlap
165 upper = counter; // each bit indicates upper/lower neighbour
167 // get neighbor index and overlap fraction
168 for( dim = 0; dim < 3; dim++ )
172 neighIndex[dim] = baseIndex[dim] + 1;
173 overlap *= distance[dim];
177 neighIndex[dim] = baseIndex[dim];
178 overlap *= 1.0 - distance[dim];
185 //Set neighbor value only if overlap is not zero
186 if( (overlap>0.0)) // &&
187 // (static_cast<unsigned int>(neighIndex[0])<size[0]) &&
188 // (static_cast<unsigned int>(neighIndex[1])<size[1]) &&
189 // (static_cast<unsigned int>(neighIndex[2])<size[2]) &&
190 // (neighIndex[0]>=0) &&
191 // (neighIndex[1]>=0) &&
192 // (neighIndex[2]>=0) )
194 //what to store? the original displacement vector?
197 //Set the pixel and weight at neighIndex
198 outputPtr->SetPixel(neighIndex, outputPtr->GetPixel(neighIndex) - (displacement*overlap));
199 m_Weights->SetPixel(neighIndex, m_Weights->GetPixel(neighIndex) + overlap);
204 //Entering critilal section: shared memory
205 m_MutexImage->GetPixel(neighIndex).Lock();
207 //Set the pixel and weight at neighIndex
208 outputPtr->SetPixel(neighIndex, outputPtr->GetPixel(neighIndex) - (displacement*overlap));
209 m_Weights->SetPixel(neighIndex, m_Weights->GetPixel(neighIndex) + overlap);
212 m_MutexImage->GetPixel(neighIndex).Unlock();
215 //Add to total overlap
216 totalOverlap += overlap;
219 if( totalOverlap == 1.0 )
234 //=========================================================================================================================
235 //helper class 2 to allow a threaded execution of normalisation by the weights
236 //=========================================================================================================================
237 template<class InputImageType, class OutputImageType> class HelperClass2 : public itk::ImageToImageFilter<InputImageType, OutputImageType>
241 /** Standard class typedefs. */
242 typedef HelperClass2 Self;
243 typedef itk::ImageToImageFilter<InputImageType,OutputImageType> Superclass;
244 typedef itk::SmartPointer<Self> Pointer;
245 typedef itk::SmartPointer<const Self> ConstPointer;
247 /** Method for creation through the object factory. */
250 /** Run-time type information (and related methods) */
251 itkTypeMacro( HelperClass2, ImageToImageFilter );
253 /** Constants for the image dimensions */
254 itkStaticConstMacro(ImageDimension, unsigned int,InputImageType::ImageDimension);
257 typedef typename OutputImageType::PixelType PixelType;
258 typedef itk::Image<double,ImageDimension> WeightsImageType;
261 void SetWeights(const typename WeightsImageType::Pointer input)
266 void SetEdgePaddingValue(PixelType value)
268 m_EdgePaddingValue = value;
272 /** Typedef to describe the output image region type. */
273 typedef typename OutputImageType::RegionType OutputImageRegionType;
280 //the actual processing
281 void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId );
285 typename WeightsImageType::Pointer m_Weights;
286 PixelType m_EdgePaddingValue;
292 //=========================================================================================================================
293 //Member functions of the helper class 2
294 //=========================================================================================================================
297 //=========================================================================================================================
299 template<class InputImageType, class OutputImageType > HelperClass2<InputImageType, OutputImageType>::HelperClass2()
301 m_EdgePaddingValue=itk::NumericTraits<PixelType>::Zero;
305 //=========================================================================================================================
306 //update the output for the outputRegionForThread
307 template<class InputImageType, class OutputImageType > void HelperClass2<InputImageType, OutputImageType>::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId )
310 //Get pointer to the input
311 typename InputImageType::ConstPointer inputPtr = this->GetInput();
313 //Get pointer to the output
314 typename OutputImageType::Pointer outputPtr = this->GetOutput();
316 //Iterators over input, weigths and output
317 typedef itk::ImageRegionConstIterator<InputImageType> InputImageIteratorType;
318 typedef itk::ImageRegionIterator<OutputImageType> OutputImageIteratorType;
319 typedef itk::ImageRegionIterator<WeightsImageType> WeightsImageIteratorType;
321 //define them over the outputRegionForThread
322 OutputImageIteratorType outputIt(outputPtr, outputRegionForThread);
323 InputImageIteratorType inputIt(inputPtr, outputRegionForThread);
324 WeightsImageIteratorType weightsIt(m_Weights, outputRegionForThread);
327 //==================================================================================================
328 //loop over the output and normalize the input, remove holes
329 PixelType neighValue;
330 double zero = itk::NumericTraits<double>::Zero;
331 while (!outputIt.IsAtEnd())
333 //the weight is not zero
334 if (weightsIt.Get() != zero)
336 //divide by the weight
337 outputIt.Set(static_cast<PixelType>(inputIt.Get()/weightsIt.Get()));
340 //copy the value of the neighbour that was just processed
343 if(!outputIt.IsAtBegin())
348 //Neighbour cannot have zero weight because it should be filled already
349 neighValue=outputIt.Get();
351 outputIt.Set(neighValue);
355 //DD("is at begin, setting edgepadding value");
356 outputIt.Set(m_EdgePaddingValue);
367 }//end nameless namespace
374 //=========================================================================================================================
375 // The rest is the InvertVFFilter
376 //=========================================================================================================================
378 //=========================================================================================================================
380 template <class InputImageType, class OutputImageType>
381 InvertVFFilter<InputImageType, OutputImageType>::InvertVFFilter()
383 m_EdgePaddingValue=itk::NumericTraits<PixelType>::Zero; //no other reasonable value?
389 //=========================================================================================================================
391 template <class InputImageType, class OutputImageType> void InvertVFFilter<InputImageType, OutputImageType>::GenerateData()
394 //Get the properties of the input
395 typename InputImageType::ConstPointer inputPtr=this->GetInput();
396 typename WeightsImageType::RegionType region;
397 typename WeightsImageType::RegionType::SizeType size=inputPtr->GetLargestPossibleRegion().GetSize();
398 region.SetSize(size);
399 typename OutputImageType::IndexType start;
400 for (unsigned int i=0; i< ImageDimension; i++) start[i]=0;
401 region.SetIndex(start);
402 PixelType zero = itk::NumericTraits<double>::Zero;
405 //Allocate the weights
406 typename WeightsImageType::Pointer weights=WeightsImageType::New();
407 weights->SetRegions(region);
409 weights->SetSpacing(inputPtr->GetSpacing());
411 //===========================================================================
412 //Inversion is divided in in two loops, for each we will call a threaded helper class
413 //1. add contribution of input to output and update weights
414 //2. normalize the output by the weight and remove holes
415 //===========================================================================
418 //===========================================================================
419 //1. add contribution of input to output and update weights
421 //Define an internal image type
423 typedef itk::Image<itk::Vector<double,ImageDimension>, ImageDimension > InternalImageType;
425 //Call threaded helper class 1
426 typedef HelperClass1<InputImageType, InternalImageType > HelperClass1Type;
427 typename HelperClass1Type::Pointer helper1=HelperClass1Type::New();
430 if(m_NumberOfThreadsIsGiven)helper1->SetNumberOfThreads(m_NumberOfThreads);
431 helper1->SetInput(inputPtr);
432 helper1->SetWeights(weights);
437 //Allocate the mutex image
438 typename MutexImageType::Pointer mutex=InvertVFFilter::MutexImageType::New();
439 mutex->SetRegions(region);
441 mutex->SetSpacing(inputPtr->GetSpacing());
442 helper1->SetMutexImage(mutex);
443 if (m_Verbose) std::cout <<"Inverting using a thread-safe algorithm" <<std::endl;
445 else if(m_Verbose)std::cout <<"Inverting using a thread-unsafe algorithm" <<std::endl;
447 //Execute helper class
451 typename InternalImageType::Pointer temp= helper1->GetOutput();
452 weights=helper1->GetWeights();
455 //===========================================================================
456 //2. Normalize the output by the weights and remove holes
457 //Call threaded helper class
458 typedef HelperClass2<InternalImageType, OutputImageType> HelperClass2Type;
459 typename HelperClass2Type::Pointer helper2=HelperClass2Type::New();
461 //Set temporary output as input
462 helper2->SetInput(temp);
463 helper2->SetWeights(weights);
464 helper2->SetEdgePaddingValue(m_EdgePaddingValue);
466 //Execute helper class
467 if (m_Verbose) std::cout << "Normalizing the output VF..."<<std::endl;
471 this->SetNthOutput(0, helper2->GetOutput());