-
-
Notifications
You must be signed in to change notification settings - Fork 712
Performance comparison of iterators and ranges to copy vector images #5669
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
|
|
||
| #include "itkProgressReporter.h" | ||
| #include "itkImageAlgorithm.h" | ||
| #include "itkImageRegionRange.h" | ||
|
|
||
| namespace itk | ||
| { | ||
|
|
@@ -139,18 +140,21 @@ CastImageFilter<TInputImage, TOutputImage>::DynamicThreadedGenerateDataDispatche | |
|
|
||
| this->CallCopyOutputRegionToInputRegion(inputRegionForThread, outputRegionForThread); | ||
|
|
||
| const unsigned int componentsPerPixel = outputPtr->GetNumberOfComponentsPerPixel(); | ||
|
|
||
| #if 0 | ||
| // Define the iterators | ||
| ImageScanlineConstIterator inputIt(inputPtr, inputRegionForThread); | ||
| ImageScanlineIterator outputIt(outputPtr, outputRegionForThread); | ||
|
|
||
|
|
||
| const unsigned int componentsPerPixel = inputPtr->GetNumberOfComponentsPerPixel(); | ||
| while (!inputIt.IsAtEnd()) | ||
| { | ||
| while (!inputIt.IsAtEndOfLine()) | ||
| { | ||
| const InputPixelType & inputPixel = inputIt.Get(); | ||
| OutputPixelType value{ outputIt.Get() }; | ||
|
|
||
| for (unsigned int k = 0; k < componentsPerPixel; ++k) | ||
| { | ||
| value[k] = static_cast<typename OutputPixelType::ValueType>(inputPixel[k]); | ||
|
|
@@ -163,6 +167,32 @@ CastImageFilter<TInputImage, TOutputImage>::DynamicThreadedGenerateDataDispatche | |
| inputIt.NextLine(); | ||
| outputIt.NextLine(); | ||
| } | ||
| #else | ||
|
|
||
| auto inputRange = ImageRegionRange<const TInputImage>(*inputPtr, inputRegionForThread); | ||
| auto outputRange = ImageRegionRange<TOutputImage>(*outputPtr, outputRegionForThread); | ||
|
Comment on lines
+172
to
+173
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nitpick: technically this is OK, of course, but in ITK we don't really do AAA ("auto almost always") everywhere. (We just follow clang-tidy modernize-use-auto, but that's still not AAA everywhere). So I would just do: ImageRegionRange<const TInputImage> inputRange(*inputPtr, inputRegionForThread);
ImageRegionRange<TOutputImage> outputRange(*outputPtr, outputRegionForThread); |
||
|
|
||
| auto inputIt = inputRange.begin(); | ||
| auto outputIt = outputRange.begin(); | ||
| const auto inputEnd = inputRange.end(); | ||
|
|
||
|
|
||
| OutputPixelType outputPixel{ *outputIt }; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At this point, the value of
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are correct that the values in outputPixel are uninitialized. However, for the VectorImage cast, the outputPixel will point to the data in the output Image's buffer. So this removed the need to allocation memory, reduced the memory locations used ( atleast for variable length vectors. )
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is also the "BUG" cast where the reference to the first pixel is maintained and will be assigned all values in the range. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you implying that #5661 didn't fix a bug? To be honest, the time it took me to understand the origin of this bug is a clear indication to me that this is not the expected behavior of the Get function of an iterator. And I guess this is not consistent with how it behaves with scalar pixel.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The merged patch fixed the issue in the case filter. But this new code block with the ImageRangeIterator exhibits the same behavior as the original CastImageFilter. Some tricks have been needed to get operations on the VectorImageFilter to perform reasonably. But they have been this way for over 10 years, and crippling filters by making them run 10x slower may not be a reasonable option. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think it's reasonable too and I don't have the solution. But it does not mean it's not a bug. BTW, if you implement the (slow) version, a recursive Gaussian test fails which probably indicates a bug there too. |
||
| const unsigned int componentsPerPixel = NumericTraits<OutputPixelType>::GetLength(outputPixel); | ||
| while (inputIt != inputEnd) | ||
| { | ||
| InputPixelType inputPixel = *inputIt; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. You reference code times better on my system. |
||
| for (unsigned int k = 0; k < componentsPerPixel; ++k) | ||
| { | ||
| outputPixel[k] = static_cast<typename OutputPixelType::ValueType>(inputPixel[k]); | ||
| } | ||
| *outputIt = outputPixel; | ||
|
|
||
| ++inputIt; | ||
| ++outputIt; | ||
| } | ||
|
|
||
| #endif | ||
| } | ||
|
|
||
| } // end namespace itk | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the
#if 0code may be removed when this PR is ready, right? Otherwiseif constexpr (false)might be nicer... 😺 But I would prefer the code to just be removed, eventually.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made PR #5670 with just the change to the cast filter.
This change below fails the testing due to the aliasing/reference of the first outputPixel, just like #5668. I'll update that issue with the Image Range iterator to hopefully focus the discussion of what the correct behavior should be.