From 7c2523a77275317dbd1d104897ef5b6b782e7a8c Mon Sep 17 00:00:00 2001 From: Niels Dekker Date: Tue, 7 May 2019 15:35:15 +0200 Subject: [PATCH] ENH: Replace elastix ImageSpatialObject2 by ITK ImageSpatialObject Replaced elastix specific `ImageSpatialObject2` and `ImageMaskSpatialObject2` by ITK's `ImageSpatialObject` and `ImageMaskSpatialObject`, respectively. Let azure CI build with the ITK5 version of May 9, 2019 (from ITK git master branch). Added Mask->Update() calls to `MultiResolutionRegistration::UpdateMasks`, to ensure that the bounding boxes are computed. Removed elementary GoogleTest for `ImageMaskSpatialObject2`. Removed failing 3DCT_lung.MI.bspline.SGD.004 test for ITK4 (it passes on ITK5) Part of the elastix upgrade to ITKv5. --- Common/CMakeLists.txt | 4 - .../itkAdvancedImageToImageMetric.h | 6 +- Common/GTesting/CMakeLists.txt | 1 - .../itkImageMaskSpatialObject2GTest.cxx | 46 -- Common/ImageSamplers/itkImageSamplerBase.hxx | 4 + Common/itkComputeImageExtremaFilter.h | 4 +- Common/itkImageMaskSpatialObject2.h | 131 ------ Common/itkImageMaskSpatialObject2.hxx | 350 --------------- Common/itkImageSpatialObject2.h | 171 -------- Common/itkImageSpatialObject2.hxx | 411 ------------------ .../elxMultiResolutionRegistration.hxx | 10 + .../elxRegistrationBase.h | 6 +- Testing/CI/Azure/ci.yml | 2 +- Testing/CMakeLists.txt | 16 +- 14 files changed, 32 insertions(+), 1130 deletions(-) delete mode 100644 Common/GTesting/itkImageMaskSpatialObject2GTest.cxx delete mode 100644 Common/itkImageMaskSpatialObject2.h delete mode 100644 Common/itkImageMaskSpatialObject2.hxx delete mode 100644 Common/itkImageSpatialObject2.h delete mode 100644 Common/itkImageSpatialObject2.hxx diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt index 8144777f5..aeb6e7b68 100644 --- a/Common/CMakeLists.txt +++ b/Common/CMakeLists.txt @@ -34,10 +34,6 @@ set( CommonFiles itkGenericMultiResolutionPyramidImageFilter.hxx itkImageFileCastWriter.h itkImageFileCastWriter.hxx - itkImageMaskSpatialObject2.h - itkImageMaskSpatialObject2.hxx - itkImageSpatialObject2.h - itkImageSpatialObject2.hxx itkMeshFileReaderBase.h itkMeshFileReaderBase.hxx itkMultiOrderBSplineDecompositionImageFilter.h diff --git a/Common/CostFunctions/itkAdvancedImageToImageMetric.h b/Common/CostFunctions/itkAdvancedImageToImageMetric.h index 37b40ae4e..3828b3ca5 100644 --- a/Common/CostFunctions/itkAdvancedImageToImageMetric.h +++ b/Common/CostFunctions/itkAdvancedImageToImageMetric.h @@ -30,7 +30,7 @@ #include "itkAdvancedTransform.h" #include "vnl/vnl_sparse_matrix.h" -#include "itkImageMaskSpatialObject2.h" +#include "itkImageMaskSpatialObject.h" // Needed for checking for B-spline for faster implementation #include "itkAdvancedBSplineDeformableTransform.h" @@ -131,8 +131,8 @@ class AdvancedImageToImageMetric : typedef typename DerivativeType::ValueType DerivativeValueType; typedef typename Superclass::ParametersType ParametersType; - typedef ImageMaskSpatialObject2< itkGetStaticConstMacro( FixedImageDimension ) > FixedImageMaskSpatialObject2Type; - typedef ImageMaskSpatialObject2< itkGetStaticConstMacro( MovingImageDimension ) > MovingImageMaskSpatialObject2Type; + typedef ImageMaskSpatialObject< itkGetStaticConstMacro( FixedImageDimension ) > FixedImageMaskSpatialObject2Type; + typedef ImageMaskSpatialObject< itkGetStaticConstMacro( MovingImageDimension ) > MovingImageMaskSpatialObject2Type; /** Some useful extra typedefs. */ typedef typename FixedImageType::PixelType FixedImagePixelType; diff --git a/Common/GTesting/CMakeLists.txt b/Common/GTesting/CMakeLists.txt index c4a76d370..3c84e24c8 100644 --- a/Common/GTesting/CMakeLists.txt +++ b/Common/GTesting/CMakeLists.txt @@ -1,6 +1,5 @@ add_executable(CommonGTest itkComputeImageExtremaFilterGTest.cxx - itkImageMaskSpatialObject2GTest.cxx ) target_link_libraries(CommonGTest GTest::GTest GTest::Main diff --git a/Common/GTesting/itkImageMaskSpatialObject2GTest.cxx b/Common/GTesting/itkImageMaskSpatialObject2GTest.cxx deleted file mode 100644 index f2de7d0f3..000000000 --- a/Common/GTesting/itkImageMaskSpatialObject2GTest.cxx +++ /dev/null @@ -1,46 +0,0 @@ -/*========================================================================= - * - * Copyright UMC Utrecht and contributors - * - * 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. - * - *=========================================================================*/ - - -// First include the header file to be tested: -#include "itkImageMaskSpatialObject2.h" - -#include - -namespace -{ - template - void Expect_New_returns_valid_ImageMaskSpatialObject2_Pointer() - { - using Type = itk::ImageMaskSpatialObject2; - - static_assert( - std::is_same::value, - "Type::New() should return a Type::Pointer"); - - EXPECT_NE(Type::New(), nullptr); - } -} - -GTEST_TEST(ImageMaskSpatialObject2, NewReturnsValidPointer) -{ - Expect_New_returns_valid_ImageMaskSpatialObject2_Pointer<1>(); - Expect_New_returns_valid_ImageMaskSpatialObject2_Pointer<2>(); - Expect_New_returns_valid_ImageMaskSpatialObject2_Pointer<3>(); -} - diff --git a/Common/ImageSamplers/itkImageSamplerBase.hxx b/Common/ImageSamplers/itkImageSamplerBase.hxx index dee5222a1..6132d8ea2 100644 --- a/Common/ImageSamplers/itkImageSamplerBase.hxx +++ b/Common/ImageSamplers/itkImageSamplerBase.hxx @@ -351,7 +351,11 @@ ImageSamplerBase< TInputImage > typedef typename MaskType::BoundingBoxType BoundingBoxType; typedef typename BoundingBoxType::PointsContainer PointsContainerType; +#if ITK_VERSION_MAJOR < 5 typename BoundingBoxType::Pointer bb = this->m_Mask->GetBoundingBox(); +#else + typename BoundingBoxType::ConstPointer bb = this->m_Mask->GetMyBoundingBoxInWorldSpace(); +#endif typename BoundingBoxType::Pointer bbIndex = BoundingBoxType::New(); const PointsContainerType * cornersWorld = bb->GetPoints(); typename PointsContainerType::Pointer cornersIndex = PointsContainerType::New(); diff --git a/Common/itkComputeImageExtremaFilter.h b/Common/itkComputeImageExtremaFilter.h index 4ff7dd38b..79a26ce0d 100644 --- a/Common/itkComputeImageExtremaFilter.h +++ b/Common/itkComputeImageExtremaFilter.h @@ -20,7 +20,7 @@ #include "itkStatisticsImageFilter.h" #include "itkSpatialObject.h" -#include "itkImageMaskSpatialObject2.h" +#include "itkImageMaskSpatialObject.h" namespace itk { @@ -86,7 +86,7 @@ class ComputeImageExtremaFilter : itkSetConstObjectMacro( ImageMask, ImageMaskType ); itkGetConstObjectMacro( ImageMask, ImageMaskType ); - typedef ImageMaskSpatialObject2< itkGetStaticConstMacro(ImageDimension) > ImageSpatialMaskType; + typedef ImageMaskSpatialObject< itkGetStaticConstMacro(ImageDimension) > ImageSpatialMaskType; typedef typename ImageSpatialMaskType::Pointer ImageSpatialMaskPointer; typedef typename ImageSpatialMaskType::ConstPointer ImageSpatialMaskConstPointer; itkSetConstObjectMacro( ImageSpatialMask, ImageSpatialMaskType ); diff --git a/Common/itkImageMaskSpatialObject2.h b/Common/itkImageMaskSpatialObject2.h deleted file mode 100644 index 9904e5dc7..000000000 --- a/Common/itkImageMaskSpatialObject2.h +++ /dev/null @@ -1,131 +0,0 @@ -/*========================================================================= - * - * Copyright UMC Utrecht and contributors - * - * 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. - * - *=========================================================================*/ - -/** This file is a slightly modified version of an ITK file. - * Original ITK copyright message: */ -/*========================================================================= - - Program: Insight Segmentation & Registration Toolkit - Module: $RCSfile$ - Language: C++ - Date: $Date: 2008-05-28 10:45:42 +0200 (Wed, 28 May 2008) $ - Version: $Revision: 1636 $ - - Copyright (c) Insight Software Consortium. All rights reserved. - See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. - - This software is distributed WITHOUT ANY WARRANTY; without even - the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - PURPOSE. See the above copyright notices for more information. - -=========================================================================*/ -#ifndef __itkImageMaskSpatialObject2_h -#define __itkImageMaskSpatialObject2_h - -#include "itkImageSpatialObject2.h" -#include "itkImageSliceConstIteratorWithIndex.h" - -namespace itk -{ - -/** \class ImageMaskSpatialObject2 - * \brief Implementation of an image mask as spatial object. - * - * This class fixes a bug in the ITK. The ITK has implemented - * the ImageSpatialObject with a wrong conversion between physical - * coordinates and image coordinates. This class solves that. - * - */ - -template< unsigned int TDimension = 3 > -class ImageMaskSpatialObject2 : - public ImageSpatialObject2< TDimension, unsigned char > -{ - -public: - - typedef ImageMaskSpatialObject2< TDimension > Self; - typedef ImageSpatialObject2< TDimension > Superclass; - typedef SmartPointer< Self > Pointer; - typedef SmartPointer< const Self > ConstPointer; - - typedef typename Superclass::ScalarType ScalarType; - typedef typename Superclass::PixelType PixelType; - typedef typename Superclass::ImageType ImageType; - typedef typename Superclass::ImagePointer ImagePointer; - typedef typename Superclass::IndexType IndexType; - typedef typename Superclass::SizeType SizeType; - typedef typename Superclass::RegionType RegionType; - typedef typename Superclass::TransformType TransformType; - typedef typename Superclass::PointType PointType; - typedef typename Superclass::BoundingBoxType BoundingBoxType; - - typedef itk::ImageSliceConstIteratorWithIndex< ImageType > - SliceIteratorType; - - /** Method for creation through the object factory. */ - itkNewMacro( Self ); - - /** Run-time type information (and related methods). */ - itkTypeMacro( ImageMaskSpatialObject2, ImageSpatialObject2 ); - - /** Returns true if the point is inside, false otherwise. */ - bool IsInside( const PointType & point, - unsigned int depth, char * name ) const override; - - /** Test whether a point is inside or outside the object - * For computational speed purposes, it is faster if the method does not - * check the name of the class and the current depth */ - virtual bool IsInside( const PointType & point ) const; - - /** Compute axis aligned bounding box from the image mask. The bounding box - * is returned as an image region. Each call to this function will recompute - * the region. This function is useful in cases, where you may have a mask image - * resulting from say a segmentation and you want to get the smallest box - * region that encapsulates the mask image. Currently this is done only for 3D - * volumes. */ - RegionType GetAxisAlignedBoundingBoxRegion() const; - - /** Compute the boundaries of the image mask spatial object. */ - bool ComputeLocalBoundingBox() const override; - - /** Helper function for GetAxisAlignedBoundingBoxRegion() - * and ComputeLocalBoundingBox(). - */ - void ComputeLocalBoundingBoxIndexAndSize( - IndexType & index, SizeType & size ) const; - -protected: - - ImageMaskSpatialObject2( const Self & ); // purposely not implemented - void operator=( const Self & ); // purposely not implemented - - ImageMaskSpatialObject2(); - ~ImageMaskSpatialObject2() override; - - void PrintSelf( std::ostream & os, Indent indent ) const override; - -}; - -} // end of namespace itk - -#ifndef ITK_MANUAL_INSTANTIATION -#include "itkImageMaskSpatialObject2.hxx" -#endif - -#endif //__itkImageMaskSpatialObject2_h diff --git a/Common/itkImageMaskSpatialObject2.hxx b/Common/itkImageMaskSpatialObject2.hxx deleted file mode 100644 index 2faa51af6..000000000 --- a/Common/itkImageMaskSpatialObject2.hxx +++ /dev/null @@ -1,350 +0,0 @@ -/*========================================================================= - * - * Copyright UMC Utrecht and contributors - * - * 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. - * - *=========================================================================*/ - -/** This file is a slightly modified version of an ITK file. - * Original ITK copyright message: */ -/*========================================================================= - - Program: Insight Segmentation & Registration Toolkit - Module: $RCSfile$ - Language: C++ - Date: $Date: 2008-05-29 12:02:25 +0200 (Thu, 29 May 2008) $ - Version: $Revision: 1641 $ - - Copyright (c) Insight Software Consortium. All rights reserved. - See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. - - This software is distributed WITHOUT ANY WARRANTY; without even - the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - PURPOSE. See the above copyright notices for more information. - -=========================================================================*/ -#ifndef __ImageMaskSpatialObject2_hxx -#define __ImageMaskSpatialObject2_hxx - -#include "itkImageMaskSpatialObject2.h" -#include "vnl/vnl_math.h" - -#include "itkImageRegionConstIteratorWithIndex.h" - -namespace itk -{ - -/** Constructor */ -template< unsigned int TDimension > -ImageMaskSpatialObject2< TDimension > -::ImageMaskSpatialObject2() -{ - this->SetTypeName( "ImageMaskSpatialObject2" ); - this->ComputeBoundingBox(); -} - - -/** Destructor */ -template< unsigned int TDimension > -ImageMaskSpatialObject2< TDimension > -::~ImageMaskSpatialObject2() -{} - -/** Test whether a point is inside or outside the object -* For computational speed purposes, it is faster if the method does not -* check the name of the class and the current depth */ -template< unsigned int TDimension > -bool -ImageMaskSpatialObject2< TDimension > -::IsInside( const PointType & point ) const -{ - if( !this->SetInternalInverseTransformToWorldToIndexTransform() ) - { - return false; - } - - PointType p = this->GetInternalInverseTransform()->TransformPoint( point ); - - IndexType index; - for( unsigned int i = 0; i < TDimension; i++ ) - { - //index[i] = static_cast( p[i] ); // changed by stefan - index[ i ] = static_cast< int >( Math::Round< double >( p[ i ] ) ); - } - - const bool insideBuffer - = this->GetImage()->GetBufferedRegion().IsInside( index ); - - if( !insideBuffer ) - { - return false; - } - - const bool insideMask - = ( this->GetImage()->GetPixel( index ) != NumericTraits< PixelType >::ZeroValue() ); - - return insideMask; - -} - - -/** Return true if the given point is inside the image */ -template< unsigned int TDimension > -bool -ImageMaskSpatialObject2< TDimension > -::IsInside( const PointType & point, unsigned int depth, char * name ) const -{ - if( name == NULL ) - { - if( IsInside( point ) ) - { - return true; - } - } - else if( strstr( typeid( Self ).name(), name ) ) - { - if( IsInside( point ) ) - { - return true; - } - } - return SpatialObject< TDimension >::IsInside( point, depth, name ); -} - - -// is this one correct? (stefan). -template< unsigned int TDimension > -typename ImageMaskSpatialObject2< TDimension >::RegionType -ImageMaskSpatialObject2< TDimension > -::GetAxisAlignedBoundingBoxRegion() const -{ - /** Compute index and size of the bounding box. */ - IndexType index; - SizeType size; - this->ComputeLocalBoundingBoxIndexAndSize( index, size ); - - /** Define and return region. */ - RegionType region; - region.SetIndex( index ); - region.SetSize( size ); - - return region; - -} // end GetAxisAlignedBoundingBoxRegion() - - -template< unsigned int TDimension > -void -ImageMaskSpatialObject2< TDimension > -::ComputeLocalBoundingBoxIndexAndSize( - IndexType & index, SizeType & size ) const -{ - // We will use a slice iterator to iterate through slices orthogonal - // to each of the axis of the image to find the bounding box. Each - // slice iterator iterates from the outermost slice towards the image - // center till it finds a mask pixel. For a 3D image, there will be six - // slice iterators, iterating from the periphery inwards till the bounds - // along each axes are found. The slice iterators save time and avoid - // having to walk the whole image. Since we are using slice iterators, - // we will implement this only for 3D images. - - ImagePointer image = this->GetImage(); - PixelType outsideValue = NumericTraits< PixelType >::Zero; - - // Initialize index and size in case image only consists of background values. - for( unsigned int axis = 0; axis < ImageType::ImageDimension; ++axis ) - { - index[ axis ] = 0; - size[ axis ] = 0; - } - - /** For 3D a smart implementation existed in the ITK already. */ - if( ImageType::ImageDimension == 3 ) - { - for( unsigned int axis = 0; axis < ImageType::ImageDimension; axis++ ) - { - // Two slice iterators along each axis... - // Find the orthogonal planes for the slices - unsigned int i, j; - unsigned int direction[ 2 ]; - for( i = 0, j = 0; i < 3; ++i ) - { - if( i != axis ) - { - direction[ j ] = i; - j++; - } - } - - // Create the forward iterator to find lower bound - SliceIteratorType fit( image, image->GetRequestedRegion() ); - fit.SetFirstDirection( direction[ 1 ] ); - fit.SetSecondDirection( direction[ 0 ] ); - - fit.GoToBegin(); - while( !fit.IsAtEnd() ) - { - while( !fit.IsAtEndOfSlice() ) - { - while( !fit.IsAtEndOfLine() ) - { - if( fit.Get() != outsideValue ) - { - index[ axis ] = fit.GetIndex()[ axis ]; - fit.GoToReverseBegin(); // skip to the end - break; - } - ++fit; - } - fit.NextLine(); - } - fit.NextSlice(); - } - - // Create the reverse iterator to find upper bound - SliceIteratorType rit( image, image->GetRequestedRegion() ); - rit.SetFirstDirection( direction[ 1 ] ); - rit.SetSecondDirection( direction[ 0 ] ); - - rit.GoToReverseBegin(); - while( !rit.IsAtReverseEnd() ) - { - while( !rit.IsAtReverseEndOfSlice() ) - { - while( !rit.IsAtReverseEndOfLine() ) - { - if( rit.Get() != outsideValue ) - { - //size[ axis ] = rit.GetIndex()[ axis ] - index[ axis ]; // changed by Marius - size[ axis ] = rit.GetIndex()[ axis ] - index[ axis ] + 1; - rit.GoToBegin(); //Skip to reverse end - break; - } - --rit; - } - rit.PreviousLine(); - } - rit.PreviousSlice(); - } - } - } - // We added a naive implementation for images of dimension other than 3 - else - { - typedef ImageRegionConstIteratorWithIndex< ImageType > IteratorType; - IteratorType it( image, image->GetRequestedRegion() ); - it.GoToBegin(); - IndexType endindex; - - for( unsigned int i = 0; i < ImageType::ImageDimension; ++i ) - { - // modified by stefan; old (commented) implemenation assumed zero start index - index[ i ] = image->GetRequestedRegion().GetIndex( i ) + image->GetRequestedRegion().GetSize( i ) - 1; - //index[ i ] = image->GetRequestedRegion().GetSize( i ); - endindex[ i ] = image->GetRequestedRegion().GetIndex( i ); - //size[ i ] = image->GetRequestedRegion().GetIndex( i ); - } - - while( !it.IsAtEnd() ) - { - if( it.Get() != outsideValue ) - { - IndexType tmpIndex = it.GetIndex(); - for( unsigned int i = 0; i < ImageType::ImageDimension; ++i ) - { - index[ i ] = index[ i ] < tmpIndex[ i ] ? index[ i ] : tmpIndex[ i ]; - //size[ i ] = static_cast( size[ i ] ) > tmpIndex[ i ] ? size[ i ] : tmpIndex[ i ]; - endindex[ i ] = endindex[ i ] > tmpIndex[ i ] ? endindex[ i ] : tmpIndex[ i ]; - } - } - ++it; - } - - for( unsigned int i = 0; i < ImageType::ImageDimension; ++i ) - { - //size[ i ] = size[ i ] - index[ i ] + 1; - size[ i ] = endindex[ i ] - index[ i ] + 1; - } - } // end else - -} // end ComputeLocalBoundingBoxIndexAndSize() - - -/** Compute the bounds of the image */ -template< unsigned int TDimension > -bool -ImageMaskSpatialObject2< TDimension > -::ComputeLocalBoundingBox() const -{ - if( this->GetBoundingBoxChildrenName().empty() - || strstr( typeid( Self ).name(), - this->GetBoundingBoxChildrenName().c_str() ) ) - { - /** Compute index and size of the bounding box. */ - IndexType indexLow; - SizeType size; - this->ComputeLocalBoundingBoxIndexAndSize( indexLow, size ); - - /** Convert to points, which are NOT physical points! */ - PointType pointLow, pointHigh; - for( unsigned int i = 0; i < ImageType::ImageDimension; ++i ) - { - pointLow[ i ] = indexLow[ i ]; - pointHigh[ i ] = indexLow[ i ] + size[ i ] - 1; - } - - /** Compute the bounding box. */ - typename BoundingBoxType::Pointer bb = BoundingBoxType::New(); - bb->SetMinimum( pointLow ); - bb->SetMaximum( pointHigh ); - typedef typename BoundingBoxType::PointsContainer PointsContainerType; - const PointsContainerType * corners = bb->GetCorners(); - - /** Take into account indextoworld transform: SK: itk implementation was buggy */ - typename PointsContainerType::Pointer cornersWorld = PointsContainerType::New(); - cornersWorld->Reserve( corners->Size() ); - - typename PointsContainerType::const_iterator itC = corners->begin(); - typename PointsContainerType::iterator itCW = cornersWorld->begin(); - while( itC != corners->end() ) - { - PointType transformedPoint = this->GetIndexToWorldTransform()->TransformPoint( *itC ); - *itCW = transformedPoint; - itCW++; - itC++; - } - const_cast< BoundingBoxType * >( this->GetBounds() )->SetPoints( cornersWorld ); - const_cast< BoundingBoxType * >( this->GetBounds() )->ComputeBoundingBox(); - - return true; - } - - return false; - -} // end ComputeLocalBoundingBox() - - -/** Print the object */ -template< unsigned int TDimension > -void -ImageMaskSpatialObject2< TDimension > -::PrintSelf( std::ostream & os, Indent indent ) const -{ - Superclass::PrintSelf( os, indent ); -} - - -} // end namespace itk - -#endif //__ImageMaskSpatialObject2_hxx diff --git a/Common/itkImageSpatialObject2.h b/Common/itkImageSpatialObject2.h deleted file mode 100644 index a46b0188f..000000000 --- a/Common/itkImageSpatialObject2.h +++ /dev/null @@ -1,171 +0,0 @@ -/*========================================================================= - * - * Copyright UMC Utrecht and contributors - * - * 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. - * - *=========================================================================*/ - -/** This file is a slightly modified version of an ITK file. - * Original ITK copyright message: */ -/*========================================================================= - - Program: Insight Segmentation & Registration Toolkit - Module: $RCSfile$ - Language: C++ - Date: $Date: 2008-05-28 10:45:42 +0200 (Wed, 28 May 2008) $ - Version: $Revision: 1636 $ - - Copyright (c) Insight Software Consortium. All rights reserved. - See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. - - This software is distributed WITHOUT ANY WARRANTY; without even - the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - PURPOSE. See the above copyright notices for more information. - -=========================================================================*/ -#ifndef __itkImageSpatialObject2_h -#define __itkImageSpatialObject2_h - -#include "itkImage.h" -#include "itkExceptionObject.h" -#include "itkSpatialObject.h" -#include "itkInterpolateImageFunction.h" -#include "itkNearestNeighborInterpolateImageFunction.h" - -namespace itk -{ - -/** \class ImageSpatialObject2 - * \brief Implementation of an image as spatial object. - * - * This class fixes a bug in the ITK. The ITK has implemented - * the ImageSpatialObject with a wrong conversion between physical - * coordinates and image coordinates. This class solves that. - * - * \sa SpatialObject CompositeSpatialObject - */ - -template< unsigned int TDimension = 3, -class TPixelType = unsigned char -> -class ImageSpatialObject2 : - public SpatialObject< TDimension > -{ - -public: - - typedef double ScalarType; - typedef ImageSpatialObject2< TDimension, TPixelType > Self; - typedef SpatialObject< TDimension > Superclass; - typedef SmartPointer< Self > Pointer; - typedef SmartPointer< const Self > ConstPointer; - - typedef TPixelType PixelType; - typedef Image< PixelType, TDimension > ImageType; - typedef typename ImageType::ConstPointer ImagePointer; - typedef typename ImageType::IndexType IndexType; - typedef typename ImageType::SizeType SizeType; - typedef typename ImageType::RegionType RegionType; - typedef typename Superclass::TransformType TransformType; - typedef typename Superclass::PointType PointType; - typedef typename Superclass::BoundingBoxType BoundingBoxType; - typedef InterpolateImageFunction< ImageType > InterpolatorType; - - typedef NearestNeighborInterpolateImageFunction< ImageType > - NNInterpolatorType; - - typedef VectorContainer< unsigned long, PointType > PointContainerType; - typedef typename PointContainerType::Pointer PointContainerPointer; - - /** Method for creation through the object factory. */ - itkNewMacro( Self ); - - /** Run-time type information (and related methods). */ - itkTypeMacro( ImageSpatialObject2, SpatialObject ); - - /** Set the image. */ - void SetImage( const ImageType * image ); - - /** Get a pointer to the image currently attached to the object. */ - const ImageType * GetImage( void ) const; - - /** Return true if the object is evaluable at the requested point, - * and else otherwise. */ - bool IsEvaluableAt( const PointType & point, - unsigned int depth = 0, char * name = NULL ) const override; - - /** Returns the value of the image at the requested point. - * If the point is not inside the object, then an exception is thrown. - * \sa ExceptionObject */ - bool ValueAt( const PointType & point, double & value, - unsigned int depth = 0, char * name = NULL ) const override; - - /** Returns true if the point is inside, false otherwise. */ - bool IsInside( const PointType & point, - unsigned int depth, char * name ) const override; - - /** Test whether a point is inside or outside the object - * For computational speed purposes, it is faster if the method does not - * check the name of the class and the current depth */ - bool IsInside( const PointType & point ) const; - - /** Compute the boundaries of the image spatial object. */ - bool ComputeLocalBoundingBox() const override; - - /** Returns the latest modified time of the object and its component. */ - ModifiedTimeType GetMTime( void ) const override; - - /** Set the slice position */ - void SetSlicePosition( unsigned int dimension, int position ); - - /** Get the slice position */ - int GetSlicePosition( unsigned int dimension ) - { return m_SlicePosition[ dimension ]; } - - const char * GetPixelType() - { - return m_PixelType.c_str(); - } - - - /** Set/Get the interpolator */ - void SetInterpolator( InterpolatorType * interpolator ); - - itkGetModifiableObjectMacro( Interpolator, InterpolatorType ); - -protected: - - ImageSpatialObject2( const Self & ); // purposely not implemented - void operator=( const Self & ); // purposely not implemented - - ImagePointer m_Image; - - ImageSpatialObject2(); - ~ImageSpatialObject2() override; - - void PrintSelf( std::ostream & os, Indent indent ) const override; - - int * m_SlicePosition; - std::string m_PixelType; - - typename InterpolatorType::Pointer m_Interpolator; -}; - -} // end of namespace itk - -#ifndef ITK_MANUAL_INSTANTIATION -#include "itkImageSpatialObject2.hxx" -#endif - -#endif //__itkImageSpatialObject2_h diff --git a/Common/itkImageSpatialObject2.hxx b/Common/itkImageSpatialObject2.hxx deleted file mode 100644 index 54458b610..000000000 --- a/Common/itkImageSpatialObject2.hxx +++ /dev/null @@ -1,411 +0,0 @@ -/*========================================================================= - * - * Copyright UMC Utrecht and contributors - * - * 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. - * - *=========================================================================*/ - -/** This file is a slightly modified version of an ITK file. - * Original ITK copyright message: */ -/*========================================================================= - - Program: Insight Segmentation & Registration Toolkit - Module: $RCSfile$ - Language: C++ - Date: $Date: 2008-06-04 16:23:50 +0200 (Wed, 04 Jun 2008) $ - Version: $Revision: 1668 $ - - Copyright (c) Insight Software Consortium. All rights reserved. - See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. - - This software is distributed WITHOUT ANY WARRANTY; without even - the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - PURPOSE. See the above copyright notices for more information. - -=========================================================================*/ -#ifndef __ImageSpatialObject2_hxx -#define __ImageSpatialObject2_hxx - -#include "itkImageSpatialObject2.h" -#include "itkSize.h" -#include -#include "vnl/vnl_math.h" - -namespace itk -{ - -/** Constructor */ -template< unsigned int TDimension, class PixelType > -ImageSpatialObject2< TDimension, PixelType > -::ImageSpatialObject2() -{ - this->SetTypeName( "ImageSpatialObject2" ); - m_Image = ImageType::New(); - m_SlicePosition = new int[ TDimension ]; - for( unsigned int i = 0; i < TDimension; i++ ) - { - m_SlicePosition[ i ] = 0; - } - - this->ComputeBoundingBox(); - if( typeid( PixelType ) == typeid( short ) ) - { - m_PixelType = "short"; - } - else if( typeid( PixelType ) == typeid( unsigned char ) ) - { - m_PixelType = "unsigned char"; - } - else if( typeid( PixelType ) == typeid( unsigned short ) ) - { - m_PixelType = "unsigned short"; - } - else if( typeid( PixelType ) == typeid( float ) ) - { - m_PixelType = "float"; - } - else if( typeid( PixelType ) == typeid( double ) ) - { - m_PixelType = "double"; - } - else - { - std::cout << "itk::ImageSpatialObject2() : PixelType not recognized" << std::endl; - } - - m_Interpolator = NNInterpolatorType::New(); -} - - -/** Destructor */ -template< unsigned int TDimension, class PixelType > -ImageSpatialObject2< TDimension, PixelType > -::~ImageSpatialObject2() -{ - delete[] m_SlicePosition; -} - - -/** Return true if the given point is inside the image */ -template< unsigned int TDimension, class PixelType > -bool -ImageSpatialObject2< TDimension, PixelType > -::IsEvaluableAt( const PointType & point, unsigned int depth, char * name ) const -{ - return IsInside( point, depth, name ); -} - - -/** Set the interpolator */ -template< unsigned int TDimension, class PixelType > -void -ImageSpatialObject2< TDimension, PixelType > -::SetInterpolator( InterpolatorType * interpolator ) -{ - m_Interpolator = interpolator; - if( m_Image ) - { - m_Interpolator->SetInputImage( m_Image ); - } -} - - -/** Test whether a point is inside or outside the object - * For computational speed purposes, it is faster if the method does not - * check the name of the class and the current depth */ -template< unsigned int TDimension, class PixelType > -bool -ImageSpatialObject2< TDimension, PixelType > -::IsInside( const PointType & point ) const -{ - if( !this->GetBounds()->IsInside( point ) ) - { - return false; - } - - if( !this->SetInternalInverseTransformToWorldToIndexTransform() ) - { - return false; - } - - PointType transformedPoint - = this->GetInternalInverseTransform()->TransformPoint( point ); - - bool isInside = true; - typename ImageType::RegionType region = m_Image->GetLargestPossibleRegion(); - itk::Size< TDimension > size = region.GetSize(); - - for( unsigned int i = 0; i < TDimension; i++ ) - { - if( size[ i ] ) - { - //if( (transformedPoint[i] > size[i]) || (transformedPoint[i] < 0) ) // changed by SK - if( ( transformedPoint[ i ] > size[ i ] - 1 ) || ( transformedPoint[ i ] < 0 ) ) - { - isInside = false; - break; - } - } - else - { - itkExceptionMacro( << "Size of the ImageSpatialObject2 must be non-zero!" ); - } - } - - return isInside; -} - - -/** Return true if the given point is inside the image */ -template< unsigned int TDimension, class PixelType > -bool -ImageSpatialObject2< TDimension, PixelType > -::IsInside( const PointType & point, unsigned int depth, char * name ) const -{ - if( name == NULL ) - { - if( IsInside( point ) ) - { - return true; - } - } - else if( strstr( typeid( Self ).name(), name ) ) - { - if( IsInside( point ) ) - { - return true; - } - } - - return Superclass::IsInside( point, depth, name ); -} - - -/** Return the value of the image at a specified point - * The value returned is always of type double - * For RGB Images the value returned is the value of the first channel. - */ -template< unsigned int TDimension, class PixelType > -bool -ImageSpatialObject2< TDimension, PixelType > -::ValueAt( const PointType & point, double & value, unsigned int depth, - char * name ) const -{ - if( IsEvaluableAt( point, 0, name ) ) - { - if( !this->SetInternalInverseTransformToWorldToIndexTransform() ) - { - return false; - } - - PointType p = this->GetInternalInverseTransform()->TransformPoint( point ); - - typename InterpolatorType::ContinuousIndexType index; - typedef typename InterpolatorType::OutputType InterpolatorOutputType; - for( unsigned int i = 0; i < TDimension; i++ ) - { - index[ i ] = p[ i ]; - } - - value = static_cast< double >( - DefaultConvertPixelTraits< InterpolatorOutputType >::GetScalarValue( - m_Interpolator->EvaluateAtContinuousIndex( index ) ) ); - - return true; - } - else - { - if( Superclass::IsEvaluableAt( point, depth, name ) ) - { - double val; - Superclass::ValueAt( point, val, depth, name ); - value = val; - return true; - } - else - { - value = this->GetDefaultOutsideValue(); - return false; - } - } - return false; -} - - -/** Compute the bounds of the image */ -template< unsigned int TDimension, class PixelType > -bool -ImageSpatialObject2< TDimension, PixelType > -::ComputeLocalBoundingBox() const -{ - if( this->GetBoundingBoxChildrenName().empty() - || strstr( typeid( Self ).name(), - this->GetBoundingBoxChildrenName().c_str() ) ) - { - typename ImageType::RegionType region - = m_Image->GetLargestPossibleRegion(); - itk::Size< TDimension > size = region.GetSize(); - PointType pointLow, pointHigh; - - unsigned int i; - for( i = 0; i < TDimension; i++ ) - { - pointLow[ i ] = 0; - pointHigh[ i ] = size[ i ] - 1; // changed by stefan: subtract -1 - } - - typename BoundingBoxType::Pointer bb = BoundingBoxType::New(); - bb->SetMinimum( pointLow ); - bb->SetMaximum( pointHigh ); - typedef typename BoundingBoxType::PointsContainer PointsContainerType; - const PointsContainerType * corners = bb->GetCorners(); - - /** Take into account indextoworld transform: SK: itk implementation was buggy */ - typename PointsContainerType::Pointer cornersWorld = PointsContainerType::New(); - cornersWorld->Reserve( corners->Size() ); - - typename PointsContainerType::const_iterator itC = corners->begin(); - typename PointsContainerType::iterator itCW = cornersWorld->begin(); - while( itC != corners->end() ) - { - PointType transformedPoint = this->GetIndexToWorldTransform()->TransformPoint( *itC ); - *itCW = transformedPoint; - itCW++; - itC++; - } - const_cast< BoundingBoxType * >( this->GetBounds() )->SetPoints( cornersWorld ); - const_cast< BoundingBoxType * >( this->GetBounds() )->ComputeBoundingBox(); - - return true; - } - - return false; -} - - -/** Set the image in the spatial object */ -template< unsigned int TDimension, class PixelType > -void -ImageSpatialObject2< TDimension, PixelType > -::SetImage( const ImageType * image ) -{ - if( !image ) - { - return; - } - - m_Image = image; - typename TransformType::OffsetType offset; - typename TransformType::MatrixType indexToObjectMatrix; - typename ImageType::PointType origin; - typename ImageType::SpacingType spacing; - typename ImageType::DirectionType direction; - typename ImageType::IndexType indexProbe; - typename ImageType::PointType pointProbe; - - origin.Fill( 0 ); - spacing.Fill( 1.0 ); - - origin = m_Image->GetOrigin(); - spacing = m_Image->GetSpacing(); - direction = m_Image->GetDirection(); - - for( unsigned int d = 0; d < TDimension; d++ ) - { - offset[ d ] = origin[ d ]; - - // Get the Image transformation by passing index probes along each one of - // the image axis. - indexProbe.Fill( 0 ); - indexProbe[ d ] = 1; - - m_Image->TransformIndexToPhysicalPoint( indexProbe, pointProbe ); - - // Remove the origin - for( unsigned int d3 = 0; d3 < TDimension; d3++ ) - { - pointProbe[ d3 ] -= origin[ d3 ]; - } - - for( unsigned int d2 = 0; d2 < TDimension; d2++ ) - { - indexToObjectMatrix[ d2 ][ d ] = pointProbe[ d2 ]; - } - } - - this->GetIndexToObjectTransform()->SetMatrix( indexToObjectMatrix ); - this->GetIndexToObjectTransform()->SetOffset( offset ); - - this->ComputeObjectToParentTransform(); - - this->Modified(); - this->ComputeBoundingBox(); - - m_Interpolator->SetInputImage( m_Image ); -} - - -/** Get the image inside the spatial object */ -template< unsigned int TDimension, class PixelType > -const typename ImageSpatialObject2< TDimension, PixelType >::ImageType -* ImageSpatialObject2< TDimension, PixelType > -::GetImage( void ) const -{ - return m_Image.GetPointer(); -} - -/** Print the object */ -template< unsigned int TDimension, class PixelType > -void -ImageSpatialObject2< TDimension, PixelType > -::PrintSelf( std::ostream & os, Indent indent ) const -{ - Superclass::PrintSelf( os, indent ); - os << "Image: " << std::endl; - os << indent << m_Image << std::endl; -} - - -/** Get the modification time */ -template< unsigned int TDimension, class PixelType > -ModifiedTimeType -ImageSpatialObject2< TDimension, PixelType > -::GetMTime( void ) const -{ - ModifiedTimeType latestMTime = Superclass::GetMTime(); - ModifiedTimeType imageMTime = m_Image->GetMTime(); - - if( imageMTime > latestMTime ) - { - latestMTime = imageMTime; - } - - return latestMTime; -} - - -/** Set the slice position */ -template< unsigned int TDimension, class PixelType > -void -ImageSpatialObject2< TDimension, PixelType > -::SetSlicePosition( unsigned int dimension, int position ) -{ - m_SlicePosition[ dimension ] = position; - this->Modified(); -} - - -} // end namespace itk - -#endif //__ImageSpatialObject2_hxx diff --git a/Components/Registrations/MultiResolutionRegistration/elxMultiResolutionRegistration.hxx b/Components/Registrations/MultiResolutionRegistration/elxMultiResolutionRegistration.hxx index 37e4aa52c..9ef5863f8 100644 --- a/Components/Registrations/MultiResolutionRegistration/elxMultiResolutionRegistration.hxx +++ b/Components/Registrations/MultiResolutionRegistration/elxMultiResolutionRegistration.hxx @@ -204,6 +204,11 @@ MultiResolutionRegistration< TElastix > FixedMaskSpatialObjectPointer fixedMask = this->GenerateFixedMaskSpatialObject( this->GetElastix()->GetFixedMask(), useFixedMaskErosion, this->GetFixedImagePyramid(), level ); + + if (fixedMask != nullptr) + { + fixedMask->Update(); + } this->GetModifiableMetric()->SetFixedImageMask( fixedMask ); /** Stop timer and print the elapsed time. */ @@ -219,6 +224,11 @@ MultiResolutionRegistration< TElastix > MovingMaskSpatialObjectPointer movingMask = this->GenerateMovingMaskSpatialObject( this->GetElastix()->GetMovingMask(), useMovingMaskErosion, this->GetMovingImagePyramid(), level ); + + if (movingMask != nullptr) + { + movingMask->Update(); + } this->GetModifiableMetric()->SetMovingImageMask(movingMask); /** Stop timer and print the elapsed time. */ diff --git a/Core/ComponentBaseClasses/elxRegistrationBase.h b/Core/ComponentBaseClasses/elxRegistrationBase.h index 285ef103b..b5ab59080 100644 --- a/Core/ComponentBaseClasses/elxRegistrationBase.h +++ b/Core/ComponentBaseClasses/elxRegistrationBase.h @@ -25,7 +25,7 @@ #include "itkMultiResolutionImageRegistrationMethod2.h" /** Mask support. */ -#include "itkImageMaskSpatialObject2.h" +#include "itkImageMaskSpatialObject.h" #include "itkErodeMaskImageFilter.h" namespace elastix @@ -160,9 +160,9 @@ class RegistrationBase : public BaseComponentSE< TElastix > typedef typename ElastixType::MovingMaskType MovingMaskImageType; typedef typename FixedMaskImageType::Pointer FixedMaskImagePointer; typedef typename MovingMaskImageType::Pointer MovingMaskImagePointer; - typedef itk::ImageMaskSpatialObject2< + typedef itk::ImageMaskSpatialObject< itkGetStaticConstMacro( FixedImageDimension ) > FixedMaskSpatialObjectType; - typedef itk::ImageMaskSpatialObject2< + typedef itk::ImageMaskSpatialObject< itkGetStaticConstMacro( MovingImageDimension ) > MovingMaskSpatialObjectType; typedef typename FixedMaskSpatialObjectType::Pointer FixedMaskSpatialObjectPointer; diff --git a/Testing/CI/Azure/ci.yml b/Testing/CI/Azure/ci.yml index 957010930..04891b2bf 100644 --- a/Testing/CI/Azure/ci.yml +++ b/Testing/CI/Azure/ci.yml @@ -1,6 +1,6 @@ variables: ITKv4_VERSION: release-4.13 - ITKv5_VERSION: eb431fa16ae8b3a93e65db1f77e57e73dc83c6a2 # master branch as of Feb 10, 2019 + ITKv5_VERSION: 9e122664724eb049955c968c054247c00d92eee2 # master branch as of May 9, 2019 (after v5.0rc02) ITK_SOURCE_DIR: $(Agent.BuildDirectory)/ITK-source ITK_BINARY_DIR: $(Agent.BuildDirectory)/ITK-build ELASTIX_SOURCE_DIR: $(Build.Repository.LocalPath) diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index 37a6d2cc3..b084d59c1 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -859,13 +859,15 @@ elx_add_run_test( 3DCT_lung.MI.bspline.SGD.003 -t0 ${TestDataDir}/transformparameters.3DCT_lung.affine.txt -p ${TestDataDir}/parameters.3D.MI.bspline.SGD.003.txt ) -elx_add_run_test( 3DCT_lung.MI.bspline.SGD.004 - "CHECKSUM;PARAMETERS;OVERLAP;LANDMARKS" - -f ${TestDataDir}/3DCT_lung_baseline.mha - -m ${TestDataDir}/3DCT_lung_followup.mha - -fMask ${TestDataDir}/3DCT_lung_baseline_mask.mha - -t0 ${TestDataDir}/transformparameters.3DCT_lung.affine.txt - -p ${TestDataDir}/parameters.3D.MI.bspline.SGD.004.txt ) +if ( NOT ITK_VERSION VERSION_LESS "5.0.0" ) + elx_add_run_test( 3DCT_lung.MI.bspline.SGD.004 + "CHECKSUM;PARAMETERS;OVERLAP;LANDMARKS" + -f ${TestDataDir}/3DCT_lung_baseline.mha + -m ${TestDataDir}/3DCT_lung_followup.mha + -fMask ${TestDataDir}/3DCT_lung_baseline_mask.mha + -t0 ${TestDataDir}/transformparameters.3DCT_lung.affine.txt + -p ${TestDataDir}/parameters.3D.MI.bspline.SGD.004.txt ) +endif() # Test some interpolators elx_add_run_test( 3DCT_lung.SSD.bspline.ASGD.002