Skip to content

Commit f18535d

Browse files
blowekampthewtex
authored andcommitted
ENH: Add test for bug related reusing TIFFImageIO
Reusing a TIFFImageIO object in the image series reader causes the incorrect slice to be read.
1 parent 1a24156 commit f18535d

File tree

3 files changed

+151
-3
lines changed

3 files changed

+151
-3
lines changed

Modules/IO/ImageBase/test/CMakeLists.txt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,6 @@ itk_add_test(
933933
COMMAND
934934
itkUnicodeIOTest)
935935

936-
set(ITKIOImageBaseGTests itkWriteImageFunctionGTest.cxx)
936+
set(ITKIOImageBaseGTests itkWriteImageFunctionGTest.cxx
937+
)
937938
creategoogletestdriver(ITKIOImageBase "${ITKIOImageBase-Test_LIBRARIES}" "${ITKIOImageBaseGTests}")
938-
939-
target_compile_definitions(ITKIOImageBaseGTestDriver PRIVATE "-DITK_TEST_OUTPUT_DIR=${ITK_TEST_OUTPUT_DIR}")

Modules/IO/TIFF/test/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,3 +632,12 @@ itk_add_test(
632632
ITKIOTIFFTestDriver
633633
itkTIFFImageIOIntPixelTest
634634
DATA{Input/int.tiff})
635+
636+
# Add GTest for TIFF module
637+
set(ITKIOTIFFGTests
638+
itkImageSeriesReaderReverse.cxx
639+
)
640+
creategoogletestdriver(ITKIOTIFF "${ITKIOTIFF-Test_LIBRARIES}" "${ITKIOTIFFGTests}")
641+
642+
643+
target_compile_definitions(ITKIOTIFFGTestDriver PRIVATE "-DITK_TEST_OUTPUT_DIR=${ITK_TEST_OUTPUT_DIR}")
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
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 "itkImageSeriesWriter.h"
20+
#include "itkImageSeriesReader.h"
21+
#include "itkImage.h"
22+
#include "itkTIFFImageIO.h"
23+
24+
#include "itkGTest.h"
25+
#include "itksys/SystemTools.hxx"
26+
#include "itkTestDriverIncludeRequiredFactories.h"
27+
#include <string>
28+
29+
30+
#define _STRING(s) #s
31+
#define TOSTRING(s) std::string(_STRING(s))
32+
33+
namespace
34+
{
35+
36+
struct ITKIOTIFF : public ::testing::Test
37+
{
38+
void
39+
SetUp() override
40+
{
41+
RegisterRequiredFactories();
42+
43+
itksys::SystemTools::MakeDirectory(m_TempDir);
44+
}
45+
46+
void
47+
TearDown() override
48+
{
49+
// Remove the temporary directory and its contents
50+
itksys::SystemTools::RemoveADirectory(m_TempDir);
51+
}
52+
53+
std::string m_TempDir = TOSTRING(ITK_TEST_OUTPUT_DIR) + "/ImageSeriesReader.ReverseOrder";
54+
55+
56+
template <typename PixelType>
57+
typename itk::Image<PixelType, 3>::Pointer
58+
MakeImage(unsigned int z_size)
59+
{
60+
using ImageType = itk::Image<PixelType, 3>;
61+
62+
typename ImageType::Pointer img = ImageType::New();
63+
typename ImageType::SizeType size = { { 32, 32, z_size } };
64+
typename ImageType::RegionType region;
65+
region.SetSize(size);
66+
img->SetRegions(region);
67+
img->Allocate();
68+
img->FillBuffer(0);
69+
70+
for (unsigned int z = 0; z < z_size; ++z)
71+
{
72+
for (unsigned int y = 0; y < 32; ++y)
73+
for (unsigned int x = 0; x < 32; ++x)
74+
{
75+
typename ImageType::IndexType idx = { { x, y, z } };
76+
img->SetPixel(idx, static_cast<PixelType>(1 + z * 5));
77+
}
78+
}
79+
return img;
80+
}
81+
};
82+
83+
84+
} // namespace
85+
86+
TEST_F(ITKIOTIFF, ReverseOrder_with_ImageIO)
87+
{
88+
89+
90+
// Create a series of 3 TIFF files with different values using native itk::Image
91+
const unsigned int z_size = 3;
92+
using PixelType = unsigned char;
93+
constexpr unsigned int Dimension = 3;
94+
using ImageType = itk::Image<PixelType, Dimension>;
95+
96+
97+
auto img = MakeImage<PixelType>(z_size);
98+
99+
std::vector<std::string> filePaths;
100+
for (unsigned int z = 0; z < z_size; ++z)
101+
{
102+
std::ostringstream oss;
103+
oss << m_TempDir << "/test_reader_kwargs_" << z << ".tiff";
104+
filePaths.push_back(oss.str());
105+
}
106+
{
107+
// Create an ImageSeriesWriter to write the series of images
108+
auto writer = itk::ImageSeriesWriter<
109+
ImageType,
110+
typename ImageType::RebindImageType<ImageType::PixelType, ImageType::ImageDimension - 1>>::New();
111+
writer->SetFileNames(filePaths);
112+
writer->SetInput(img);
113+
writer->Update();
114+
}
115+
116+
// Create ImageIO for TIFF
117+
auto imageIO = itk::TIFFImageIO::New();
118+
119+
// Test reading with ReverseOrder=True
120+
auto reader = itk::ImageSeriesReader<ImageType>::New();
121+
reader->SetImageIO(imageIO);
122+
reader->SetFileNames(filePaths);
123+
reader->SetReverseOrder(true);
124+
reader->Update();
125+
ImageType::Pointer reversed_img = reader->GetOutput();
126+
127+
128+
// Print the value at 0,0 of each slice for the two images
129+
for (unsigned int z = 0; z < z_size; ++z)
130+
{
131+
132+
ImageType::IndexType idx{ { 31, 31, z } };
133+
auto actual = reversed_img->GetPixel(idx);
134+
135+
idx[2] = z_size - 1 - z;
136+
auto expected = img->GetPixel(idx);
137+
138+
EXPECT_EQ(static_cast<int>(expected), static_cast<int>(actual)) << "Slice " << z << " value mismatch";
139+
}
140+
}

0 commit comments

Comments
 (0)