From ceb157d634d7e4801781c92ea8e04b27621845ec Mon Sep 17 00:00:00 2001 From: Niels Dekker Date: Thu, 6 Aug 2020 10:14:49 +0200 Subject: [PATCH] BUG: Fix issue #1950, ImageMaskSpatialObject access outside image buffer Fixed issue #1950, "ImageMaskSpatialObject tries to access pixels outside the image buffer (segfault)". In the original code, `TransformPhysicalPointToContinuousIndex` did estimate whether the specified point was inside the image buffer, but then `GetInterpolator()->EvaluateAtContinuousIndex(index)` did in some cases still try to access a pixel outside the image buffer. This fix avoids using an interpolator. It only accesses a pixel when its index is inside the buffered region. The use of an interpolator appears less relevant for an image mask than for other spatial objects, as for each mask pixel value, it is usually only interesting to know whether it is zero or non-zero. Added ImageMaskSpatialObject.CornerPointIsNotInsideMaskOfZeroValues unit test. --- .../include/itkImageMaskSpatialObject.hxx | 18 +++++------------- .../test/itkImageMaskSpatialObjectGTest.cxx | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Modules/Core/SpatialObjects/include/itkImageMaskSpatialObject.hxx b/Modules/Core/SpatialObjects/include/itkImageMaskSpatialObject.hxx index 85a2cbdfbe5..94b0148675a 100644 --- a/Modules/Core/SpatialObjects/include/itkImageMaskSpatialObject.hxx +++ b/Modules/Core/SpatialObjects/include/itkImageMaskSpatialObject.hxx @@ -40,20 +40,12 @@ template bool ImageMaskSpatialObject::IsInsideInObjectSpace(const PointType & point) const { - typename Superclass::InterpolatorType::ContinuousIndexType index; - if (this->GetImage()->TransformPhysicalPointToContinuousIndex(point, index)) - { - using InterpolatorOutputType = typename InterpolatorType::OutputType; - bool insideMask = (Math::NotExactlyEquals(DefaultConvertPixelTraits::GetScalarValue( - this->GetInterpolator()->EvaluateAtContinuousIndex(index)), - NumericTraits::ZeroValue())); - if (insideMask) - { - return true; - } - } + const ImageType * const image = this->GetImage(); + + const IndexType index = image->TransformPhysicalPointToIndex(point); - return false; + return image->GetBufferedRegion().IsInside(index) && + Math::NotExactlyEquals(image->GetPixel(index), NumericTraits::ZeroValue()); } diff --git a/Modules/Core/SpatialObjects/test/itkImageMaskSpatialObjectGTest.cxx b/Modules/Core/SpatialObjects/test/itkImageMaskSpatialObjectGTest.cxx index b04a86cba50..d6715fd855e 100644 --- a/Modules/Core/SpatialObjects/test/itkImageMaskSpatialObjectGTest.cxx +++ b/Modules/Core/SpatialObjects/test/itkImageMaskSpatialObjectGTest.cxx @@ -306,3 +306,20 @@ TEST(ImageMaskSpatialObject, IsInsideIndependentOfDistantPixels) #endif + + +// Tests that IsInsideInObjectSpace returns false for a corner point, when the +// mask image is filled with zero values. This test would sometimes fail on +// ITK v5.0.1 and v5.1.0 +TEST(ImageMaskSpatialObject, CornerPointIsNotInsideMaskOfZeroValues) +{ + // Create a mask image, and fill the image with zero vales. + const auto image = itk::Image::New(); + image->SetRegions(itk::Size<>{ { 2, 2 } }); + image->Allocate(true); + + const auto imageMaskSpatialObject = itk::ImageMaskSpatialObject<2>::New(); + imageMaskSpatialObject->SetImage(image); + const double cornerPoint[] = { 1.5, 1.5 }; + ASSERT_FALSE(imageMaskSpatialObject->IsInsideInObjectSpace(cornerPoint)); +}