Skip to content

Commit 7536dde

Browse files
hjmjohnsonblowekamptbirdso
committed
ENH: Ingest ITKMultipleImageIterator into Modules/Core
Brings MultipleImageIterator from a configure-time remote fetch into the ITK source tree at Modules/Core/MultipleImageIterator/ using the v4 ingestion pipeline (whitelist filter-repo + per-commit clang-format + black + commit-prefix sanitization). Upstream repo: https://github.com/KitwareMedical/MultipleImageIterator.git Upstream tip: 32f67c75cce9be0ceac7876428930be64d99a57b Ingest date: 2026-05-12 Whitelist: MultipleImageIterator.list Per-commit transforms applied across all 16 commits: - filter-repo --paths-from-file (whitelist) - filter-repo --to-subdirectory-filter Modules/Core/MultipleImageIterator - clang-format -style=file (ITK main's .clang-format) for *.cxx/.h/.hxx/... - black for *.py - heuristic ITK prefix added to commit subjects without one Merge topology preserved: 8 -> 3 merge(s). Primary author: Dženan Zukić <dzenan.zukic@kitware.com> Co-authored-by: Bradley Lowekamp <blowekamp@mail.nih.gov> Co-authored-by: Hans J. Johnson <hans-johnson@uiowa.edu> Co-authored-by: Hans Johnson <hans-johnson@uiowa.edu> Co-authored-by: Hans Johnson <hans.j.johnson@gmail.com> Co-authored-by: Tom Birdsong <tom.birdsong@kitware.com>
2 parents 3915420 + 4903234 commit 7536dde

9 files changed

