Skip to content

ENH: Add StructuralSimilarity Beta module (SSIM image filter) — stacked on #6085#6034

Closed
hjmjohnson wants to merge 2 commits intoInsightSoftwareConsortium:mainfrom
hjmjohnson:copilot/add-structural-similarity-filter-clean
Closed

ENH: Add StructuralSimilarity Beta module (SSIM image filter) — stacked on #6085#6034
hjmjohnson wants to merge 2 commits intoInsightSoftwareConsortium:mainfrom
hjmjohnson:copilot/add-structural-similarity-filter-clean

Conversation

@hjmjohnson
Copy link
Copy Markdown
Member

@hjmjohnson hjmjohnson commented Apr 10, 2026

Adds Modules/Beta/StructuralSimilarity/ containing StructuralSimilarityImageFilter (SSIM, Wang et al. 2004). Stacked on #6085 — relocating out of Modules/Filtering/ImageCompare/ into the new Modules/Beta/ container so the API can stabilize before promotion to a core module. Merge #6085 first; this PR's base is still main only because GitHub won't accept a base branch from a fork.

What changed vs. the previous revision of this PR

Previous revision placed the filter in Modules/Filtering/ImageCompare/ and touched that module's itk-module.cmake (adding ITKSmoothing / ITKGoogleTest deps). That perturbed a core module's dependency surface for a brand-new filter whose API has not yet been exercised by downstream users.

This revision:

  • Moves all SSIM files into a self-contained Modules/Beta/StructuralSimilarity/ module
  • Leaves Modules/Filtering/ImageCompare/ completely untouched
  • Adds a Modules/Beta/StructuralSimilarity.beta.cmake provenance manifest
  • Renames \ingroup ITKImageCompare\ingroup StructuralSimilarity in the header
  • Unchanged: filter implementation (.h/.hxx), GoogleTest suite, Python .wrap
Module layout
Modules/Beta/
├── StructuralSimilarity.beta.cmake         # provenance manifest
└── StructuralSimilarity/
    ├── itk-module.cmake                    # DEPENDS ITKImageIntensity
    │                                       # COMPILE_DEPENDS ITKImageFilterBase, ITKSmoothing
    │                                       # TEST_DEPENDS ITKTestKernel, ITKGoogleTest
    ├── CMakeLists.txt
    ├── include/
    │   ├── itkStructuralSimilarityImageFilter.h
    │   └── itkStructuralSimilarityImageFilter.hxx
    ├── test/
    │   ├── CMakeLists.txt                  # creategoogletestdriver
    │   └── itkStructuralSimilarityImageFilterGTest.cxx
    └── wrapping/
        ├── CMakeLists.txt
        └── itkStructuralSimilarityImageFilter.wrap   # WRAP_ITK_REAL, 2D

@github-actions github-actions bot added type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots type:Enhancement Improvement of existing methods or implementation area:Python wrapping Python bindings for a class type:Testing Ensure that the purpose of a class is met/the results on a wide set of test cases are correct area:Filtering Issues affecting the Filtering module labels Apr 10, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 10, 2026

Greptile Summary

This PR adds a new StructuralSimilarityImageFilter implementing the Wang et al. 2004 SSIM metric as an N-dimensional, multi-threaded composite ITK filter. The implementation is thorough: five internal DiscreteGaussianImageFilter passes feed a parallelized per-pixel combination stage, with mean SSIM averaged over the cropped interior region matching the scikit-image/MATLAB reference. All 30 GTests pass locally. Two minor correctness edge-cases are worth noting before merge.

Confidence Score: 5/5

Safe to merge; all findings are P2 style/edge-case suggestions that do not affect the default use case.

The algorithm is correct for the default configuration (σ=1.5, 11×11 kernel, K1=0.01, K2=0.03, L from NumericTraits). The two flagged gaps — border-crop formula for even kernel widths, and no guard against K1/K2=0 NaN — are P2 edge cases that do not affect any of the 30 passing tests or the documented API. The test coverage is comprehensive and the implementation closely follows Wang 2004 and scikit-image.

itkStructuralSimilarityImageFilter.hxx lines 106–122 (K1/K2 validation) and line 240 (border-crop formula).

Important Files Changed

Filename Overview
Modules/Filtering/ImageCompare/include/itkStructuralSimilarityImageFilter.h Public API and class declaration; well-structured with standard ITK macros. Documentation note: header comment still says "BeforeGenerate" though validation is in VerifyPreconditions (flagged in previous thread).
Modules/Filtering/ImageCompare/include/itkStructuralSimilarityImageFilter.hxx Core implementation; simplified and general SSIM paths are correct. Two edge-case gaps: K1/K2=0 produces silent NaN for constant/zero-mean inputs, and the border-crop formula diverges from scikit-image for even MaximumKernelWidth values.
Modules/Filtering/ImageCompare/test/itkStructuralSimilarityImageFilterGTest.cxx 30 GTest cases covering identities, analytic constant-image checks, input validation, qualitative properties, scikit-image cross-checks, code-path equivalence, and multi-dimensional/pixel-type coverage. Well-designed and comprehensive.
Modules/Filtering/ImageCompare/itk-module.cmake Adds ITKSmoothing as COMPILE_DEPENDS (correct for template-only dependency) and ITKGoogleTest as TEST_DEPENDS. No issues.
Modules/Filtering/ImageCompare/test/CMakeLists.txt Adds creategoogletestdriver for the new GTest file; GTest auto-discovery handles CTest registration, confirmed by author's ctest run showing 30 tests.
Modules/Filtering/ImageCompare/wrapping/itkStructuralSimilarityImageFilter.wrap Wraps for WRAP_ITK_REAL (float/double) in 2D, consistent with SimilarityIndexImageFilter's wrapping pattern. Appropriate starting point.

