Skip to content

BUG: Reject class counts that overflow non-contiguous labels#6596

Open
physwkim wants to merge 1 commit into
InsightSoftwareConsortium:mainfrom
physwkim:bug-scalar-kmeans-label-interval-6575
Open

BUG: Reject class counts that overflow non-contiguous labels#6596
physwkim wants to merge 1 commit into
InsightSoftwareConsortium:mainfrom
physwkim:bug-scalar-kmeans-label-interval-6575

Conversation

@physwkim

Copy link
Copy Markdown
Contributor

Reject class counts whose non-contiguous labels cannot be represented in the output pixel type, instead of computing a wrapped label interval. Addresses B14 of #6575.

Root cause

itkScalarImageKmeansImageFilter.hxx:112-116:

unsigned int labelInterval = 1;
if (m_UseNonContiguousLabels)
  labelInterval = (NumericTraits<OutputPixelType>::max() / numberOfClasses) - 1;

numberOfClasses is m_InitialMeans.size(). For a uint8 output the quotient reaches 0 once the class count exceeds 255, and 0 - 1 in unsigned arithmetic gives labelInterval == 0xFFFFFFFF; the later label += labelInterval (:124) and the outside-region label labelInterval * numberOfClasses (:189) then wrap. Short of full wraparound the interval already degenerates to 0 once the class count passes half the pixel range, collapsing every class label — and the outside label — onto the same value. VerifyPreconditions() only rejected an empty mean list.

The fix adds the exact representability precondition (2 * numberOfClasses <= NumericTraits<OutputPixelType>::max(), the condition under which max()/N - 1 >= 1 holds) rather than clamping the arithmetic, so an unrepresentable configuration is diagnosed instead of silently producing indistinguishable labels.

Local validation

New GoogleTest ScalarImageKmeansImageFilter.NonContiguousLabelsTooManyClassesThrows (module had no GTest driver; one is added).

Fail-before: Expected: filter->Update() throws an exception of type itk::ExceptionObject. Actual: it throws nothing.
Pass-after: [ PASSED ] 1 test.

ctest -L ITKClassifiers: identical pass/fail set before and after, verified against a pristine checkout (the failures are missing ExternalData baselines and KWStyle in this offline build tree, not regressions). itkScalarImageKmeansImageFilter3DTest, which exercises UseNonContiguousLabels(true) on real data, passes both before and after.

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 area:Segmentation Issues affecting the Segmentation module labels Jul 13, 2026
@greptile-apps

greptile-apps Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR rejects invalid non-contiguous K-means label ranges before execution. The main changes are:

  • A new VerifyPreconditions() check for too many classes.
  • A new GoogleTest dependency for the Classifiers tests.
  • A regression test for excessive class counts with unsigned char output.

Confidence Score: 4/5

The changed precondition needs a small fix for one-class boolean output images.

The new guard matches the intended unsigned-char overflow boundary for multi-class label images, and the test wiring follows the module GoogleTest pattern for the excessive-class case.

Modules/Segmentation/Classifiers/include/itkScalarImageKmeansImageFilter.hxx needs attention because the same guard rejects a valid bool output case with one initial mean.

T-Rex T-Rex Logs

What T-Rex did

  • Created a focused C++ harness that instantiates itk::ScalarImageKmeansImageFilter with float input, bool output, UseNonContiguousLabelsOn, and exactly one initial mean.
  • Attempted to compile and run the harness, but the build could not proceed because itkConfigure.h was missing in this environment.
  • Inspected the environment for build tooling and found that cmake, ctest, ninja, itkConfigure.h, ITKConfig.cmake, and CMakeCache.txt were not present, so a real execution path could not be built here.
  • Validated the workflow and captured evidence showing the same missing build prerequisites, including the validation run and blocker state.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
Modules/Segmentation/Classifiers/include/itkScalarImageKmeansImageFilter.hxx Adds a non-contiguous label representability check, but rejects the valid one-class bool output case.
Modules/Segmentation/Classifiers/itk-module.cmake Adds ITKGoogleTest as a test dependency for the module.
Modules/Segmentation/Classifiers/test/CMakeLists.txt Registers a GoogleTest driver for the new Classifiers test source.
Modules/Segmentation/Classifiers/test/itkScalarImageKmeansImageFilterGTest.cxx Adds a regression test that expects too many non-contiguous labels to throw.

Reviews (1): Last reviewed commit: "BUG: Reject class counts that overflow n..." | Re-trigger Greptile

Comment thread Modules/Segmentation/Classifiers/include/itkScalarImageKmeansImageFilter.hxx Outdated
@hjmjohnson hjmjohnson force-pushed the bug-scalar-kmeans-label-interval-6575 branch from 8138a84 to 2c8a6ea Compare July 13, 2026 23:48
@hjmjohnson

Copy link
Copy Markdown
Member

Second force-push = review fixes from a high-effort automated review: the precondition is now compiled only for integral output pixel types (casting a float/double max() to an integer was undefined behavior), and the label/interval arithmetic in GenerateData() is std::uintmax_t so the distinct-label guarantee actually holds for 64-bit output pixel types (the previous unsigned int truncated the interval). ctest -R 'Kmeans|Classifiers': 11/11 pass.

@hjmjohnson hjmjohnson force-pushed the bug-scalar-kmeans-label-interval-6575 branch 2 times, most recently from 42cc8a3 to 602a6a6 Compare July 14, 2026 18:34
Non-contiguous label spacing divides the output pixel range by
the class count; once that quotient drops below 2, the interval
computation underflows in unsigned arithmetic and produces
wrapped label values instead of a diagnosable error.

Addresses item B14 of InsightSoftwareConsortium#6575.

Co-Authored-By: Hans J. Johnson <hans-johnson@uiowa.edu>
@hjmjohnson hjmjohnson force-pushed the bug-scalar-kmeans-label-interval-6575 branch from 602a6a6 to cf1c5f2 Compare July 16, 2026 01:08
@hjmjohnson

Copy link
Copy Markdown
Member

Force-push 602a6a6b157 → cf1c5f22c22 = plain rebase onto latest upstream/main (108 commits), no content change — git range-diff shows the single commit identical (=). Now 0 behind; this also re-runs the CI that hit a transient ExternalData download flake (VisibleHumanMale1608.png) on Pixi-Cxx (ubuntu-22.04).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Segmentation Issues affecting the Segmentation module 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