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