Reviews (3): Last reviewed commit: "ENH: Add StructuralSimilarityImageFilter..." | Re-trigger Greptile

@blowekamp

This comment has been minimized.

@hjmjohnson

This comment has been minimized.

@hjmjohnson hjmjohnson marked this pull request as draft April 10, 2026 13:21
@blowekamp

This comment has been minimized.

@dzenanz

This comment has been minimized.

@hjmjohnson

This comment has been minimized.

@dzenanz

This comment has been minimized.

@hjmjohnson

This comment has been minimized.

@hjmjohnson
Copy link
Copy Markdown
Member Author

The lone failing check (ITK.Linux on Azure DevOps build 15505) appears to be a pipeline-side flake rather than a real build/test issue:

  • CDash reports "All builds completed successfully" for SHA 46fabd3525 — meaning the same Linux ITK build that Azure ran successfully completed, ran its tests, and submitted the green results to CDash.
  • ✅ Every other Linux build passes:
    • Pixi-Cxx (ubuntu-22.04)
    • ARMBUILD-Ubuntu-24.04-arm
    • ARMBUILD-x86_64-rosetta ✓ (macOS but same toolchain class)
  • ✅ Every other Azure pipeline passes:
    • ITK.Windows
    • ITK.macOS
    • ITK.Linux.Python
    • ITK.macOS.Python
  • ✅ The 30 new SSIM GTests run and pass on ARMBUILD-Python (verified in the run log: tests FindPython3.cmake unavailable before CMake 3.12 #1700Add lambda function command #1735 all Passed).

The pattern (lone Azure pipeline failing, CDash green, all duplicate-coverage Linux builds green) almost always means the failure is in a post-CTest infrastructure step in the Azure pipeline (cache save, artifact upload, agent cleanup), not in the build itself. Re-triggering.

@hjmjohnson
Copy link
Copy Markdown
Member Author

/azp run ITK.Linux

Copy link
Copy Markdown
Member

@blowekamp blowekamp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some comment on pipeline management details.

The implementation this feeling is going to be rather memory intensive with the number of image converted and processed to real type.

Is this a 2D only implementation?

Comment thread Modules/Filtering/ImageCompare/include/itkStructuralSimilarityImageFilter.hxx Outdated
@hjmjohnson
Copy link
Copy Markdown
Member Author

Updated diagnosis: the ITK.Linux failure was a real one in the legacy-removed Linux build (the Azure pipeline runs both a normal and an ITK_LEGACY_REMOVE=ON configuration; the normal one was green on CDash, hence the misleading "all builds completed successfully" CDash summary, but the legacy-removed one promoted a deprecation warning into an error).

The root cause:

itkStructuralSimilarityImageFilter.hxx:342:87:
warning: 'itk::ImageConstIterator<TImage>::IndexType
itk::ImageConstIterator<TImage>::GetIndex() const' is deprecated:
Please use ComputeIndex() instead, or use an iterator with index,
like ImageIteratorWithIndex! [-Wdeprecated-declarations]

  342 |   if (subInterior.GetNumberOfPixels() > 0 && subInterior.IsInside(outIt.GetIndex()))

The output iterator was a plain ImageRegionIterator, and the per-pixel loop called outIt.GetIndex() to test interior-region membership for the mean accumulator. GetIndex() on the index-less iterator is wrapped in #ifndef ITK_FUTURE_LEGACY_REMOVE (Modules/Core/Common/include/itkImageConstIterator.h:306-317) and emits a deprecation warning under ITK_LEGACY_REMOVE. CI promotes that warning to an error.

Fix (commit f4316869e7): switch the output iterator to ImageRegionIteratorWithIndex, which tracks the index natively and exposes a non-deprecated GetIndex(). One-line change: replace the using OutputIteratorType = ImageRegionIterator<OutputImageType> typedef and add the corresponding header include.

Local verification:

$ cmake -B build-ssim-legacy -S . -G Ninja \
       -DITK_LEGACY_REMOVE=ON -DITK_LEGACY_SILENT=OFF ...
$ cmake --build build-ssim-legacy -j 4 \
       --target ITKImageCompareHeaderTest1 ITKImageCompareGTestDriver
[1/4] Building CXX object .../ITKImageCompareHeaderTest1.dir/test/ITKImageCompareHeaderTest1.cxx.o
[2/4] Linking CXX executable bin/ITKImageCompareHeaderTest1
[3/4] Building CXX object .../itkStructuralSimilarityImageFilterGTest.cxx.o
[4/4] Linking CXX executable bin/ITKImageCompareGTestDriver

No deprecation warnings, clean build.

$ ./bin/ITKImageCompareGTestDriver --gtest_filter='StructuralSimilarityImageFilter.*'
[==========] 30 tests from 1 test suite ran. (333 ms total)
[  PASSED  ] 30 tests.

All 30 SSIM GTests still pass under the legacy-removed build with the new iterator.

@hjmjohnson hjmjohnson force-pushed the copilot/add-structural-similarity-filter-clean branch from f431686 to c4721ab Compare April 10, 2026 19:02
@hjmjohnson hjmjohnson force-pushed the copilot/add-structural-similarity-filter-clean branch from c4721ab to 80a2e9a Compare April 12, 2026 02:35
@hjmjohnson
Copy link
Copy Markdown
Member Author

@greptileai review this draft before I make it official

@hjmjohnson hjmjohnson marked this pull request as ready for review April 12, 2026 02:48
hjmjohnson added a commit to hjmjohnson/ITKRemoteAnalysis that referenced this pull request Apr 14, 2026
N-dimensional, multi-threaded ITK filter for the Structural Similarity
Index Measure (Wang et al., IEEE TIP 2004). Two inputs in, a per-pixel
SSIM map out, and a scalar mean SSIM available via GetMeanSSIM() after
Update().

Restructured from ITK PR #6034 (in-tree ImageCompare addition) to
standalone remote module format for ITKRemoteAnalysis category repo.

Original PR: InsightSoftwareConsortium/ITK#6034
@hjmjohnson hjmjohnson marked this pull request as draft April 15, 2026 14:34
@hjmjohnson hjmjohnson requested a review from thewtex April 15, 2026 14:34
@hjmjohnson hjmjohnson changed the title ENH: Add StructuralSimilarityImageFilter for SSIM image quality WIP: MOVE TO EXTERNAL PROJET ENH: Add StructuralSimilarityImageFilter for SSIM image quality Apr 15, 2026
@hjmjohnson hjmjohnson force-pushed the copilot/add-structural-similarity-filter-clean branch from 80a2e9a to aa5fd89 Compare April 16, 2026 02:00
@github-actions github-actions bot removed the type:Enhancement Improvement of existing methods or implementation label Apr 16, 2026
Introduces Modules/Beta/ as the in-tree home for modules that were
formerly configure-time remote fetches (Modules/Remote/*.remote.cmake).

Modules/Beta/CMakeLists.txt defines a no-op itk_beta_module_manifest()
function so that provenance files (Modules/Beta/<Name>.beta.cmake) are
valid CMake and can be include()-d without build-time side effects.
Actual modules grafted under Modules/Beta/<Name>/ are discovered via
the existing itk-module.cmake DAG scan in ITKModuleEnablement.cmake.

No modules are ingested by this commit; this only wires the container.
Introduces a new Modules/Beta/StructuralSimilarity/ module containing
StructuralSimilarityImageFilter, which computes the Structural
Similarity Index (SSIM) between two images using a sliding Gaussian
window over local luminance, contrast, and structure terms.

Reference: Wang et al., "Image quality assessment: From error
visibility to structural similarity," IEEE TIP 13(4), 2004.

Placed under Modules/Beta/ (stacked on the Modules/Beta/ container
introduced by the parent commit) so the API can stabilize before
promotion to a core ITK module. Original proposal placed the filter
in Modules/Filtering/ImageCompare; the Beta location lets it mature
without perturbing a core module's API surface.

Module contents:
  itk-module.cmake              - DEPENDS ITKImageIntensity;
                                  COMPILE_DEPENDS ITKImageFilterBase,
                                  ITKSmoothing; TEST_DEPENDS
                                  ITKTestKernel, ITKGoogleTest
  include/                      - header + templated impl (.hxx)
  test/                         - GoogleTest-based test suite
  wrapping/                     - Python wrapping for WRAP_ITK_REAL 2D
  ../StructuralSimilarity.beta.cmake - provenance manifest
@hjmjohnson hjmjohnson force-pushed the copilot/add-structural-similarity-filter-clean branch from aa5fd89 to c865deb Compare April 19, 2026 14:25
@github-actions github-actions bot removed the area:Filtering Issues affecting the Filtering module label Apr 19, 2026
@hjmjohnson hjmjohnson changed the title WIP: MOVE TO EXTERNAL PROJET ENH: Add StructuralSimilarityImageFilter for SSIM image quality ENH: Add StructuralSimilarity Beta module (SSIM image filter) — stacked on #6085 Apr 19, 2026
@hjmjohnson
Copy link
Copy Markdown
Member Author

Superseded by #6094, which places the SSIM filter as a standalone module at Modules/Filtering/StructuralSimilarity/ based directly on upstream/main — no dependency on the rejected Modules/Beta/ approach (#6085). All reviewer feedback from this PR has been incorporated.

@hjmjohnson hjmjohnson closed this Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:Python wrapping Python bindings for a class 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.

4 participants