1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkMirrorPadImageFilter_hxx
19 #define itkMirrorPadImageFilter_hxx
20 
21 #include "itkMirrorPadImageFilter.h"
22 #include "itkImageRegionIteratorWithIndex.h"
23 #include "itkImageRegionConstIterator.h"
24 #include "itkObjectFactory.h"
25 #include "itkProgressReporter.h"
26 #include <vector>
27 
28 namespace itk
29 {
30 /**
31  * Given an n dimensional list of output region breakpoints in indices
32  * and size (where the current region and maximum region for each dimension
33  * is encoded in regIndices and regLimit), choose the next output region.
34  */
35 template< typename TInputImage, typename TOutputImage >
36 int MirrorPadImageFilter< TInputImage, TOutputImage >
GenerateNextOutputRegion(long * regIndices,long * regLimit,std::vector<long> * indices,std::vector<long> * sizes,OutputImageRegionType & outputRegion)37 ::GenerateNextOutputRegion(long *regIndices, long *regLimit,
38                            std::vector< long > *indices,
39                            std::vector< long > *sizes,
40                            OutputImageRegionType & outputRegion)
41 {
42   unsigned int         ctr;
43   int                  done = 0;
44   OutputImageIndexType nextIndex = outputRegion.GetIndex();
45   OutputImageSizeType  nextSize = outputRegion.GetSize();
46 
47   //
48   // Starting at the first dimension, increment the counter and set a new
49   // value for the region parameters.  If we wrap on a region, then we
50   // also increment to the next region for the next higher dimension.
51   //
52   for ( ctr = 0; ( ctr < ImageDimension ) && !done; ctr++ )
53     {
54     regIndices[ctr]++;
55     done = 1;
56     if ( regIndices[ctr] >= regLimit[ctr] )
57       {
58       regIndices[ctr] = 0;
59       done = 0;
60       }
61     nextIndex[ctr] = indices[ctr][regIndices[ctr]];
62     nextSize[ctr] = sizes[ctr][regIndices[ctr]];
63     }
64 
65   //
66   // Set what we have learned into the image region.
67   //
68   outputRegion.SetIndex(nextIndex);
69   outputRegion.SetSize(nextSize);
70 
71   //
72   // If any dimension has zero size, then we do not need to process this
73   // region.  Report this back to the calling routine.
74   //
75   for ( ctr = 0; ctr < ImageDimension; ctr++ )
76     {
77     if ( nextSize[ctr] == 0 )
78       {
79       return 0;
80       }
81     }
82 
83   return 1;
84 }
85 
86 /**
87  * Given an n dimensional list of input region breakpoints in indices
88  * and size (where the current region and maximum region for each dimension
89  * is encoded in regIndices and regLimit), choose the next input region.
90  */
91 template< typename TInputImage, typename TOutputImage >
92 int MirrorPadImageFilter< TInputImage, TOutputImage >
GenerateNextInputRegion(long * regIndices,long * regLimit,std::vector<long> * indices,std::vector<long> * sizes,InputImageRegionType & inputRegion)93 ::GenerateNextInputRegion(long *regIndices, long *regLimit,
94                           std::vector< long > *indices,
95                           std::vector< long > *sizes,
96                           InputImageRegionType & inputRegion)
97 {
98   unsigned int        ctr;
99   int                 done = 0;
100   InputImageIndexType nextIndex = inputRegion.GetIndex();
101   InputImageSizeType  nextSize = inputRegion.GetSize();
102 
103   //
104   // Starting at the first dimension, increment the counter and set a new
105   // value for the region parameters.  If we wrap on a region, then we
106   // also increment to the next region for the next higher dimension.
107   //
108   for ( ctr = 0; ( ctr < ImageDimension ) && !done; ctr++ )
109     {
110     regIndices[ctr]++;
111     done = 1;
112     if ( regIndices[ctr] >= regLimit[ctr] )
113       {
114       regIndices[ctr] = 0;
115       done = 0;
116       }
117     nextIndex[ctr] = indices[ctr][regIndices[ctr]];
118     nextSize[ctr] = sizes[ctr][regIndices[ctr]];
119     }
120 
121   //
122   // Set what we have learned into the image region.
123   //
124   inputRegion.SetIndex(nextIndex);
125   inputRegion.SetSize(nextSize);
126 
127   //
128   // If any dimension has zero size, then we do not need to process this
129   // region.  Report this back to the calling routine.
130   //
131   for ( ctr = 0; ctr < ImageDimension; ctr++ )
132     {
133     if ( nextSize[ctr] == 0 )
134       {
135       return 0;
136       }
137     }
138 
139   return 1;
140 }
141 
142 /**
143  * Given the start and end indices of a region, determine how many
144  * instances of size fit within the region.  The variable offset provides
145  * a way to adjust width of the area while forcing alignment to the
146  * start or end location.
147  */
148 template< typename TInputImage, typename TOutputImage >
149 int
150 MirrorPadImageFilter< TInputImage, TOutputImage >
FindRegionsInArea(long start,long end,long size,long offset)151 ::FindRegionsInArea(long start, long end, long size, long offset)
152 {
153   int  result = 1;
154   long regionsize;
155 
156   regionsize = end - start;
157   if ( regionsize > 0 )  // Find out home many regions we have,
158     {
159     result = regionsize / size;
160 //      if ((regionsize % size) != 0)
161 //  {
162     result++;
163 //  }
164     if ( offset > 0 )
165       {
166       result = result - ( offset / size );
167       }
168     }
169 
170   return result;
171 }
172 
173 /**
174  * Convert from the output index to the input index taking
175  * into consideration mirrored and normal regions.
176  */
177 template< typename TInputImage, typename TOutputImage >
178 void
179 MirrorPadImageFilter< TInputImage, TOutputImage >
ConvertOutputIndexToInputIndex(OutputImageIndexType & outputIndex,InputImageIndexType & inputIndex,OutputImageRegionType & outputRegion,InputImageRegionType & inputRegion,int * oddRegionArray,double & outDecayFactor)180 ::ConvertOutputIndexToInputIndex(
181                                  OutputImageIndexType & outputIndex,
182                                  InputImageIndexType & inputIndex,
183                                  OutputImageRegionType & outputRegion,
184                                  InputImageRegionType & inputRegion,
185                                  int *oddRegionArray,
186                                  double & outDecayFactor )
187 {
188   unsigned int dimCtr;
189   long         a, b, c; // Output region goes from a to a+b-1
190                         // Input region goes from c to c+b-1
191   OutputImageIndexType outputRegionStart = outputRegion.GetIndex();
192   InputImageIndexType  inputRegionStart = inputRegion.GetIndex();
193   InputImageSizeType   inputSizes = inputRegion.GetSize();
194 
195   for ( dimCtr = 0; dimCtr < ImageDimension; dimCtr++ )
196     {
197     a = outputRegionStart[dimCtr];
198     c = inputRegionStart[dimCtr];
199 
200     if ( oddRegionArray[dimCtr] )
201       {
202       b = inputSizes[dimCtr];
203       inputIndex[dimCtr] = a + c + b - 1 - outputIndex[dimCtr];
204       }
205     else
206       {
207       inputIndex[dimCtr] =  outputIndex[dimCtr] - a + c;
208       }
209   }
210 
211   if (this->m_DecayBase != 1.0)
212     {
213       SizeValueType distanceFromEdge = 0;
214 
215       //city-block distance, first layer of 6-connected outside voxels having distance 1
216       //18-connected voxels and second 6-connected layer having distance 2 etc.
217       for ( dimCtr = 0; dimCtr < ImageDimension; ++dimCtr )
218         {
219         distanceFromEdge += (std::abs(outputIndex[dimCtr] - inputIndex[dimCtr]) + 1) / 2;
220         }
221       //TODO: see if precomputed pow look-up table will speed this up
222       outDecayFactor = std::pow(this->m_DecayBase, distanceFromEdge);
223     }
224 }
225 
226 
227 /**
228  * Decide whether test falls within an odd or even number
229  * of size regions from base.
230  */
231 template< typename TInputImage, typename TOutputImage >
232 int
233 MirrorPadImageFilter< TInputImage, TOutputImage >
RegionIsOdd(long base,long test,long size)234 ::RegionIsOdd(long base, long test, long size)
235 {
236   long oddness;
237 
238   // Within first region is even.
239   if ( ( test >= base ) && ( test < ( base + size ) ) )
240     {
241     return 0;
242     }
243 
244   if ( test < base )
245     {
246     oddness = ( base - test - 1 ) / size;
247     return !( oddness & 1 );
248     }
249 
250   oddness = ( test - base ) / size;
251   return ( oddness & 1 );
252 }
253 
254 /**
255  * Generate region 0 (inter-region) information.  Based on the indices
256  * of the input and the output for this dimension, decide what are the
257  * starting points and the lengths of the output region directly
258  * corresponding to the input region.  Padding will be on either
259  * side of this region.  The algorithmic complications are necessary
260  * to support the streaming interface and multithreading.
261  */
262 template< typename TInputImage, typename TOutputImage >
263 int
264 MirrorPadImageFilter< TInputImage, TOutputImage >
BuildInterRegions(std::vector<long> & inputRegionStart,std::vector<long> & outputRegionStart,std::vector<long> & inputRegionSizes,std::vector<long> & outputRegionSizes,long inputIndex,long outputIndex,long inputSize,long outputSize,int numRegs,int & regCtr)265 ::BuildInterRegions(std::vector< long > & inputRegionStart,
266                     std::vector< long > & outputRegionStart,
267                     std::vector< long > & inputRegionSizes,
268                     std::vector< long > & outputRegionSizes,
269                     long inputIndex, long outputIndex,
270                     long inputSize, long outputSize,
271                     int numRegs, int & regCtr)
272 {
273   long sizeTemp;  // Holder for current size calculation.
274 
275   // Region 0 is between, which has a starting index equal to
276   // the input region starting index, unless that would be
277   // outside the bounds of the output image.
278   if ( inputIndex > outputIndex )
279     {
280     outputRegionStart[0] = inputIndex;
281     inputRegionStart[0] = inputIndex;
282     }
283   else
284     {
285     outputRegionStart[0] = outputIndex;
286     inputRegionStart[0] = outputIndex;
287     }
288 
289   // Size of the in region is the area from index 0 to the end of the
290   // input or the output, whichever comes first.
291   if ( ( inputIndex + inputSize )
292        < ( outputIndex + outputSize ) )
293     {
294     sizeTemp = inputIndex + inputSize - outputRegionStart[0];
295     }
296   else
297     {
298     sizeTemp = outputIndex + outputSize - outputRegionStart[0];
299     }
300   outputRegionSizes[0] = ( ( sizeTemp > 0 ) ? sizeTemp : 0 );
301   inputRegionSizes[0] = ( ( sizeTemp > 0 ) ? sizeTemp : 0 );
302 
303   regCtr = numRegs;
304   return 1;
305 }
306 
307 /**
308  * Generate region 1 (pre-region) information.  Based on the indices
309  * of the input and the output for this dimension, decide what are the
310  * starting points and the lengths of the output region directly
311  * preceding the input region in this dimension.  This may require
312  * more than one region be defined if the padding is larger than the
313  * size of the input image in this dimension.  Other algorithmic
314  * complications are necessary to support the streaming interface
315  * and multithreading.
316  */
317 template< typename TInputImage, typename TOutputImage >
318 int
319 MirrorPadImageFilter< TInputImage, TOutputImage >
BuildPreRegions(std::vector<long> & inputRegionStart,std::vector<long> & outputRegionStart,std::vector<long> & inputRegionSizes,std::vector<long> & outputRegionSizes,long inputIndex,long outputIndex,long inputSize,long outputSize,int numRegs,int & regCtr)320 ::BuildPreRegions(std::vector< long > & inputRegionStart,
321                   std::vector< long > & outputRegionStart,
322                   std::vector< long > & inputRegionSizes,
323                   std::vector< long > & outputRegionSizes,
324                   long inputIndex, long outputIndex,
325                   long inputSize, long outputSize,
326                   int numRegs, int & regCtr)
327 {
328   long sizeTemp;  // Holder for current size calculation.
329   int  ctr;       // Generic loop counter.
330   long offset;    // Offset for times when we need to shorten both ends.
331 
332   // Handle the pre-region.  Within the pre-region, the first and last
333   // groups may be truncated and only contain the back part of the input
334   // data.  All other regions will be complete copies of the input.
335   outputRegionStart[regCtr] = outputIndex;
336 
337   // Size of the pre-region is all the output that precedes the input,
338   // all except the first (and possibly the last) will be the size of
339   // the input.
340   sizeTemp = outputRegionStart[0] - outputIndex;
341   sizeTemp = ( ( sizeTemp > 0 ) ? ( sizeTemp % inputSize ) : 0 );
342   outputRegionSizes[regCtr] = sizeTemp;
343   inputRegionSizes[regCtr] = sizeTemp;
344   offset = inputSize - sizeTemp;
345   if ( ( sizeTemp == 0 ) || this->RegionIsOdd(inputIndex, outputIndex, inputSize) )
346     {
347     inputRegionStart[regCtr] = inputIndex;
348     }
349   else
350     {
351     inputRegionStart[regCtr] = inputIndex + offset;
352     }
353   // Handle the rest of the pre-region by stepping through in blocks of
354   // the size of the input image.
355   for ( ctr = 1; ctr < numRegs; ctr++ )
356     {
357     regCtr++;
358     offset = 0;
359     outputRegionStart[regCtr] = outputRegionStart[regCtr - 1]
360                                 + static_cast< long >( outputRegionSizes[regCtr - 1] );
361     inputRegionStart[regCtr] = inputIndex;
362     outputRegionSizes[regCtr] = inputSize;
363     inputRegionSizes[regCtr] = inputSize;
364     }
365   // Fix size on last region, if necessary.
366   if ( ( outputRegionStart[regCtr] + static_cast< long >( outputRegionSizes[regCtr] ) )
367        > ( outputIndex + outputSize ) )
368     {
369     outputRegionSizes[regCtr] = outputIndex + outputSize
370                                 - outputRegionStart[regCtr];
371     inputRegionSizes[regCtr] = outputRegionSizes[regCtr];
372     if ( ( inputRegionSizes[regCtr] < inputSize )
373          && this->RegionIsOdd(inputIndex, outputRegionStart[regCtr], inputSize) )
374       {
375       inputRegionStart[regCtr] = inputIndex + inputSize - inputRegionSizes[regCtr] - offset;
376       }
377     }
378 
379   return regCtr;
380 }
381 
382 /**
383  * Generate region 2 (post-region) information.  Based on the indices
384  * of the input and the output for this dimension, decide what are the
385  * starting points and the lengths of the output region directly
386  * succeeding the input region in this dimension.  This may require
387  * more than one region be defined if the padding is larger than the
388  * size of the input image in this dimension.  Other algorithmic
389  * complications are necessary to support the streaming interface
390  * and multithreading.
391  */
392 template< typename TInputImage, typename TOutputImage >
393 int
394 MirrorPadImageFilter< TInputImage, TOutputImage >
BuildPostRegions(std::vector<long> & inputRegionStart,std::vector<long> & outputRegionStart,std::vector<long> & inputRegionSizes,std::vector<long> & outputRegionSizes,long inputIndex,long outputIndex,long inputSize,long outputSize,int numRegs,int & regCtr)395 ::BuildPostRegions(std::vector< long > & inputRegionStart,
396                    std::vector< long > & outputRegionStart,
397                    std::vector< long > & inputRegionSizes,
398                    std::vector< long > & outputRegionSizes,
399                    long inputIndex, long outputIndex,
400                    long inputSize, long outputSize,
401                    int numRegs, int & regCtr)
402 {
403   long sizeTemp;  // Holder for current size calculation.
404   int  ctr;       // Generic loop counter.
405   int  offset;    // Offset for when we have to shorten both ends.
406 
407   // Handle the post region.  The post region has a number of
408   // areas of size equal to the input region, followed by one
409   // region of possibly smaller size.
410   regCtr++;
411   sizeTemp = outputIndex + outputSize - inputIndex - inputSize;
412   sizeTemp = ( ( sizeTemp > 0 ) ? ( sizeTemp % inputSize ) : 0 );
413   outputRegionSizes[regCtr] = sizeTemp;
414   inputRegionSizes[regCtr] = sizeTemp;
415   outputRegionStart[regCtr] = outputIndex + outputSize - sizeTemp;
416   offset = inputSize - sizeTemp;
417   if ( ( sizeTemp > 0 ) && this->RegionIsOdd(inputIndex, outputRegionStart[regCtr], inputSize) )
418     {
419     inputRegionStart[regCtr] = inputIndex + offset;
420     }
421   else
422     {
423     inputRegionStart[regCtr] = inputIndex;
424     }
425 
426   for ( ctr = numRegs - 1; ctr >= 1; ctr-- )
427     {
428     offset = 0;
429     regCtr++;
430     outputRegionStart[regCtr] = outputRegionStart[regCtr - 1] - inputSize;
431     inputRegionStart[regCtr] = inputIndex;
432     outputRegionSizes[regCtr] = inputSize;
433     inputRegionSizes[regCtr] = inputSize;
434     }
435   // Fix size on last region, if necessary.
436   if ( outputRegionStart[regCtr] < outputIndex )
437     {
438     sizeTemp = outputIndex - outputRegionStart[regCtr];
439     outputRegionStart[regCtr] += sizeTemp;
440     if ( this->RegionIsOdd(inputIndex, outputRegionStart[regCtr], inputSize)
441          && ( outputIndex > ( inputIndex + inputSize ) ) )
442       {
443       inputRegionStart[regCtr] = inputIndex + offset;
444       }
445     else
446       {
447       inputRegionStart[regCtr] += sizeTemp;
448       }
449     outputRegionSizes[regCtr] -= sizeTemp;
450     inputRegionSizes[regCtr] = outputRegionSizes[regCtr];
451     }
452 
453   return regCtr;
454 }
455 
456 /**
457  * MirrorPadImageFilter needs a different input requested region than
458  * output requested region.  As such, MirrorPadImageFilter needs to
459  * provide an implementation for GenerateInputRequestedRegion() in
460  * order to inform the pipeline execution model.
461  *
462  * \sa PadImageFilter::GenerateInputRequestedRegion()
463  * \sa ProcessObject::GenerateInputRequestedRegion()
464  */
465 template< typename TInputImage, typename TOutputImage >
466 void
467 MirrorPadImageFilter< TInputImage, TOutputImage >
GenerateInputRequestedRegion()468 ::GenerateInputRequestedRegion()
469 {
470   unsigned int dimCtr;
471   int          regCtr;
472 
473   // call the superclass' implementation of this method
474   // Superclass::GenerateInputRequestedRegion();
475 
476   // get pointers to the input and output
477   typename Superclass::InputImagePointer inputPtr =
478     const_cast< InputImageType * >( this->GetInput() );
479   typename Superclass::OutputImagePointer outputPtr = this->GetOutput();
480 
481   if ( !inputPtr || !outputPtr )
482     {
483     return;
484     }
485 
486   // Define a few indices that will be used to translate from an input pixel
487   // to an output pixel
488   OutputImageIndexType outputIndex = outputPtr->GetRequestedRegion().GetIndex();
489   InputImageIndexType  inputIndex = inputPtr->GetLargestPossibleRegion().GetIndex();
490   OutputImageSizeType  outputSize = outputPtr->GetRequestedRegion().GetSize();
491   InputImageSizeType   inputSize = inputPtr->GetLargestPossibleRegion().GetSize();
492 
493   OutputImageRegionType outputRegion;
494   InputImageRegionType  inputRegion;
495 
496   // For n dimensions, there are k^n combinations of before, between, and
497   // after on these regions.  We are keeping this flexible so that we
498   // can handle other blockings imposed by the mirror and wrap algorithms.
499   long                inRegLimit[ImageDimension];
500   long                outRegLimit[ImageDimension];
501   long                minIndex[ImageDimension], maxIndex[ImageDimension];
502   int                 numPre[ImageDimension], numPost[ImageDimension], numIn[ImageDimension];
503   std::vector< long > outputRegionStart[ImageDimension];
504   std::vector< long > outputRegionSizes[ImageDimension];
505   std::vector< long > inputRegionStart[ImageDimension];
506   std::vector< long > inputRegionSizes[ImageDimension];
507 
508   // Calculate the actual number of regions for each dimension,
509   // and set up the required variables here.
510   for ( dimCtr = 0; dimCtr < ImageDimension; dimCtr++ )
511     {
512     numIn[dimCtr] = 1;  // Always assume exactly one inter region.
513     numPre[dimCtr] =    // Count how many versions of input fit in pre-pad
514                      this->FindRegionsInArea( outputIndex[dimCtr], inputIndex[dimCtr],
515                                               static_cast< long >( inputSize[dimCtr] ),
516                                               inputIndex[dimCtr] - outputIndex[dimCtr]
517                                               - static_cast< long >( outputSize[dimCtr] ) );
518     numPost[dimCtr] =   // Count how many versions of input fit in post-pad
519                       this->FindRegionsInArea( inputIndex[dimCtr] + static_cast< long >( inputSize[dimCtr] ),
520                                                outputIndex[dimCtr] + static_cast< long >( outputSize[dimCtr] ),
521                                                static_cast< long >( inputSize[dimCtr] ),
522                                                outputIndex[dimCtr] - inputIndex[dimCtr]
523                                                - static_cast< long >( inputSize[dimCtr] ) );
524     inRegLimit[dimCtr] = numPre[dimCtr] + numIn[dimCtr] + numPost[dimCtr];
525     outRegLimit[dimCtr] = numPre[dimCtr] + numIn[dimCtr] + numPost[dimCtr];
526     outputRegionStart[dimCtr].resize(outRegLimit[dimCtr]);
527     outputRegionSizes[dimCtr].resize(outRegLimit[dimCtr]);
528     inputRegionStart[dimCtr].resize(inRegLimit[dimCtr]);
529     inputRegionSizes[dimCtr].resize(inRegLimit[dimCtr]);
530     }
531 
532   //
533   // Generate the break points for the image regions we counted in the
534   // previous loop.
535   //
536   for ( dimCtr = 0; dimCtr < ImageDimension; dimCtr++ )
537     {
538     //
539     // Generate region 0 (inter-region) information.  Based on the indices
540     // of the input and the output for this dimension, decide what are the
541     // starting points and the lengths of the output region directly
542     // corresponding to the input region.  Padding will be on either
543     // side of this region.
544     //
545     regCtr = BuildInterRegions(inputRegionStart[dimCtr],
546                                outputRegionStart[dimCtr],
547                                inputRegionSizes[dimCtr],
548                                outputRegionSizes[dimCtr],
549                                inputIndex[dimCtr],
550                                outputIndex[dimCtr],
551                                static_cast< long >( inputSize[dimCtr] ),
552                                static_cast< long >( outputSize[dimCtr] ),
553                                numIn[dimCtr], regCtr);
554 
555     //
556     // Generate region 1 (pre-region) information for that part of the
557     // output image which precedes the input image in this dimension.
558     //
559     regCtr = BuildPreRegions(inputRegionStart[dimCtr],
560                              outputRegionStart[dimCtr],
561                              inputRegionSizes[dimCtr],
562                              outputRegionSizes[dimCtr],
563                              inputIndex[dimCtr],
564                              outputIndex[dimCtr],
565                              static_cast< long >( inputSize[dimCtr] ),
566                              static_cast< long >( outputSize[dimCtr] ),
567                              numPre[dimCtr], regCtr);
568 
569     //
570     // Generate region 2 (post-region) information for that part of the
571     // output image which succeeds the input image in this dimension.
572     //
573     regCtr = BuildPostRegions(inputRegionStart[dimCtr],
574                               outputRegionStart[dimCtr],
575                               inputRegionSizes[dimCtr],
576                               outputRegionSizes[dimCtr],
577                               inputIndex[dimCtr],
578                               outputIndex[dimCtr],
579                               static_cast< long >( inputSize[dimCtr] ),
580                               static_cast< long >( outputSize[dimCtr] ),
581                               numPost[dimCtr], regCtr);
582     }
583 
584   //
585   // Pick the indices which span the largest input region we need for this
586   // output region.
587   //
588   for ( dimCtr = 0; dimCtr < ImageDimension; dimCtr++ )
589     {
590     minIndex[dimCtr] = inputRegionStart[dimCtr][0];
591     maxIndex[dimCtr] = minIndex[dimCtr] + static_cast< long >( inputRegionSizes[dimCtr][0] );
592 
593     for ( regCtr = 1;
594           regCtr < ( numIn[dimCtr] + numPre[dimCtr] + numPost[dimCtr] );
595           regCtr++ )
596       {
597       if ( minIndex[dimCtr] == maxIndex[dimCtr] )
598         {
599         minIndex[dimCtr] = inputRegionStart[dimCtr][regCtr];
600         maxIndex[dimCtr] = minIndex[dimCtr]
601                            + static_cast< long >( inputRegionSizes[dimCtr][regCtr] );
602         }
603       else
604         {
605         if ( inputRegionStart[dimCtr][regCtr] < minIndex[dimCtr] )
606           {
607           minIndex[dimCtr] = inputRegionStart[dimCtr][regCtr];
608           }
609         if ( ( inputRegionStart[dimCtr][regCtr]
610                + static_cast< long >( inputRegionSizes[dimCtr][regCtr] ) )
611              > maxIndex[dimCtr] )
612           {
613           maxIndex[dimCtr] = inputRegionStart[dimCtr][regCtr]
614                              + static_cast< long >( inputRegionSizes[dimCtr][regCtr] );
615           }
616         }
617       }
618     }
619 
620   typename TInputImage::SizeType inputRequestedRegionSize;
621   typename TInputImage::IndexType inputRequestedRegionStartIndex;
622   for ( dimCtr = 0; dimCtr < ImageDimension; dimCtr++ )
623     {
624     inputRequestedRegionStartIndex[dimCtr] = minIndex[dimCtr];
625     inputRequestedRegionSize[dimCtr] = maxIndex[dimCtr] - minIndex[dimCtr];
626     }
627 
628   typename TInputImage::RegionType inputRequestedRegion;
629   inputRequestedRegion.SetSize(inputRequestedRegionSize);
630   inputRequestedRegion.SetIndex(inputRequestedRegionStartIndex);
631 
632   inputPtr->SetRequestedRegion(inputRequestedRegion);
633 }
634 
635 template< typename TInputImage, typename TOutputImage >
636 void
637 MirrorPadImageFilter< TInputImage, TOutputImage >
DynamicThreadedGenerateData(const OutputImageRegionType & outputRegionForThread)638 ::DynamicThreadedGenerateData(const OutputImageRegionType & outputRegionForThread)
639 {
640   unsigned int dimCtr, i;
641   int          regCtr;
642   int          numRegions = 1; // number of regions in our decomposed space.
643   int          goodInput, goodOutput;
644 
645   // Are the regions non-empty?
646   itkDebugMacro(<< "MirrorPadImageFilter::DynamicThreadedGenerateData");
647 
648   // Get the input and output pointers
649   const InputImageType *inputPtr = this->GetInput();
650   OutputImageType *outputPtr = this->GetOutput();
651 
652   // Define a few indices that will be used to translate from an input pixel
653   // to an output pixel
654   OutputImageIndexType outputIndex = outputRegionForThread.GetIndex();
655   InputImageIndexType  inputIndex = inputPtr->GetLargestPossibleRegion().GetIndex();
656   OutputImageSizeType outputSize = outputRegionForThread.GetSize();
657   InputImageSizeType  inputSize = inputPtr->GetLargestPossibleRegion().GetSize();
658 
659   OutputImageRegionType outputRegion;
660   InputImageRegionType  inputRegion;
661 
662   // For n dimensions, there are k^n combinations of before, between, and
663   // after on these regions.  We are keeping this flexible so that we
664   // can handle other blockings imposed by the mirror and wrap algorithms.
665   long                inRegIndices[ImageDimension];
666   long                inRegLimit[ImageDimension];
667   long                outRegIndices[ImageDimension];
668   long                outRegLimit[ImageDimension];
669   int                 numPre[ImageDimension], numPost[ImageDimension], numIn[ImageDimension];
670   std::vector< long > outputRegionStart[ImageDimension];
671   std::vector< long > outputRegionSizes[ImageDimension];
672   std::vector< long > inputRegionStart[ImageDimension];
673   std::vector< long > inputRegionSizes[ImageDimension];
674 
675   // Calculate the actual number of regions for each dimension,
676   // and set up the required variables here.
677   for ( dimCtr = 0; dimCtr < ImageDimension; dimCtr++ )
678     {
679     numIn[dimCtr] = 1;  // Always assume exactly one inter region.
680     numPre[dimCtr] =    // Count how many versions of input fit in pre-pad
681                      this->FindRegionsInArea( outputIndex[dimCtr], inputIndex[dimCtr],
682                                               static_cast< long >( inputSize[dimCtr] ),
683                                               inputIndex[dimCtr] - outputIndex[dimCtr]
684                                               - static_cast< long >( outputSize[dimCtr] ) );
685     numPost[dimCtr] =   // Count how many versions of input fit in post-pad
686                       this->FindRegionsInArea( inputIndex[dimCtr] + static_cast< long >( inputSize[dimCtr] ),
687                                                outputIndex[dimCtr] + static_cast< long >( outputSize[dimCtr] ),
688                                                static_cast< long >( inputSize[dimCtr] ),
689                                                outputIndex[dimCtr] - inputIndex[dimCtr]
690                                                - static_cast< long >( inputSize[dimCtr] ) );
691     inRegLimit[dimCtr] = numPre[dimCtr] + numIn[dimCtr] + numPost[dimCtr];
692     inRegIndices[dimCtr] = inRegLimit[dimCtr] - 1;
693     outRegLimit[dimCtr] = numPre[dimCtr] + numIn[dimCtr] + numPost[dimCtr];
694     outRegIndices[dimCtr] = outRegLimit[dimCtr] - 1;
695     numRegions *= outRegLimit[dimCtr];
696     outputRegionStart[dimCtr].resize(outRegLimit[dimCtr]);
697     outputRegionSizes[dimCtr].resize(outRegLimit[dimCtr]);
698     inputRegionStart[dimCtr].resize(inRegLimit[dimCtr]);
699     inputRegionSizes[dimCtr].resize(inRegLimit[dimCtr]);
700     }
701 
702   // Generate the break points for the image regions we counted in the
703   // previous loop.
704   for ( dimCtr = 0; dimCtr < ImageDimension; dimCtr++ )
705     {
706     // Generate region 0 (inter-region) information.  Based on the indices
707     // of the input and the output for this dimension, decide what are the
708     // starting points and the lengths of the output region directly
709     // corresponding to the input region.  Padding will be on either
710     // side of this region.
711     regCtr = BuildInterRegions(inputRegionStart[dimCtr],
712                                outputRegionStart[dimCtr],
713                                inputRegionSizes[dimCtr],
714                                outputRegionSizes[dimCtr],
715                                inputIndex[dimCtr],
716                                outputIndex[dimCtr],
717                                static_cast< long >( inputSize[dimCtr] ),
718                                static_cast< long >( outputSize[dimCtr] ),
719                                numIn[dimCtr], regCtr);
720 
721     // Generate region 1 (pre-region) information for that part of the
722     // output image which precedes the input image in this dimension.
723     regCtr = BuildPreRegions(inputRegionStart[dimCtr],
724                              outputRegionStart[dimCtr],
725                              inputRegionSizes[dimCtr],
726                              outputRegionSizes[dimCtr],
727                              inputIndex[dimCtr],
728                              outputIndex[dimCtr],
729                              static_cast< long >( inputSize[dimCtr] ),
730                              static_cast< long >( outputSize[dimCtr] ),
731                              numPre[dimCtr], regCtr);
732 
733     // Generate region 2 (post-region) information for that part of the
734     // output image which succeeds the input image in this dimension.
735     regCtr = BuildPostRegions(inputRegionStart[dimCtr],
736                               outputRegionStart[dimCtr],
737                               inputRegionSizes[dimCtr],
738                               outputRegionSizes[dimCtr],
739                               inputIndex[dimCtr],
740                               outputIndex[dimCtr],
741                               static_cast< long >( inputSize[dimCtr] ),
742                               static_cast< long >( outputSize[dimCtr] ),
743                               numPost[dimCtr], regCtr);
744     }
745 
746   // Define/declare iterators that will walk the input and output regions
747   // for this thread.
748   using OutputIterator = ImageRegionIterator< TOutputImage >;
749   using InputIterator = ImageRegionConstIterator< TInputImage >;
750 
751   int                  oddRegionArray[ImageDimension];
752   OutputImageIndexType currentOutputIndex;
753   InputImageIndexType  currentInputIndex;
754 
755   i = 0;
756 
757   // Now walk the regions.
758   for ( regCtr = 0; regCtr < numRegions; regCtr++ )
759     {
760     // If both a valid output and input region are defined for the particular
761     // defined region, then copy the input values to the output values.
762     goodOutput = this->GenerateNextOutputRegion
763                    (outRegIndices, outRegLimit, outputRegionStart,
764                    outputRegionSizes, outputRegion);
765     goodInput = this->GenerateNextInputRegion
766                   (inRegIndices, inRegLimit, inputRegionStart,
767                   inputRegionSizes, inputRegion);
768     if ( goodInput && goodOutput )
769       {
770       if ( inputRegion == outputRegion ) //this is an inner region which only needs to be copied
771         {
772         ImageAlgorithm::Copy(inputPtr, outputPtr, inputRegion, outputRegion);
773         }
774       else //this is a padding region, which might need exponential decay
775         {
776         for ( dimCtr = 0; dimCtr < ImageDimension; dimCtr++ )
777           {
778           oddRegionArray[dimCtr] =
779             RegionIsOdd( inputIndex[dimCtr],
780                          outputRegion.GetIndex()[dimCtr],
781                          static_cast< long >( inputSize[dimCtr] ) );
782           }
783 
784         OutputIterator outIt = OutputIterator(outputPtr, outputRegion);
785         InputIterator  inIt  = InputIterator(inputPtr, inputRegion);
786         double decayFactor = 1.0;
787 
788         // Do the actual copy of the input pixels to the output pixels here.
789         for (; !outIt.IsAtEnd(); ++outIt, i++, ++inIt )
790           {
791           currentOutputIndex = outIt.GetIndex();
792 
793           this->ConvertOutputIndexToInputIndex(currentOutputIndex,
794                                                currentInputIndex,
795                                                outputRegion,
796                                                inputRegion,
797                                                oddRegionArray,
798                                                decayFactor );
799 
800           inIt.SetIndex(currentInputIndex);
801 
802           using RealPixelType = typename  NumericTraits<typename InputImageType::PixelType>::RealType;
803           const typename OutputImageType::PixelType outVal( RealPixelType(inIt.Get()) * decayFactor );
804 
805           outIt.Set( outVal );
806           }
807         }
808       }
809     }
810 }
811 } // end namespace itk
812 
813 #endif
814