Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ BSplineInterpolationWeightFunction<TCoordinate, VSpaceDimension, VSplineOrder>::
{
static constexpr auto offsetToIndexTable = [] {
FixedArray<IndexType, NumberOfWeights> table{};
auto indexIterator = ZeroBasedIndexRange<SpaceDimension>(SupportSize).cbegin();
auto indexIterator = MakeIndexRange(SupportSize).cbegin();

for (size_t i{}; i < NumberOfWeights; ++i)
{
Expand Down
27 changes: 25 additions & 2 deletions Modules/Core/Common/include/itkIndexRange.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ namespace itk
\code
constexpr unsigned int Dimension{ 2 };
const Size<Dimension> size = { {2, 3} };
const ZeroBasedIndexRange<Dimension> indexRange{ size };

for (const Index<Dimension> index : indexRange)
for (const Index<Dimension> index : MakeIndexRange(size))
{
std::cout << index;
}
Expand Down Expand Up @@ -474,6 +473,30 @@ using ImageRegionIndexRange = IndexRange<VDimension, false>;
template <unsigned int VDimension>
using ZeroBasedIndexRange = IndexRange<VDimension, true>;

/* Creates a range of indices for the specified grid size. */
template <unsigned int VDimension>
[[nodiscard]] constexpr auto
MakeIndexRange(const Size<VDimension> & gridSize)
{
return ZeroBasedIndexRange<VDimension>(gridSize);
}

/* Creates a range of indices for the specified image region. */
template <unsigned int VDimension>
[[nodiscard]] auto
MakeIndexRange(const ImageRegion<VDimension> & imageRegion)
{
return ImageRegionIndexRange<VDimension>(imageRegion);
}

/* Creates a range of indices for the image region specified by its index and size. */
template <unsigned int VDimension>
[[nodiscard]] auto
MakeIndexRange(const Index<VDimension> & imageRegionIndex, const Size<VDimension> & imageRegionSize)
{
return ImageRegionIndexRange<VDimension>(ImageRegion<VDimension>{ imageRegionIndex, imageRegionSize });
}

Comment on lines +476 to +499
Copy link
Copy Markdown
Contributor Author

@N-Dekker N-Dekker Feb 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of these simple MakeIndexRange functions, I think we might as well add similar functionality by using CTAD (class template argument deduction). But we had discussion about CTAD before. It might sometimes be risky to use CTAD (looking at Arthur O'Dwyer's blog). And it might sometimes cause compiler warnings (warning: 'T' may not intend to support class template argument deduction [-Wctad-maybe-unsupported]). So maybe we should just stick with such simple Make functions 🤷

} // namespace itk

#endif
3 changes: 1 addition & 2 deletions Modules/Core/Common/include/itkSobelOperator.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ SobelOperator<TPixel, VDimension, TAllocator>::Fill(const CoefficientVector & co
using IndexType = Index<VDimension>;

unsigned int coeff_index = 0;
for (const IndexType & index :
ImageRegionIndexRange<VDimension>(ImageRegion{ IndexType::Filled(-1), SizeType::Filled(3) }))
for (const IndexType & index : MakeIndexRange(IndexType::Filled(-1), SizeType::Filled(3)))
{
auto pos = static_cast<int>(center);

Expand Down
2 changes: 1 addition & 1 deletion Modules/Core/Common/test/itkImageRegionGTest.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ TEST(ImageRegion, OneSizedRegionIsInsideIffItsIndexIsInside)
auto paddedRegion = region;
paddedRegion.PadByRadius(1);

for (const auto & index : itk::ImageRegionIndexRange<RegionType::ImageDimension>(paddedRegion))
for (const auto & index : itk::MakeIndexRange(paddedRegion))
{
const RegionType oneSizedRegion{ index, SizeType::Filled(1) };

Expand Down
17 changes: 16 additions & 1 deletion Modules/Core/Common/test/itkIndexRangeGTest.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,26 @@ template class itk::IndexRange<2, false>;

using itk::IndexRange;
using itk::ImageRegionIndexRange;
using itk::MakeIndexRange;
using itk::ZeroBasedIndexRange;
using itk::RangeGTestUtilities;


static_assert(sizeof(ZeroBasedIndexRange<3>) < sizeof(ImageRegionIndexRange<3>),
"ZeroBasedIndexRange does not need to store the index of a region, so it should take less memory.");

static_assert(std::is_same_v<decltype(MakeIndexRange(itk::Size<2>{})), ZeroBasedIndexRange<2>> &&
std::is_same_v<decltype(MakeIndexRange(itk::Size<3>{})), ZeroBasedIndexRange<3>>,
"MakeIndexRange(size) should return a ZeroBasedIndexRange.");

static_assert(std::is_same_v<decltype(MakeIndexRange(itk::ImageRegion<2>{})), ImageRegionIndexRange<2>> &&
std::is_same_v<decltype(MakeIndexRange(itk::ImageRegion<3>{})), ImageRegionIndexRange<3>>,
"MakeIndexRange(imageRegion) should return an ImageRegionIndexRange.");

static_assert(std::is_same_v<decltype(MakeIndexRange(itk::Index<2>{}, itk::Size<2>{})), ImageRegionIndexRange<2>> &&
std::is_same_v<decltype(MakeIndexRange(itk::Index<3>{}, itk::Size<3>{})), ImageRegionIndexRange<3>>,
"MakeIndexRange(index, size) should return an ImageRegionIndexRange.");

namespace
{
template <unsigned int VDimension>
Expand Down Expand Up @@ -107,7 +120,9 @@ ExpectRangeIsEmptyWhenRegionSizeIsZero(std::mt19937 & randomNumberEngine)
const itk::Index<VDimension> randomRegionIndex = GenerateRandomIndex<VDimension>(randomNumberEngine);
const itk::ImageRegion<VDimension> zeroSizedImageRegion{ randomRegionIndex, zeroSize };

EXPECT_TRUE(ImageRegionIndexRange<VDimension>{ zeroSizedImageRegion }.empty());
EXPECT_TRUE(MakeIndexRange(zeroSize).empty());
EXPECT_TRUE(MakeIndexRange(zeroSizedImageRegion).empty());
EXPECT_TRUE(MakeIndexRange(randomRegionIndex, zeroSize).empty());
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ itkGaussianInterpolateImageFunctionTest(int, char *[])
image->SetOrigin(origin);
image->SetSpacing(spacing);

for (const auto index : itk::ZeroBasedIndexRange<ImageType::ImageDimension>(size))
for (const auto index : itk::MakeIndexRange(size))
{
image->SetPixel(index, index[0] + index[1]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ Expect_EvaluateAtIndex_returns_zero_when_all_pixels_are_zero(const typename TIma

imageFunction->SetInputImage(image);

for (const auto index : itk::ZeroBasedIndexRange<TImage::ImageDimension>{ imageSize })
for (const auto index : itk::MakeIndexRange(imageSize))
{
EXPECT_EQ(imageFunction->EvaluateAtIndex(index), 0);
}
Expand All @@ -88,7 +88,7 @@ Expect_EvaluateAtIndex_returns_number_of_neigbors_when_all_pixels_are_one(const

const auto numberOfNeighbors = std::pow(2.0 * radius + 1.0, TImage::ImageDimension);

for (const auto index : itk::ZeroBasedIndexRange<TImage::ImageDimension>{ imageSize })
for (const auto index : itk::MakeIndexRange(imageSize))
{
EXPECT_EQ(imageFunction->EvaluateAtIndex(index), numberOfNeighbors);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,13 @@ Expect_AxisAlignedBoundingBoxRegion_equals_region_of_single_pixel_when_it_is_the
image->SetRegions(imageRegion);
image->AllocateInitialized();

const itk::ImageRegionIndexRange<VImageDimension> indexRange{ imageRegion };

// Expected size: the "region size" of a single pixel (1x1, in 2D, 1x1x1 in 3D).
const itk::Size<VImageDimension> expectedSize = [] {
auto size = itk::Size<VImageDimension>::Filled(1);
return size;
}();

for (const auto & index : indexRange)
for (const auto & index : MakeIndexRange(imageRegion))
{
// Set only one pixel value non-zero.
image->SetPixel(index, 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ TEST(GradientImageFilter, ConstantGradientInputImage)
inputImage->SetRegions(imageSize);
inputImage->Allocate(false);

for (const auto & index : itk::ZeroBasedIndexRange<Dimension>(imageSize))
for (const auto & index : itk::MakeIndexRange(imageSize))
{
// A constant gradient along the first dimension of the image.
inputImage->SetPixel(index, static_cast<PixelType>(inputGradientValue * index[0]));
Expand All @@ -102,7 +102,7 @@ TEST(GradientImageFilter, ConstantGradientInputImage)
// Only look at the inner region, to avoid boundary effects (which are beyond the scope of this unit test).
const itk::ImageRegion innerRegion{ IndexType::Filled(1), imageSize - SizeType::Filled(2) };

for (const auto & index : itk::ImageRegionIndexRange<Dimension>(innerRegion))
for (const auto & index : itk::MakeIndexRange(innerRegion))
{
const auto outputPixelValue = output.GetPixel(index);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,11 @@ class ITK_TEMPLATE_EXPORT ContourExtractor2DImageFilter
using InputRealType = typename NumericTraits<InputPixelType>::RealType;

/** Ranges and iterators for regions */
using RegionIndexRange = ImageRegionIndexRange<InputImageType::ImageDimension>;
#ifndef ITK_FUTURE_LEGACY_REMOVE
using RegionIndexRange ITK_FUTURE_DEPRECATED(
"Please use `itk::ImageRegionIndexRange` or `itk::MakeIndexRange` directly!") =
ImageRegionIndexRange<InputImageType::ImageDimension>;
#endif
Comment on lines -148 to +152
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It appears that this nested RegionIndexRange type alias was only used internally by the filter itself, so now it is no longer necessary!

using RegionRange = ImageRegionRange<InputImageType>;
using RegionConstRange = ImageRegionRange<const InputImageType>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ ContourExtractor2DImageFilter<TInputImage>::CreateSingleContour(InputPixelType
using NeighborhoodRange = itk::ShapedImageNeighborhoodRange<const InputImageType, Policy>;
NeighborhoodRange neighborhoodRange{ *input, InputIndexType(), offsets, m_UnusedLabel };

for (const InputIndexType index : RegionIndexRange{ usableRegion })
for (const InputIndexType index : MakeIndexRange(usableRegion))
{
neighborhoodRange.SetLocation(index);
// There are sixteen different possible square types, diagrammed below.
Expand Down
4 changes: 2 additions & 2 deletions Modules/Filtering/Smoothing/include/itkMeanImageFilter.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ MeanImageFilter<TInputImage, TOutputImage>::GenerateDataInSubregion(
inputImage, Index<InputImageDimension>(), neighborhoodOffsets);
auto outputIterator = ImageRegionRange<OutputImageType>(outputImage, imageRegion).begin();

for (const auto & index : ImageRegionIndexRange<InputImageDimension>(imageRegion))
for (const auto & index : MakeIndexRange(imageRegion))
{
neighborhoodRange.SetLocation(index);

Expand Down Expand Up @@ -124,7 +124,7 @@ MeanImageFilter<TInputImage, TOutputImage>::GenerateDataInSubregion(
InputRealType sum(inputImage.GetNumberOfComponentsPerPixel());
OutputPixelType out(inputImage.GetNumberOfComponentsPerPixel());

for (const auto & index : ImageRegionIndexRange<InputImageDimension>(imageRegion))
for (const auto & index : MakeIndexRange(imageRegion))
{
neighborhoodRange.SetLocation(index);

Expand Down
4 changes: 2 additions & 2 deletions Modules/Filtering/Smoothing/include/itkMedianImageFilter.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ MedianImageFilter<TInputImage, TOutputImage>::DynamicThreadedGenerateData(
*input, Index<InputImageDimension>(), neighborhoodOffsets);
auto outputIterator = ImageRegionRange<OutputImageType>(*output, nonBoundaryRegion).begin();

for (const auto & index : ImageRegionIndexRange<InputImageDimension>(nonBoundaryRegion))
for (const auto & index : MakeIndexRange(nonBoundaryRegion))
{
neighborhoodRange.SetLocation(index);
std::copy_n(neighborhoodRange.cbegin(), neighborhoodSize, pixels.begin());
Expand All @@ -93,7 +93,7 @@ MedianImageFilter<TInputImage, TOutputImage>::DynamicThreadedGenerateData(
ShapedImageNeighborhoodRange<const InputImageType>(*input, Index<InputImageDimension>(), neighborhoodOffsets);
auto outputIterator = ImageRegionRange<OutputImageType>(*output, boundaryFace).begin();

for (const auto & index : ImageRegionIndexRange<InputImageDimension>(boundaryFace))
for (const auto & index : MakeIndexRange(boundaryFace))
{
neighborhoodRange.SetLocation(index);
std::copy_n(neighborhoodRange.cbegin(), neighborhoodSize, pixels.begin());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#include "itkContinuousIndex.h"
#include "itkDisplacementFieldTransform.h"
#include "itkImageDuplicator.h"
#include "itkImageRegionConstIteratorWithOnlyIndex.h"
#include "itkIndexRange.h"
#include "itkImportImageFilter.h"
#include "itkPointSet.h"
#include "itkResampleImageFilter.h"
Expand Down Expand Up @@ -508,12 +508,8 @@ TimeVaryingBSplineVelocityFieldImageRegistrationMethod<
fixedDisplacementField->GetRequestedRegion().GetIndex();
typename DisplacementFieldType::SizeType fixedDomainSize = fixedDisplacementField->GetRequestedRegion().GetSize();

ImageRegionConstIteratorWithOnlyIndex<DisplacementFieldType> ItF(fixedDisplacementField,
fixedDisplacementField->GetRequestedRegion());
for (ItF.GoToBegin(); !ItF.IsAtEnd(); ++ItF)
for (const auto & index : MakeIndexRange(fixedDisplacementField->GetRequestedRegion()))
{
typename DisplacementFieldType::IndexType index = ItF.GetIndex();

Comment thread
N-Dekker marked this conversation as resolved.
bool isOnBoundary = false;
for (unsigned int d = 0; d < ImageDimension; ++d)
{
Expand Down Expand Up @@ -770,13 +766,8 @@ TimeVaryingBSplineVelocityFieldImageRegistrationMethod<
typename DisplacementFieldType::SizeType gradientFieldSize = gradientField->GetRequestedRegion().GetSize();

SizeValueType localCount = 0;
for (ImageRegionConstIteratorWithOnlyIndex<DisplacementFieldType> ItG(gradientField,
gradientField->GetRequestedRegion());
!ItG.IsAtEnd();
++ItG)
for (const auto & index : MakeIndexRange(gradientField->GetRequestedRegion()))
{
typename DisplacementFieldType::IndexType index = ItG.GetIndex();

bool isOnBoundary = false;
for (SizeValueType d = 0; d < ImageDimension; ++d)
{
Expand Down
Loading