Skip to content

BUG: Compute curvature whenever the reinitialization term needs it - #6606

Merged
hjmjohnson merged 1 commit into
InsightSoftwareConsortium:mainfrom
physwkim:bug-region-based-levelset-reinit-curvature-6575
Jul 14, 2026
Merged

hjmjohnson merged 1 commit into
InsightSoftwareConsortium:mainfrom
physwkim:bug-region-based-levelset-reinit-curvature-6575

Conversation

@physwkim

Copy link
Copy Markdown
Contributor

The reinitialization term in RegionBasedLevelSetFunction::ComputeUpdate() subtracts a curvature that was only computed when the curvature-length term was active, so it silently degenerated to a bare Laplacian. Addresses B30 of #6575.

Root cause

itkRegionBasedLevelSetFunction.hxx:255-269 — curvature is populated inside the curvature-length guard, then read by the reinitialization term, which has its own independent activation condition:

if ((dh != 0.) && (this->m_CurvatureWeight != ScalarValueType{}))
{
  curvature = this->ComputeCurvature(it, offset, gd);      // only here
  curvature_term = this->m_CurvatureWeight * curvature * ... * dh;
}

if (this->m_ReinitializationSmoothingWeight != ScalarValueType{})
{
  laplacian_term = this->ComputeLaplacian(gd) - curvature; // but read here
}

Whenever CurvatureWeight == 0, or dh == 0 at a pixel, curvature stays at its zero initializer and the term collapses to Laplacian(phi) alone — coupling two regularization weights that the class documents (itkRegionBasedLevelSetFunction.h:445-448) as independent, and dropping the div(grad(phi)/|grad(phi)|) half of Laplacian(phi) - div(grad(phi)/|grad(phi)|). The dh factor belongs to the curvature-length term only; the reinitialization term has no dh in its formula.

ComputeCurvature() is now called once when either consumer needs it, and the two guards are separate.

Local validation

New GoogleTest itkRegionBasedLevelSetFunctionGTest.cxx, registered in ITKReviewGTests. phi = x^2 + y^2 gives curvature 1 and Laplacian 4 at the probed pixel, so the correct reinitialization contribution is 3.0 and the buggy one is 4.0. One test per half of the guard:

  • ReinitializationTermSubtractsCurvatureWhenCurvatureWeightIsZero — fail-before 4.0, pass-after 3.0.
  • ReinitializationTermSubtractsCurvatureWhenDerivativeIsZero — fail-before 4.0, pass-after 3.0.

No ExternalData baseline changes. All six ScalarChanAndVese*LevelSetImageFilter regression tests were run with baselines downloaded, before and after the fix: ImageError = 0 in every case. Test2_2 (CurvatureWeight=0, ReinitializationSmoothingWeight=1) is the one configuration that exercises the bug at every pixel, yet its output is unchanged — MultiphaseDenseFiniteDifferenceImageFilter::ApplyUpdate() re-runs a full SignedMaurerDistanceMap reinitialization every iteration (m_ReinitializeCounter defaults to 1), which rebuilds the level set from the sign of phi and discards the magnitude of the per-pixel correction.

AI assistance

@github-actions github-actions Bot added type:Bug Inconsistencies or issues which will cause an incorrect result under some or all circumstances type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots type:Testing Ensure that the purpose of a class is met/the results on a wide set of test cases are correct labels Jul 13, 2026
@greptile-apps

greptile-apps Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes curvature use in the region-based level set update path. The main changes are:

  • Compute curvature when the reinitialization term needs it.
  • Keep the curvature-length and reinitialization term guards separate.
  • Add focused GoogleTests for zero curvature weight and zero Heaviside derivative cases.

Confidence Score: 5/5

This looks safe to merge.

No blocking issues found in the changed code.

No files need attention.

T-Rex T-Rex Logs

What T-Rex did

  • Tool availability was captured for the validation run, showing make, gcc, g++, and python3 present, while cmake, ctest, and ninja were missing.
  • The narrow CMake configuration command was attempted but cmake was not found, causing the configure step to exit with an error.
  • CTest discovery for RegionBasedLevelSetFunction was attempted but failed because ctest was not found.
  • The ITKReviewGTestDriver build command was attempted but cmake was not found, so the build could not proceed.
  • The filtered CTest run was attempted but ctest was not found, and no severity-bearing findings were reported because the tests could not be executed.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
Modules/Nonunit/Review/include/itkRegionBasedLevelSetFunction.hxx Computes curvature for both term consumers while preserving each term's activation guard.
Modules/Nonunit/Review/test/CMakeLists.txt Registers the new region-based level set GoogleTest source.
Modules/Nonunit/Review/test/itkRegionBasedLevelSetFunctionGTest.cxx Adds regression tests for the reinitialization-only curvature subtraction cases.

Reviews (1): Last reviewed commit: "BUG: Compute curvature whenever the rein..." | Re-trigger Greptile

@hjmjohnson
hjmjohnson force-pushed the bug-region-based-levelset-reinit-curvature-6575 branch from b614a70 to f1b786a Compare July 13, 2026 23:57
@hjmjohnson

Copy link
Copy Markdown
Member

First force-push = plain rebase on main; second = review fix only — the new GTest's helper classes are renamed (RegionBasedLevelSetReinitTestFunction/...SharedData) so they no longer share a qualified name with the different itk::RegionBasedLevelSetFunctionTestHelper in the sibling legacy test (latent ODR hazard). Verified locally that itkScalarChanAndVeseDenseLevelSetImageFilterTest2_* baseline comparisons still pass (8/8) — the CurvatureWeight=0 reinitialization change stays within the compare tolerance.

@hjmjohnson
hjmjohnson force-pushed the bug-region-based-levelset-reinit-curvature-6575 branch from f1b786a to f356c41 Compare July 14, 2026 00:14
The reinitialization term is Laplacian(phi) minus curvature, but
curvature was only computed when the curvature-length term was
active (dh != 0 and CurvatureWeight != 0). Either condition alone
made the reinitialization term silently collapse to a bare
Laplacian, coupling two independent regularization weights.

Addresses item B30 of InsightSoftwareConsortium#6575.
@hjmjohnson
hjmjohnson force-pushed the bug-region-based-levelset-reinit-curvature-6575 branch from f356c41 to 47d1a01 Compare July 14, 2026 01:57
@hjmjohnson

Copy link
Copy Markdown
Member

Force-push = plain rebase onto current main, folding the new GTest source into the GTests list that #6589 introduced for this module (two creategoogletestdriver calls in the CI merge build caused/would cause a duplicate-target configure error). Verified locally: configure clean, module tests pass.

@hjmjohnson
hjmjohnson merged commit 776d5c4 into InsightSoftwareConsortium:main Jul 14, 2026
20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:Bug Inconsistencies or issues which will cause an incorrect result under some or all circumstances type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots type:Testing Ensure that the purpose of a class is met/the results on a wide set of test cases are correct

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants