1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://www.centreleonberard.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
18 #ifndef __clitkForwardWarpImageFilter_txx
19 #define __clitkForwardWarpImageFilter_txx
20 #include "clitkForwardWarpImageFilter.h"
21 #include "clitkImageCommon.h"
23 // Put the helper classes in an anonymous namespace so that it is not
24 // exposed to the user
30 //=========================================================================================================================
31 //helper class 1 to allow a threaded execution: add contributions of input to output and update weights
32 //=========================================================================================================================
33 template<class InputImageType, class OutputImageType, class DeformationFieldType> class HelperClass1 : public itk::ImageToImageFilter<InputImageType, OutputImageType>
37 /** Standard class typedefs. */
38 typedef HelperClass1 Self;
39 typedef itk::ImageToImageFilter<InputImageType,OutputImageType> Superclass;
40 typedef itk::SmartPointer<Self> Pointer;
41 typedef itk::SmartPointer<const Self> ConstPointer;
43 /** Method for creation through the object factory. */
46 /** Run-time type information (and related methods) */
47 itkTypeMacro( HelperClass1, ImageToImageFilter );
49 /** Constants for the image dimensions */
50 itkStaticConstMacro(ImageDimension, unsigned int,InputImageType::ImageDimension);
54 typedef typename OutputImageType::PixelType OutputPixelType;
55 typedef itk::Image<double, ImageDimension > WeightsImageType;
56 #if ITK_VERSION_MAJOR <= 4
57 typedef itk::Image<itk::SimpleFastMutexLock, ImageDimension> MutexImageType;
59 //===================================================================================
61 void SetWeights(const typename WeightsImageType::Pointer input) {
65 void SetDeformationField(const typename DeformationFieldType::Pointer input) {
66 m_DeformationField=input;
69 #if ITK_VERSION_MAJOR <= 4
70 void SetMutexImage(const typename MutexImageType::Pointer input) {
76 void SetMutexImage() {
83 typename WeightsImageType::Pointer GetWeights() {
87 /** Typedef to describe the output image region type. */
88 typedef typename OutputImageType::RegionType OutputImageRegionType;
94 //the actual processing
95 void BeforeThreadedGenerateData();
96 void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId );
99 typename itk::Image< double, ImageDimension>::Pointer m_Weights;
100 typename DeformationFieldType::Pointer m_DeformationField;
101 #if ITK_VERSION_MAJOR <= 4
102 typename MutexImageType::Pointer m_MutexImage;
112 //=========================================================================================================================
113 //Member functions of the helper class 1
114 //=========================================================================================================================
117 //=========================================================================================================================
119 template<class InputImageType, class OutputImageType, class DeformationFieldType >
120 HelperClass1<InputImageType, OutputImageType, DeformationFieldType>::HelperClass1()
126 //=========================================================================================================================
127 //Before threaded data
128 template<class InputImageType, class OutputImageType, class DeformationFieldType >
129 void HelperClass1<InputImageType, OutputImageType, DeformationFieldType>::BeforeThreadedGenerateData()
131 //Since we will add, put to zero!
132 this->GetOutput()->FillBuffer(itk::NumericTraits<double>::Zero);
133 this->GetWeights()->FillBuffer(itk::NumericTraits<double>::Zero);
137 //=========================================================================================================================
138 //update the output for the outputRegionForThread
139 template<class InputImageType, class OutputImageType, class DeformationFieldType >
140 void HelperClass1<InputImageType, OutputImageType, DeformationFieldType>::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId )
143 //Get pointer to the input
144 typename InputImageType::ConstPointer inputPtr = this->GetInput();
146 //Get pointer to the output
147 typename OutputImageType::Pointer outputPtr = this->GetOutput();
148 //typename OutputImageType::SizeType size=outputPtr->GetLargestPossibleRegion().GetSize();
150 //Iterators over input and deformation field
151 typedef itk::ImageRegionConstIteratorWithIndex<InputImageType> InputImageIteratorType;
152 typedef itk::ImageRegionIterator<DeformationFieldType> DeformationFieldIteratorType;
154 //define them over the outputRegionForThread
155 InputImageIteratorType inputIt(inputPtr, outputRegionForThread);
156 DeformationFieldIteratorType fieldIt(m_DeformationField,outputRegionForThread);
159 typename InputImageType::IndexType index;
160 itk::ContinuousIndex<double,ImageDimension> contIndex;
161 typename InputImageType::PointType point;
162 typedef typename DeformationFieldType::PixelType DisplacementType;
163 DisplacementType displacement;
167 //define some temp variables
168 signed long baseIndex[ImageDimension];
169 double distance[ImageDimension];
170 for(unsigned int i=0; i<ImageDimension; i++) distance[i] = 0.0; // to avoid warning
171 unsigned int dim, counter, upper;
172 double overlap, totalOverlap;
173 typename OutputImageType::IndexType neighIndex;
175 //Find the number of neighbors
176 unsigned int neighbors = 1 << ImageDimension;
179 //==================================================================================================
180 //Loop over the region and add the intensities to the output and the weight to the weights
181 //==================================================================================================
182 while( !inputIt.IsAtEnd() ) {
184 // get the input image index
185 index = inputIt.GetIndex();
186 inputPtr->TransformIndexToPhysicalPoint( index, point );
188 // get the required displacement
189 displacement = fieldIt.Get();
191 // compute the required output image point
192 for(unsigned int j = 0; j < ImageDimension; j++ ) point[j] += displacement[j];
195 // Update the output and the weights
196 if(outputPtr->TransformPhysicalPointToContinuousIndex(point, contIndex ) ) {
197 for(dim = 0; dim < ImageDimension; dim++) {
198 // The following block is equivalent to the following line without
199 // having to call floor. For positive inputs!!!
200 // baseIndex[dim] = (long) std::floor(contIndex[dim] );
201 baseIndex[dim] = (long) contIndex[dim];
202 distance[dim] = contIndex[dim] - double( baseIndex[dim] );
205 //Add contribution for each neighbor
206 totalOverlap = itk::NumericTraits<double>::Zero;
207 for( counter = 0; counter < neighbors ; counter++ ) {
208 overlap = 1.0; // fraction overlap
209 upper = counter; // each bit indicates upper/lower neighbour
211 // get neighbor index and overlap fraction
212 for( dim = 0; dim < ImageDimension; dim++ ) {
214 neighIndex[dim] = baseIndex[dim] + 1;
215 overlap *= distance[dim];
217 neighIndex[dim] = baseIndex[dim];
218 overlap *= 1.0 - distance[dim];
223 //Set neighbor value only if overlap is not zero
224 if( (overlap>0.0)) // &&
225 // (static_cast<unsigned int>(neighIndex[0])<size[0]) &&
226 // (static_cast<unsigned int>(neighIndex[1])<size[1]) &&
227 // (static_cast<unsigned int>(neighIndex[2])<size[2]) &&
228 // (neighIndex[0]>=0) &&
229 // (neighIndex[1]>=0) &&
230 // (neighIndex[2]>=0) )
233 if (! m_ThreadSafe) {
234 //Set the pixel and weight at neighIndex
235 outputPtr->SetPixel(neighIndex, outputPtr->GetPixel(neighIndex) + overlap * static_cast<OutputPixelType>(inputIt.Get()));
236 m_Weights->SetPixel(neighIndex, m_Weights->GetPixel(neighIndex) + overlap);
239 //Entering critilal section: shared memory
240 #if ITK_VERSION_MAJOR <= 4
241 m_MutexImage->GetPixel(neighIndex).Lock();
246 //Set the pixel and weight at neighIndex
247 outputPtr->SetPixel(neighIndex, outputPtr->GetPixel(neighIndex) + overlap * static_cast<OutputPixelType>(inputIt.Get()));
248 m_Weights->SetPixel(neighIndex, m_Weights->GetPixel(neighIndex) + overlap);
251 #if ITK_VERSION_MAJOR <= 4
252 m_MutexImage->GetPixel(neighIndex).Unlock();
258 //Add to total overlap
259 totalOverlap += overlap;
262 //check for totaloverlap: not very likely
263 if( totalOverlap == 1.0 ) {
279 //=========================================================================================================================
280 //helper class 2 to allow a threaded execution of normalisation by the weights
281 //=========================================================================================================================
282 template<class InputImageType, class OutputImageType>
283 class HelperClass2 : public itk::ImageToImageFilter<InputImageType, OutputImageType>
287 /** Standard class typedefs. */
288 typedef HelperClass2 Self;
289 typedef itk::ImageToImageFilter<InputImageType,OutputImageType> Superclass;
290 typedef itk::SmartPointer<Self> Pointer;
291 typedef itk::SmartPointer<const Self> ConstPointer;
293 /** Method for creation through the object factory. */
296 /** Run-time type information (and related methods) */
297 itkTypeMacro( HelperClass2, ImageToImageFilter );
299 /** Constants for the image dimensions */
300 itkStaticConstMacro(ImageDimension, unsigned int,InputImageType::ImageDimension);
303 typedef typename InputImageType::PixelType InputPixelType;
304 typedef typename OutputImageType::PixelType OutputPixelType;
305 typedef itk::Image<double, ImageDimension > WeightsImageType;
309 void SetWeights(const typename WeightsImageType::Pointer input) {
313 void SetEdgePaddingValue(OutputPixelType value) {
314 m_EdgePaddingValue = value;
318 /** Typedef to describe the output image region type. */
319 typedef typename OutputImageType::RegionType OutputImageRegionType;
326 //the actual processing
327 void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId );
331 typename WeightsImageType::Pointer m_Weights;
332 OutputPixelType m_EdgePaddingValue;
337 //=========================================================================================================================
338 //Member functions of the helper class 2
339 //=========================================================================================================================
342 //=========================================================================================================================
344 template<class InputImageType, class OutputImageType >
345 HelperClass2<InputImageType, OutputImageType>::HelperClass2()
347 m_EdgePaddingValue=static_cast<OutputPixelType>(0.0);
351 //=========================================================================================================================
352 //update the output for the outputRegionForThread
353 template<class InputImageType, class OutputImageType > void
354 HelperClass2<InputImageType, OutputImageType>::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, int threadId )
357 //Get pointer to the input
358 typename InputImageType::ConstPointer inputPtr = this->GetInput();
360 //Get pointer to the output
361 typename OutputImageType::Pointer outputPtr = this->GetOutput();
363 //Iterators over input, weigths and output
364 typedef itk::ImageRegionConstIterator<InputImageType> InputImageIteratorType;
365 typedef itk::ImageRegionIterator<OutputImageType> OutputImageIteratorType;
366 typedef itk::ImageRegionIterator<WeightsImageType> WeightsImageIteratorType;
368 //define them over the outputRegionForThread
369 OutputImageIteratorType outputIt(outputPtr, outputRegionForThread);
370 InputImageIteratorType inputIt(inputPtr, outputRegionForThread);
371 WeightsImageIteratorType weightsIt(m_Weights, outputRegionForThread);
374 //==================================================================================================
375 //loop over the output and normalize the input, remove holes
376 OutputPixelType neighValue;
377 double zero = itk::NumericTraits<double>::Zero;
378 while (!outputIt.IsAtEnd()) {
379 //the weight is not zero
380 if (weightsIt.Get() != zero) {
381 //divide by the weight
382 outputIt.Set(static_cast<OutputPixelType>(inputIt.Get()/weightsIt.Get()));
385 //copy the value of the neighbour that was just processed
387 if(!outputIt.IsAtBegin()) {
390 neighValue=outputIt.Get();
392 outputIt.Set(neighValue);
394 //DD("is at begin, setting edgepadding value");
395 outputIt.Set(m_EdgePaddingValue);
406 }//end nameless namespace
413 //=========================================================================================================================
414 // The rest is the ForwardWarpImageFilter
415 //=========================================================================================================================
417 //=========================================================================================================================
419 template <class InputImageType, class OutputImageType, class DeformationFieldType>
420 ForwardWarpImageFilter<InputImageType, OutputImageType, DeformationFieldType>::ForwardWarpImageFilter()
423 m_NumberOfThreadsIsGiven=false;
424 m_EdgePaddingValue=static_cast<PixelType>(0.0);
430 //=========================================================================================================================
432 template <class InputImageType, class OutputImageType, class DeformationFieldType>
433 void ForwardWarpImageFilter<InputImageType, OutputImageType, DeformationFieldType>::GenerateData()
436 //Get the properties of the input
437 typename InputImageType::ConstPointer inputPtr=this->GetInput();
438 typename WeightsImageType::RegionType region;
439 typename WeightsImageType::RegionType::SizeType size=inputPtr->GetLargestPossibleRegion().GetSize();
440 region.SetSize(size);
441 typename OutputImageType::IndexType start;
442 for (unsigned int i =0; i< ImageDimension ; i ++)start[i]=0;
443 region.SetIndex(start);
445 //Allocate the weights
446 typename WeightsImageType::Pointer weights=ForwardWarpImageFilter::WeightsImageType::New();
447 weights->SetRegions(region);
449 weights->SetSpacing(inputPtr->GetSpacing());
452 //===========================================================================
453 //warp is divided in in two loops, for each we call a threaded helper class
454 //1. Add contribution of input to output and update weights
455 //2. Normalize the output by the weight and remove holes
456 //===========================================================================
458 //===========================================================================
459 //1. Add contribution of input to output and update weights
461 //Define an internal image type in double precision
462 typedef itk::Image<double, ImageDimension> InternalImageType;
464 //Call threaded helper class 1
465 typedef HelperClass1<InputImageType, InternalImageType, DeformationFieldType> HelperClass1Type;
466 typename HelperClass1Type::Pointer helper1=HelperClass1Type::New();
469 if(m_NumberOfThreadsIsGiven) {
470 #if ITK_VERSION_MAJOR <= 4
471 helper1->SetNumberOfThreads(m_NumberOfThreads);
473 helper1->SetNumberOfWorkUnits(m_NumberOfWorkUnits);
476 helper1->SetInput(inputPtr);
477 helper1->SetDeformationField(m_DeformationField);
478 helper1->SetWeights(weights);
482 //Allocate the mutex image
483 #if ITK_VERSION_MAJOR <= 4
484 typename MutexImageType::Pointer mutex=ForwardWarpImageFilter::MutexImageType::New();
485 mutex->SetRegions(region);
487 mutex->SetSpacing(inputPtr->GetSpacing());
488 helper1->SetMutexImage(mutex);
490 helper1->SetMutexImage();
492 if (m_Verbose) std::cout <<"Forwarp warping using a thread-safe algorithm" <<std::endl;
493 } else if(m_Verbose)std::cout <<"Forwarp warping using a thread-unsafe algorithm" <<std::endl;
495 //Execute helper class
499 typename InternalImageType::Pointer temp= helper1->GetOutput();
502 weights=helper1->GetWeights();
505 //===========================================================================
506 //2. Normalize the output by the weights and remove holes
507 //Call threaded helper class
508 typedef HelperClass2<InternalImageType, OutputImageType> HelperClass2Type;
509 typename HelperClass2Type::Pointer helper2=HelperClass2Type::New();
511 //Set temporary output as input
512 if(m_NumberOfThreadsIsGiven) {
513 #if ITK_VERSION_MAJOR <= 4
514 helper2->SetNumberOfThreads(m_NumberOfThreads);
516 helper2->SetNumberOfWorkUnits(m_NumberOfWorkUnits);
519 helper2->SetInput(temp);
520 helper2->SetWeights(weights);
521 helper2->SetEdgePaddingValue(m_EdgePaddingValue);
523 //Execute helper class
527 this->SetNthOutput(0, helper2->GetOutput());