Skip to content

Commit

Permalink
BUG: incorrect neighbor determination in scan-line derived filters
Browse files Browse the repository at this point in the history
Thanks to @DVigneault for finding the bug and creating a MWE to demonstrate it
  • Loading branch information
dzenanz committed Feb 4, 2020
1 parent 5671480 commit c32a784
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 1 deletion.
11 changes: 10 additions & 1 deletion Modules/Filtering/ImageLabel/include/itkScanlineFilterCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,12 +236,21 @@ class ScanlineFilterCommon
{
// This checks whether the line encodings are really neighbors. The first
// dimension gets ignored because the encodings are along that axis.
SizeValueType diffSum = 0;
for (unsigned i = 1; i < OutputImageDimension; i++)
{
if (Math::abs(A[i] - B[i]) > 1)
SizeValueType diff = Math::abs(A[i] - B[i]);
if (diff > 1)
{
return false;
}
diffSum += diff;
}

assert(diffSum > 0); // we are checking potential neighbors, index difference must exist
if (!this->m_FullyConnected)
{
return (diffSum <= 1); // indices can differ only along one dimension
}
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,6 @@ itk_add_test(NAME itkMaskConnectedComponentImageFilterTest

set(ITKConnectedComponentsGTests
itkRelabelComponentImageFilterGTest.cxx
itkConnectedComponentImageFilterGTest.cxx
)
CreateGoogleTestDriver(ITKConnectedComponents "${ITKConnectedComponents-Test_LIBRARIES}" "${ITKConnectedComponentsGTests}")
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*=========================================================================
*
* Copyright Insight Software Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*=========================================================================*/


#include "itkPrintHelper.h"
using itk::print_helper::operator<<;

#include "itkGTest.h"
#include "itkImage.h"
#include "itkConnectedComponentImageFilter.h"

#include <bitset>

namespace
{
typename itk::Image<unsigned char, 3>::Pointer
CreateTestImageA(void)
{
std::bitset<8> bits(105); // 3D Checkerboard: 01101001

using namespace itk::GTest::TypedefsAndConstructors::Dimension3;

using PixelType = unsigned char;
using ImageType = itk::Image<PixelType, Dimension>;

auto image = ImageType::New();
image->SetRegions(ImageType::RegionType(MakeSize(2u, 2u, 2u)));
image->Allocate(true);

for (size_t i = 0; i < 8; ++i)
{
std::bitset<3> idx(i);
image->SetPixel({ { idx[0], idx[1], idx[2] } }, bits[i]);
}

return image;
}
} // namespace


TEST(ConnectedComponentImageFilter, checkerboard_3D)
{
auto image = CreateTestImageA();
using ImageType = decltype(image)::ObjectType;

auto connected = itk::ConnectedComponentImageFilter<ImageType, ImageType>::New();
connected->SetInput(image);
connected->FullyConnectedOff();
connected->Update();

itk::ImageRegionConstIterator<ImageType> it(connected->GetOutput(),
connected->GetOutput()->GetLargestPossibleRegion());

EXPECT_EQ(it.Get(), 1);
++it;
EXPECT_EQ(it.Get(), 0);
++it;
EXPECT_EQ(it.Get(), 0);
++it;
EXPECT_EQ(it.Get(), 2);
++it;
EXPECT_EQ(it.Get(), 0);
++it;
EXPECT_EQ(it.Get(), 3);
++it;
EXPECT_EQ(it.Get(), 4);
++it;
EXPECT_EQ(it.Get(), 0);
++it;
EXPECT_TRUE(it.IsAtEnd());
}

0 comments on commit c32a784

Please sign in to comment.