Skip to content

Commit 9e5f5df

Browse files
committed
COMP: Don't let ImageToFeaturesMap output inherit the input LargestPossibleRegion
ImageToFeaturesMap is an itk::ProcessObject whose outputs are feature maps whose size and spacing are data-dependent (decided by the model) and set in GenerateData() by grafting the TensorToImageFilter result. The default ProcessObject::GenerateOutputInformation() copies the primary input's geometry -- including its LargestPossibleRegion -- onto every output. When a downstream filter re-propagates UpdateOutputInformation() up this filter (e.g. the per-channel VectorIndexSelectionCast in InterpolateVectorImageFunction::SetInputImage), that default resets each output's LargestPossibleRegion back to the larger input image size while the buffer still holds the smaller feature map, so the consumer then iterates an input-sized region over the smaller buffer and throws 'Region ... is outside of buffered region'. Override GenerateOutputInformation() with an empty body so the grafted regions are never clobbered. Surfaced by the Elastix IMPACT metric on static-ITK builds; the Advanced (Elastix) and v4 (Python) metrics both consume this filter.
1 parent a681247 commit 9e5f5df

2 files changed

Lines changed: 30 additions & 0 deletions

File tree

include/itkImageToFeaturesMap.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,23 @@ class ImageToFeaturesMap : public ProcessObject
167167
void
168168
VerifyPreconditions() const override;
169169

170+
/** Deliberately suppress the default output-information generation.
171+
*
172+
* ProcessObject::GenerateOutputInformation() copies the primary input's geometry
173+
* (origin/spacing/direction AND LargestPossibleRegion) onto every output. That is
174+
* wrong for this filter: the outputs are feature maps whose size and spacing are
175+
* data-dependent (decided by the model) and are set authoritatively in
176+
* GenerateData() by grafting the TensorToImageFilter result. Worse, when a
177+
* downstream filter re-propagates UpdateOutputInformation() up this filter (e.g. the
178+
* per-channel VectorIndexSelectionCast in InterpolateVectorImageFunction::SetInputImage),
179+
* the default would reset each output's LargestPossibleRegion back to the (larger)
180+
* input image size while the buffer still holds the smaller feature map -- the
181+
* consumer then iterates an input-sized region over the smaller buffer and throws
182+
* "Region ... is outside of buffered region". Overriding with an empty body keeps the
183+
* grafted regions intact. */
184+
void
185+
GenerateOutputInformation() override;
186+
170187
void
171188
GenerateData() override;
172189

include/itkImageToFeaturesMap.hxx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,19 @@ ImageToFeaturesMap<TInputImage, TInterpolator>::VerifyPreconditions() const
8080
Superclass::VerifyPreconditions();
8181
}
8282

83+
template <typename TInputImage, typename TInterpolator>
84+
void
85+
ImageToFeaturesMap<TInputImage, TInterpolator>::GenerateOutputInformation()
86+
{
87+
// Intentionally empty: do NOT chain to Superclass (ProcessObject), whose default
88+
// copies the primary input's geometry -- including its LargestPossibleRegion -- onto
89+
// the outputs. The feature-map geometry is data-dependent and is set in GenerateData()
90+
// via graft; letting the default run (e.g. on a downstream UpdateOutputInformation
91+
// re-propagation) would reset LargestPossibleRegion to the input image size while the
92+
// buffer holds the smaller feature map, making a consumer iterate out of bounds. See
93+
// the declaration in itkImageToFeaturesMap.h for the full rationale.
94+
}
95+
8396
/**
8497
* ******************* pca_fit ***********************
8598
*/

0 commit comments

Comments
 (0)