Lines changed: 248 additions & 0 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
project(MultipleImageIterator)
2+
3+
itk_module_impl()
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*=========================================================================
2+
*
3+
* Copyright NumFOCUS
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+
* https://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+
19+
#ifndef itkMultipleImageIterator_h
20+
#define itkMultipleImageIterator_h
21+
#include <vector>
22+
#include <itkImageRegionIterator.h>
23+
24+
25+
namespace itk
26+
{
27+
/** \class MultipleImageIterator
28+
* \brief An wrapper around image iterators to iterate over several images simultaneously
29+
* All iterators must
30+
* - point to images of the same type
31+
* - be of the same size (number of values from begin to end)
32+
* \ingroup MultipleImageIterator */
33+
template <typename TIterator>
34+
class MultipleImageIterator
35+
{
36+
public:
37+
using Self = MultipleImageIterator;
38+
using IteratorType = TIterator;
39+
using ImageType = typename IteratorType::ImageType;
40+
/// Access one of the iterators
41+
IteratorType &
42+
operator[](const int i)
43+
{
44+
return m_Iterators[i];
45+
}
46+
/// Add a new iterator
47+
void
48+
AddIterator(const IteratorType & it)
49+
{
50+
m_Iterators.push_back(it);
51+
}
52+
/// Advance all iterators
53+
Self &
54+
operator++()
55+
{
56+
for (auto it = m_Iterators.begin(); it != m_Iterators.end(); ++it)
57+
{
58+
++(*it);
59+
}
60+
return *this;
61+
}
62+
/// Rewind all iterators
63+
void
64+
GoToBegin()
65+
{
66+
for (auto it = m_Iterators.begin(); it != m_Iterators.end(); ++it)
67+
{
68+
it->GoToBegin();
69+
}
70+
}
71+
/** Check if the first iterator is at end. In debug mode, additionally check
72+
* that at least one iterator is present and that all iterators' IsAtEnd()
73+
* methods return the same thing */
74+
bool
75+
IsAtEnd()
76+
{
77+
#ifdef NDEBUG
78+
return m_Iterators[0].IsAtEnd();
79+
#else
80+
assert(m_Iterators.size());
81+
bool retval = m_Iterators[0].IsAtEnd();
82+
for (unsigned int i = 0; i < m_Iterators.size(); ++i)
83+
assert(m_Iterators[i].IsAtEnd() == retval);
84+
return retval;
85+
#endif
86+
}
87+
/// Returns the number of iterators
88+
unsigned int
89+
Size() const
90+
{
91+
return m_Iterators.size();
92+
}
93+
94+
protected:
95+
std::vector<IteratorType> m_Iterators;
96+
};
97+
} // namespace itk
98+
#endif // itkMultipleImageIterator_h
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
set(
2+
DOCUMENTATION
3+
"Several applications such as multi-atlas segmentation
4+
require frequent iteration over multiple image volumes at the same time.
5+
Doing so with the regular ITK iterators is tedious and error prone
6+
as it requires updating each iterator at end of each iteration.
7+
Failing to do so results in hard to debug errors and crashes.
8+
The MultipleImageIterator is a simple wrapper class that tries to make this more convenient.
9+
10+
A more detailed description can be found in the Insight Journal article::
11+
Schaerer J. \"A MultipleImageIterator for iterating over multiple images simultaneously\".
12+
https://hdl.handle.net/10380/3455
13+
https://www.insight-journal.org/browse/publication/915
14+
December, 2014.
15+
"
16+
)
17+
18+
itk_module(
19+
MultipleImageIterator
20+
# DEPENDS
21+
# ITKCommon
22+
COMPILE_DEPENDS
23+
ITKCommon
24+
TEST_DEPENDS
25+
ITKTestKernel
26+
EXCLUDE_FROM_DEFAULT
27+
DESCRIPTION "${DOCUMENTATION}"
28+
)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
itk_module_test()
2+
3+
set(MultipleImageIteratorTests DumpIntensities.cxx)
4+
5+
createtestdriver(MultipleImageIterator "${MultipleImageIterator-Test_LIBRARIES}" "${MultipleImageIteratorTests}")
6+
7+
itk_add_test(
8+
NAME MultipleImageIteratorTest
9+
COMMAND
10+
MultipleImageIteratorTestDriver
11+
--compare
12+
DATA{randBase.nrrd}
13+
"${ITK_TEST_OUTPUT_DIR}/randOut.nrrd"
14+
DumpIntensities
15+
"${ITK_TEST_OUTPUT_DIR}/randOut.nrrd"
16+
DATA{img1.png}
17+
DATA{img2.png}
18+
DATA{img3.png}
19+
)
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*=========================================================================
2+
*
3+
* Copyright NumFOCUS
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+
* https://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+
19+
#include <iostream>
20+
#include <vector>
21+
#include <string>
22+
#include <cstdlib>
23+
#include <itkImageFileReader.h>
24+
#include <itkImageFileWriter.h>
25+
#include "itkMultipleImageIterator.h"
26+
27+
// Dumps random samples from files into a csv file
28+
using namespace std;
29+
30+
int
31+
DumpIntensities(int argc, char * argv[])
32+
{
33+
if (argc < 3)
34+
{
35+
cerr << "Usage: DumpIntensities outfile inImage [inImage ...]" << endl;
36+
return 1;
37+
}
38+
using PixelType = unsigned short;
39+
using ImageType = itk::Image<PixelType, 3>;
40+
using ReaderType = itk::ImageFileReader<ImageType>;
41+
42+
using IteratorType = itk::ImageRegionIterator<ImageType>;
43+
itk::MultipleImageIterator<IteratorType> it;
44+
45+
vector<ImageType::Pointer> images; // Need to keep a reference as iterators only have weak references
46+
for (int i = 2; i < argc; ++i)
47+
{
48+
ReaderType::Pointer r = ReaderType::New();
49+
r->SetFileName(argv[i]);
50+
r->Update();
51+
ImageType::Pointer im = r->GetOutput();
52+
im->DisconnectPipeline();
53+
images.push_back(im);
54+
it.AddIterator(itk::ImageRegionIterator<ImageType>(im, im->GetLargestPossibleRegion()));
55+
}
56+
57+
unsigned long long c = 0;
58+
using Vec3 = itk::FixedArray<PixelType, 3>;
59+
vector<Vec3> values;
60+
for (it.GoToBegin(); !it.IsAtEnd(); ++it, ++c)
61+
{
62+
if (c % 42 == 0)
63+
{
64+
Vec3 v;
65+
for (unsigned int i = 0; i < it.Size(); ++i)
66+
{
67+
v[i] = it[i].Get();
68+
}
69+
values.push_back(v);
70+
}
71+
}
72+
73+
using Image1D = itk::Image<Vec3, 1>;
74+
Image1D::RegionType region;
75+
region.SetIndex(0, 0);
76+
region.SetSize(0, values.size());
77+
Image1D::Pointer randImage = Image1D::New();
78+
randImage->SetRegions(region);
79+
randImage->Allocate();
80+
81+
int index = 0;
82+
itk::ImageRegionIterator<Image1D> oIt(randImage, randImage->GetLargestPossibleRegion());
83+
while (!oIt.IsAtEnd())
84+
{
85+
oIt.Set(values[index++]);
86+
++oIt;
87+
}
88+
89+
using WriterType = itk::ImageFileWriter<Image1D>;
90+
WriterType::Pointer writer = WriterType::New();
91+
writer->SetInput(randImage);
92+
writer->SetFileName(argv[1]);
93+
writer->Update();
94+
95+
return 0;
96+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bafkreicd6xi33oatbqzspxkeszliv3mmjnnmiiu6dj6qj6wuclkv7uokda
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bafkreiactetnzqheknc2zjeg6aoo6y7uqbid7oukpwttfjuj52stok6wbe
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bafkreibqkbie3ezhl2y2kvgfizpoj5qfz3y5xdbe5rqtjo35pb5zn5geti
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bafkreihso7ziayrcpwm22dbjctew7ju3a7egxdyoytdn4ueuwggu26tscq

0 commit comments

Comments
 (0)