BUG: Smooth structure tensor with an isotropic Gaussian kernel#6602
Conversation
|
Status of this draft: blocked on baselines and now on a rebase conflict, and a high-effort automated review found two confirmed behavioral regressions in the smoothing swap. Blockers
Review findings (confirmed)
|
1cceb81 to
0008d4c
Compare
|
Rebased onto
Why the test changedThe prior fixture was x-constant (8×64, y-step only), so isotropic x-smoothing was a no-op on it — the assertion proved some cross-axis smoothing but couldn't distinguish "all axes" from "y only", and would not catch a regression that dropped primary-axis smoothing while keeping y. The two-axis loop asserts a feature-scale trace delta on each axis independently. Verified locally (
The 16 |
0008d4c to
40d9e20
Compare
|
Maintainer confirmed this is a genuine bug. Pushed the follow-through — the PR is now complete on the code side and awaits its baseline data:
CI ordering: the Force-push history (all
|
40d9e20 to
de548a8
Compare
|
It appears that only SimpleITK will need new baselines. |
This comment was marked as low quality.
This comment was marked as low quality.
RecursiveGaussianImageFilter smooths along a single axis only (direction 0 by default). The structure tensor definition K_rho(grad(u_sigma) (x) grad(u_sigma)) requires an isotropic Gaussian kernel at both scales, smoothing every axis. Use SmoothingRecursiveGaussianImageFilter, which smooths all axes. All 16 CoherenceEnhancingDiffusion/AnisotropicDiffusionLBR baselines are regenerated for the corrected isotropic output, and the migration guide documents the behavior change for downstream consumers. Addresses item B22 of InsightSoftwareConsortium#6575.
de548a8 to
0b55b82
Compare
|
Force-pushed Conflict resolutionOne conflict, in
|
0acef9a
into
InsightSoftwareConsortium:main
StructureTensorImageFiltersmoothed the tensor field withRecursiveGaussianImageFilter, which filters one axis only. The structure tensor requires an isotropic kernel, so both scales now useSmoothingRecursiveGaussianImageFilter. Addresses B22 of #6575.The output change is intentional and maintainer-confirmed; all 16
AnisotropicDiffusionLBRbaselines are regenerated in this PR (blobs merged via InsightSoftwareConsortium/ITKTestingData#77) and the ITK 6 migration guide documents the change for downstream consumers. Only SimpleITK is expected to need new baselines.Root cause
itkStructureTensorImageFilter.hxx:124built the feature-scale (K_rho) smoother asusing GaussianFilterType = RecursiveGaussianImageFilter<TensorImageType>;RecursiveGaussianImageFilterderives fromRecursiveSeparableImageFilterand filters along a single direction —m_Direction, which defaults to 0 and was never set here. The structure tensorK_rho * (grad(u_sigma) (x) grad(u_sigma))requires an isotropic kernel, i.e. smoothing on every axis. The same mistake appears at:75for the noise-scale (K_sigma) smoother, on them_UseGradientRecursiveGaussianImageFilter == falsebranch (unreachable — the flag has no setter — but the same defect, so it is fixed too). Both now useSmoothingRecursiveGaussianImageFilter, which chains oneRecursiveGaussianImageFilterper axis.GradientRecursiveGaussianImageFilter, used elsewhere in the same file, already loopsSetDirection()over every axis and was correct.The single-axis smoothing dates to the original 2014 implementation (Jean-Marie Mirebeau) and was unintentional.
Baselines and migration
All 16 regenerated:
PacMan_cEED/cCED/I,FingerPrint_cEED/cCED/I,Cos3D_cCED,mrbrain_cEED,Lena_Detail_cCED_2/cEED_2/I_2,VectorField_Circle_cEED,Triangle_cEED/Triangle_EED,Oscillations1_cCED/Oscillations1_CED.Generated on macOS arm64 from the fixed filter; CIDs computed with
npx ipfs-car pack --no-wrap(unixfs-v1-2025 profile)..cidcontent links andcontent-links.manifestare updated in this commit.itk_6_migration_guide.mdexplains why the structure tensor requires an isotropic kernel and what changes forCoherenceEnhancingDiffusionImageFilter/AnisotropicDiffusionLBRImageFilter.Regression test
itkStructureTensorImageFilterGTest.cxxgainsStructureTensorImageFilter.FeatureScaleSmoothsAlongAllAxes, which loops a step edge over both axes of a symmetric 64x64 fixture and asserts a feature-scale trace delta on each axis independently. Verified to fail against the pre-fix single-axis source (stepAxis=1delta = 0), so it is a real tripwire.ITKSmoothingadded to the module'sDEPENDSfor the new include.AI assistance