Skip to content

Commit c2c79a8

Browse files
authored
Merge pull request #34 from dzenanz/groupwiseWIP
2 parents 997aa88 + 5162452 commit c2c79a8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1353
-33
lines changed

.github/workflows/build-test-package.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ on: [push,pull_request]
44

55
jobs:
66
cxx-build-workflow:
7-
uses: InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction/.github/workflows/build-test-cxx.yml@main
7+
uses: InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction/.github/workflows/build-test-cxx.yml@v5.4.0
88

99
python-build-workflow:
10-
uses: InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction/.github/workflows/build-test-package-python.yml@main
10+
uses: InsightSoftwareConsortium/ITKRemoteModuleBuildTestPackageAction/.github/workflows/[email protected]
11+
with:
12+
manylinux-platforms: '["_2_28-x64","_2_28-aarch64"]'
1113
secrets:
1214
pypi_password: ${{ secrets.pypi_password }}

CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
cmake_minimum_required(VERSION 3.16.3)
22

3+
if(POLICY CMP0169)
4+
cmake_policy(SET CMP0169 OLD)
5+
endif()
6+
37
include(FetchContent)
48
FetchContent_Declare(
59
ants_inner
610
GIT_REPOSITORY https://github.com/ANTsX/ANTs
7-
GIT_TAG v2.5.1 # 2024-01-24
11+
GIT_TAG 0e0e488fe17aa96dc25a8e88d2db42e5bdfefce7 # 2024-09-27
812
)
913
FetchContent_GetProperties(ants_inner)
1014
if(NOT ants_inner_POPULATED)
Lines changed: 249 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,249 @@
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+
#ifndef itkANTSGroupwiseBuildTemplate_h
19+
#define itkANTSGroupwiseBuildTemplate_h
20+
21+
#include "itkImageToImageFilter.h"
22+
#include "itkANTSRegistration.h"
23+
#include "itkImage.h"
24+
#include "itkDisplacementFieldTransform.h"
25+
26+
namespace itk
27+
{
28+
29+
/** \class ANTSGroupwiseBuildTemplate
30+
*
31+
* \brief Group-wise image registration method parameterized according to ANTsPy.
32+
*
33+
* Inputs are images to be registered, and optionally initial template.
34+
* Outputs are the computed template image, and optionally forward and inverse transforms
35+
* for each of the input images when registered to the template.
36+
*
37+
* If images are large, a way to conserve memory is to provide a list of file paths
38+
* instead of images already loaded into memory. If this is done, the images will be
39+
* loaded into memory one at a time as they are being iterated on, and then unloaded.
40+
*
41+
* This is similar to ANTsPy build_template function:
42+
* https://github.com/ANTsX/ANTsPy/blob/master/ants/registration/build_template.py
43+
*
44+
* \ingroup ANTsWasm
45+
* \ingroup Registration
46+
*
47+
*/
48+
template <typename TImage,
49+
typename TTemplateImage = Image<float, TImage::ImageDimension>,
50+
typename TParametersValueType = double>
51+
class ANTSGroupwiseBuildTemplate : public ImageToImageFilter<TTemplateImage, TTemplateImage>
52+
{
53+
public:
54+
ITK_DISALLOW_COPY_AND_MOVE(ANTSGroupwiseBuildTemplate);
55+
56+
static constexpr unsigned int ImageDimension = TImage::ImageDimension;
57+
58+
using ImageType = TImage;
59+
using PixelType = typename ImageType::PixelType;
60+
using TemplateImageType = TTemplateImage;
61+
62+
using ParametersValueType = TParametersValueType;
63+
using TransformType = Transform<TParametersValueType, ImageDimension, ImageDimension>;
64+
using CompositeTransformType = CompositeTransform<ParametersValueType, ImageDimension>;
65+
using OutputTransformType = CompositeTransformType;
66+
using DecoratedOutputTransformType = DataObjectDecorator<OutputTransformType>;
67+
68+
/** Standard class aliases. */
69+
using Self = ANTSGroupwiseBuildTemplate<ImageType, TTemplateImage, ParametersValueType>;
70+
using Superclass = ImageToImageFilter<TTemplateImage, TTemplateImage>;
71+
using Pointer = SmartPointer<Self>;
72+
using ConstPointer = SmartPointer<const Self>;
73+
74+
/** Run-time type information. */
75+
itkTypeMacro(ANTSGroupwiseBuildTemplate, ImageToImageFilter);
76+
77+
/** Standard New macro. */
78+
itkNewMacro(Self);
79+
80+
81+
/** Set/Get the initial template image. */
82+
void
83+
SetInitialTemplateImage(const TemplateImageType * initialTemplate)
84+
{
85+
this->SetNthInput(0, const_cast<TemplateImageType *>(initialTemplate)); // the primary input
86+
}
87+
const TemplateImageType *
88+
GetInitialTemplateImage()
89+
{
90+
return static_cast<TemplateImageType *>(this->GetInput(0)); // the primary input
91+
}
92+
93+
/** Get the optimal template image. */
94+
TemplateImageType *
95+
GetTemplateImage()
96+
{
97+
return this->GetOutput(0); // this is just the primary output
98+
}
99+
100+
/** Set/Get step size for shape update gradient. */
101+
itkSetMacro(GradientStep, ParametersValueType);
102+
itkGetMacro(GradientStep, ParametersValueType);
103+
104+
/** Set/Get the weight for image blending. Zero disables it. */
105+
itkSetMacro(BlendingWeight, ParametersValueType);
106+
itkGetMacro(BlendingWeight, ParametersValueType);
107+
108+
/** Set/Get whether template update step uses the rigid component. */
109+
itkSetMacro(UseNoRigid, bool);
110+
itkGetMacro(UseNoRigid, bool);
111+
itkBooleanMacro(UseNoRigid);
112+
113+
/** Set/Get number of template building iterations. */
114+
itkSetMacro(Iterations, unsigned int);
115+
itkGetMacro(Iterations, unsigned int);
116+
117+
118+
/** Set/Get whether we should keep registration transforms in memory.
119+
* If true, transforms which register each of the input images to the template
120+
* will be available via GetTransform(index) after the registration finishes.
121+
* Off by default, to conserve memory. Incompatible with providing a PathList. */
122+
itkSetMacro(KeepTransforms, bool);
123+
itkGetMacro(KeepTransforms, bool);
124+
itkBooleanMacro(KeepTransforms);
125+
126+
/** Set/Get the weight for each image. */
127+
itkSetMacro(Weights, std::vector<ParametersValueType>);
128+
itkGetConstReferenceMacro(Weights, std::vector<ParametersValueType>);
129+
130+
/** Set the images to register. */
131+
itkSetMacro(ImageList, std::vector<typename ImageType::Pointer>);
132+
133+
/** Set the file paths of images to register. */
134+
itkSetMacro(PathList, std::vector<std::string>);
135+
itkGetConstReferenceMacro(PathList, std::vector<std::string>);
136+
137+
/** Add an image to the list of images to register. */
138+
virtual void
139+
AddImage(const ImageType * image)
140+
{
141+
m_ImageList.push_back(const_cast<ImageType *>(image));
142+
}
143+
144+
/** Clear the list of images to register. */
145+
virtual void
146+
ClearImageList()
147+
{
148+
m_ImageList.clear();
149+
}
150+
151+
/** Returns the transform which registers the image with the provided index to the average template.
152+
* To make sure this is available, KeepTransformsOn() should be set be called. */
153+
const OutputTransformType *
154+
GetTransform(unsigned imageIndex) const
155+
{
156+
return m_TransformList[imageIndex];
157+
}
158+
159+
using PairwiseType = ANTSRegistration<TemplateImageType, ImageType, ParametersValueType>;
160+
/** Set/Get the internal pairwise registration object (allows its customization). */
161+
itkSetObjectMacro(PairwiseRegistration, PairwiseType);
162+
itkGetModifiableObjectMacro(PairwiseRegistration, PairwiseType);
163+
164+
using ProcessObject::AddInput;
165+
using ProcessObject::RemoveInput;
166+
using ProcessObject::GetInput;
167+
168+
/** This filter only deals with whole images. */
169+
void
170+
GenerateInputRequestedRegion() override
171+
{
172+
auto * inputPtr = dynamic_cast<TTemplateImage *>(this->GetInput(0));
173+
inputPtr->SetRequestedRegionToLargestPossibleRegion();
174+
}
175+
176+
/** Request the largest possible region on all outputs. */
177+
void
178+
EnlargeOutputRequestedRegion(DataObject * output) override
179+
{
180+
output->SetRequestedRegionToLargestPossibleRegion();
181+
}
182+
183+
void
184+
GenerateOutputInformation() override;
185+
186+
protected:
187+
ANTSGroupwiseBuildTemplate();
188+
~ANTSGroupwiseBuildTemplate() override = default;
189+
190+
/** Make a DataObject of the correct type to be used as the specified output. */
191+
using DataObjectPointerArraySizeType = ProcessObject::DataObjectPointerArraySizeType;
192+
DataObject::Pointer MakeOutput(DataObjectPointerArraySizeType) override;
193+
194+
void
195+
PrintSelf(std::ostream & os, Indent indent) const override;
196+
197+
void
198+
GenerateData() override;
199+
200+
void
201+
VerifyInputInformation() const override;
202+
203+
// helper function to create the right kind of concrete transform
204+
template <typename TTransform>
205+
static void
206+
MakeOutputTransform(SmartPointer<TTransform> & ptr)
207+
{
208+
ptr = TTransform::New();
209+
}
210+
211+
typename TemplateImageType::Pointer
212+
DuplicateImage(const TemplateImageType * image);
213+
214+
template <typename TOutputImage, typename TInputImage>
215+
typename TOutputImage::Pointer
216+
ResampleToTarget(const TInputImage * input,
217+
const TemplateImageType * target,
218+
typename TransformType::ConstPointer transform);
219+
220+
template <typename TTempImage>
221+
typename TTempImage::Pointer
222+
ScaleAndAdd(typename TTempImage::Pointer temp, const TTempImage * image, typename TTempImage::PixelType weight);
223+
224+
ParametersValueType m_GradientStep{ 0.2 };
225+
ParametersValueType m_BlendingWeight{ 0.75 };
226+
bool m_UseNoRigid{ true };
227+
unsigned int m_Iterations{ 3 };
228+
bool m_KeepTransforms{ false };
229+
230+
std::vector<ParametersValueType> m_Weights;
231+
std::vector<std::string> m_PathList;
232+
std::vector<typename ImageType::Pointer> m_ImageList;
233+
typename PairwiseType::Pointer m_PairwiseRegistration{ nullptr };
234+
235+
std::vector<typename OutputTransformType::Pointer> m_TransformList;
236+
237+
#ifdef ITK_USE_CONCEPT_CHECKING
238+
static_assert(TImage::ImageDimension == TTemplateImage::ImageDimension,
239+
"Template imagemust have the same dimension as the input images.");
240+
static_assert(ImageDimension >= 2, "Images must be at least two-dimensional.");
241+
#endif
242+
};
243+
} // namespace itk
244+
245+
#ifndef ITK_MANUAL_INSTANTIATION
246+
# include "itkANTSGroupwiseBuildTemplate.hxx"
247+
#endif
248+
249+
#endif // itkANTSGroupwiseBuildTemplate

0 commit comments

Comments
 (0)