Skip to content

Commit 5ca44c9

Browse files
N-Dekkerhjmjohnson
authored andcommitted
BUG: Add ImageAdaptor::ComputeOffset, to fix ImageRegionIterator support
Fixed issue #5870, "ImageAdaptor should have its own ComputeOffset, ImageRegionIterator support broken" `ImageRegionConstIterator<AdapterType>::Increment()` depends on `AdapterType::ComputeOffset`.
1 parent 22f6d27 commit 5ca44c9

2 files changed

Lines changed: 76 additions & 2 deletions

File tree

Modules/Core/ImageAdaptors/include/itkImageAdaptor.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,13 @@ class ITK_TEMPLATE_EXPORT ImageAdaptor : public ImageBase<TImage::ImageDimension
234234
IndexType
235235
ComputeIndex(OffsetValueType offset) const;
236236

237+
/** Computes the offset from the beginning of the buffer. */
238+
OffsetValueType
239+
ComputeOffset(const IndexType & index) const
240+
{
241+
return m_Image->ComputeOffset(index);
242+
}
243+
237244
/** PixelContainer type alias support Used to construct a container for
238245
* the pixel data. */
239246
using PixelContainer = typename TImage::PixelContainer;

Modules/Core/ImageAdaptors/test/itkImageAdaptorGTest.cxx

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@
1717
*=========================================================================*/
1818

1919
// First include the header file to be tested:
20-
#include "itkImageBase.h"
20+
#include "itkImageAdaptor.h"
2121

2222
#include "itkCovariantVector.h"
2323
#include "itkImage.h"
24-
#include "itkImageAdaptor.h"
24+
#include "itkImageRegionIterator.h"
25+
#include "itkIndexRange.h"
2526
#include "itkVector.h"
2627

2728
#include <gtest/gtest.h>
@@ -185,3 +186,69 @@ TEST(ImageAdapter, TransformMemberFunctionsReturnSameAsForImage)
185186
const auto image3D = itk::Image<unsigned char, 3>::New();
186187
Expect_Transform_member_functions_return_the_same_for_an_ImageAdapter_as_for_its_image(*image3D);
187188
}
189+
190+
191+
// Tests that ComputeOffset(index) returns the same value for an adaptor as for its internal image.
192+
TEST(ImageAdaptor, ComputeOffset)
193+
{
194+
constexpr unsigned int dimension{ 2 };
195+
using PixelType = int;
196+
using ImageType = itk::Image<PixelType, dimension>;
197+
198+
const auto image = ImageType::New();
199+
const auto adaptor = itk::ImageAdaptor<ImageType, DummyPixelAccessor<PixelType>>::New();
200+
201+
// Use a very small image region, to speed up the unit test.
202+
const itk::ImageRegion imageRegion{ itk::Index<dimension>::Filled(1), itk::Size<dimension>::Filled(2) };
203+
204+
adaptor->SetImage(image);
205+
adaptor->SetRegions(imageRegion);
206+
adaptor->AllocateInitialized();
207+
208+
for (const auto & index : itk::ImageRegionIndexRange<dimension>(imageRegion))
209+
{
210+
EXPECT_EQ(adaptor->ComputeOffset(index), image->ComputeOffset(index));
211+
}
212+
}
213+
214+
215+
// Tests that ImageAdaptor supports iteration by means of ImageRegionIterator.
216+
TEST(ImageAdaptor, SupportsRegionIterator)
217+
{
218+
constexpr unsigned int dimension{ 2 };
219+
using PixelType = int;
220+
using ImageType = itk::Image<PixelType, dimension>;
221+
222+
const auto image = ImageType::New();
223+
const auto adaptor = itk::ImageAdaptor<ImageType, DummyPixelAccessor<PixelType>>::New();
224+
225+
adaptor->SetImage(image);
226+
adaptor->SetRegions(itk::Size<dimension>::Filled(4));
227+
adaptor->AllocateInitialized();
228+
229+
constexpr auto regionIndex = itk::Index<dimension>::Filled(1);
230+
constexpr auto regionSize = itk::Size<dimension>::Filled(2);
231+
const itk::ImageRegion region{ regionIndex, regionSize };
232+
233+
// Set the pixel values by means of the adaptor, for the specified region.
234+
PixelType pixelValue{};
235+
constexpr PixelType maxPixelValue{ regionSize.CalculateProductOfElements() };
236+
237+
using AdaptorType = itk::ImageAdaptor<ImageType, DummyPixelAccessor<PixelType>>;
238+
for (itk::ImageRegionIterator<AdaptorType> iterator(adaptor, region); !iterator.IsAtEnd(); ++iterator)
239+
{
240+
++pixelValue;
241+
ASSERT_LE(pixelValue, maxPixelValue);
242+
iterator.Set(pixelValue);
243+
EXPECT_EQ(iterator.Get(), pixelValue);
244+
}
245+
246+
// Now check if the internal image has got the expected pixel values, in the specified region.
247+
PixelType expectedPixelValue{};
248+
249+
for (itk::ImageRegionConstIterator<ImageType> iterator(image, region); !iterator.IsAtEnd(); ++iterator)
250+
{
251+
++expectedPixelValue;
252+
EXPECT_EQ(iterator.Get(), expectedPixelValue);
253+
}
254+
}

0 commit comments

Comments
 (0)