Skip to content

Commit 0b6156d

Browse files
committed
PERF: Use tuned ImageRangeRegion copy in CastImageFilter
Based on performance testing, across converting between Image of Vector and VectorImage, this loop was the best performing. Key features of the improved performane: - Uses NumericTraits::GetLength over Image::GetNumberOfComponents, the former may be constant, while the latter is virtual - Uses const InputPixelType & inputPixel - OutputPixelType value{ outputIt.Get() } initialized to a reference in the output image bufffer and does not perform memory allocation for variable length vectors.
1 parent 4fcc20a commit 0b6156d

File tree

1 file changed

+19
-20
lines changed

1 file changed

+19
-20
lines changed

Modules/Filtering/ImageFilterBase/include/itkCastImageFilter.hxx

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -139,29 +139,28 @@ CastImageFilter<TInputImage, TOutputImage>::DynamicThreadedGenerateDataDispatche
139139

140140
this->CallCopyOutputRegionToInputRegion(inputRegionForThread, outputRegionForThread);
141141

142-
const unsigned int componentsPerPixel = outputPtr->GetNumberOfComponentsPerPixel();
143-
144-
// Define the iterators
145-
ImageScanlineConstIterator inputIt(inputPtr, inputRegionForThread);
146-
ImageScanlineIterator outputIt(outputPtr, outputRegionForThread);
147-
148-
while (!inputIt.IsAtEnd())
142+
auto inputRange = itk::ImageRegionRange<const TInputImage>(*inputPtr, inputRegionForThread);
143+
auto outputRange = itk::ImageRegionRange<TOutputImage>(*outputPtr, outputRegionForThread);
144+
145+
auto inputIt = inputRange.begin();
146+
auto outputIt = outputRange.begin();
147+
const auto inputEnd = inputRange.end();
148+
149+
// Note: this loop has been timed for performance with converstions betwee image of vectors and VectorImages and other
150+
// combinations. The following is the most efficient usage of iterators. Important considerations are the some times
151+
// constant GetLength, the const & to input pixel and free from memory allocations with variable length vectors.
152+
const unsigned int componentsPerPixel = itk::NumericTraits<OutputPixelType>::GetLength(*outputIt);
153+
while (inputIt != inputEnd)
149154
{
150-
while (!inputIt.IsAtEndOfLine())
155+
const InputPixelType & inputPixel = *inputIt;
156+
OutputPixelType outputPixel{ *outputIt };
157+
for (unsigned int k = 0; k < componentsPerPixel; ++k)
151158
{
152-
const InputPixelType & inputPixel = inputIt.Get();
153-
OutputPixelType value{ outputIt.Get() };
154-
for (unsigned int k = 0; k < componentsPerPixel; ++k)
155-
{
156-
value[k] = static_cast<typename OutputPixelType::ValueType>(inputPixel[k]);
157-
}
158-
outputIt.Set(value);
159-
160-
++inputIt;
161-
++outputIt;
159+
outputPixel[k] = static_cast<typename OutputPixelType::ValueType>(inputPixel[k]);
162160
}
163-
inputIt.NextLine();
164-
outputIt.NextLine();
161+
*outputIt = outputPixel;
162+
++inputIt;
163+
++outputIt;
165164
}
166165
}
167166

0 commit comments

Comments
 (0)