InsightSoftwareConsortium / InsightSoftwareConsortium/ITK
ENH: Give `itkCurvatureRegistrationFilter` a single-precision (fftwf_*) r2r/DCT path
- Dominant language
- C++
- Stars
- 1.7k
- Forks
- 748
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 64
Description
`itkCurvatureRegistrationFilter` is still hardcoded to the double-precision FFTW real-to-real (DCT) API, so it is compiled out entirely in `ITK_USE_FFTWF`-only builds.
The generic fix already exists — `fftw::Proxy::Plan_r2r` — and the VariationalRegistration curvature regularizer already uses it. This filter should be migrated the same way, then its `ITK_USE_FFTWD` guard relaxed.
Background and current state on main
`itk::fftw::Proxy` historically wrapped only the c2c / r2c / c2r transforms, not FFTW's real-to-real (r2r / DCT) transforms. Code needing a DCT therefore called the bare, double-only `fftw_*` API. In an `ITK_USE_FFTWF=ON` / `ITK_USE_FFTWD=OFF` build those translation units failed to compile (float buffers passed to `fftw_plan_r2r`, plan-type mismatch), e.g.:
```
itkVariationalRegistrationCurvatureRegularizer.hxx:207:45: error:
cannot convert 'itk::fftw::Proxy::PixelType*' {aka 'float*'} to 'double*'
... incompatible pointer types assigning to 'fftwf_plan_s *' from 'fftw_plan'
```
PR #6330 unblocked the FFTWF-only build by guarding the DCT-based regularizers behind `ITK_USE_FFTWD`. Commit `8882eb0f86f` ("ENH: Single-precision FFTW support for DCT-based regularizers") then did the real work for one of the two:
- `Modules/Filtering/FFT/include/itkFFTWCommon.h` — `Plan_r2r` added to both precisions: float overload at lines **377-412**, double overload at lines **752-787**.
- `Modules/Registration/VariationalRegistration/include/itkVariationalRegistrationCurvatureRegularizer.hxx` — now calls `FFTWProxyType::Plan_r2r` (lines **200** and **213**); the module guard at line **21** is already `#if defined(ITK_USE_FFTWD) || defined(ITK_USE_FFTWF)`, matching the `.h` at line 24.
Remaining work — file:line evidence
`Modules/Registration/PDEDeformable/include/itkCurvatureRegistrationFilter.h` (upstream/main):
- line **25-26**: `// precision here, so this filter requires ITK_USE_FFTWD.` / `#if !defined(ITK_USE_CUFFTW) && defined(ITK_USE_FFTWD)` (closing `#endif` at line **206**)
- line **138**: `using RealTypeDFT = double;` — precision hardcoded
- lines **193-194**: `fftw_plan m_PlanForwardDCT{}; fftw_plan m_PlanBackwardDCT{};` — double-only plan type
`Modules/Registration/PDEDeformable/include/itkCurvatureRegistrationFilter.hxx`:
- line **20**: `#if !defined(ITK_USE_CUFFTW) && defined(ITK_USE_FFTWD)` (closing `#endif` at line **278**)
- lines **147** and **158**: bare `fftw_plan_r2r(ImageDimension, ...)` calls (plus the accompanying `fftw_malloc` / `fftw_free` / `fftw_destroy_plan` / `fftw_execute` / `fftw_r2r_kind` usage)
`Modules/Registration/PDEDeformable/test/itkCurvatureRegistrationFilterTest.cxx`:
- line **21**: `#if defined(ITK_USE_FFTWD)` — test is skipped in FFTWF-only builds
Note: the `fftw_r2r_kind` enum type is shared across precisions; only the plan-creation / execute / malloc functions are precision-specific (`fftw_*` vs `fftwf_*`).
Suggested steps
1. In `itkCurvatureRegistrationFilter.h`, replace `RealTypeDFT = double` with a precision selected the same way `itkVariationalRegistrationCurvatureRegularizer.h` does (its `.h` line 92 `#if defined(ITK_USE_FFTWD)` block picking `RealTypeFFT`), and replace the raw `fftw_plan` members with `typename FFTWProxyType::PlanType`.
2. In the `.hxx`, replace the bare `fftw_plan_r2r` / `fftw_malloc` / `fftw_free` / `fftw_destroy_plan` / `fftw_execute` calls with the corresponding `FFTWProxyType::` entry points (`Plan_r2r`, `Malloc`, `Free`, `DestroyPlan`, `Execute`).
3. Relax the guards in `.h` (line 26), `.hxx` (line 20), and the test (line 21) to
`#if !defined(ITK_USE_CUFFTW) && (defined(ITK_USE_FFTWD) || defined(ITK_USE_FFTWF))`.
4. Validate numerically: DCT round-trip in float vs double on a known input; confirm `itkCurvatureRegistrationFilterTest` passes in an FFTWF-only build and in a dual-precision build.
`itkVariationalRegistrationElasticRegularizer` (c2c/r2c via `FFTWProxyType`) and the now-migrated `itkVariationalRegistrationCurvatureRegularizer` are the templates to follow.
Related
- PR #6330 — forced FFTWF-only Pixi CI; added the `ITK_USE_FFTWD` guards this issue relaxes.
- Commit `8882eb0f86f` (2026-05-23) — added `fftw::Proxy::Plan_r2r` and migrated the VariationalRegistration regularizer. Reference implementation.
- Companion test-coverage issue: exercise every enabled FFT precision in the 1D FFT tests (TODO L136).
---
Contributor guide
Research direction
Start with itkCurvatureRegistrationFilter.h and .hxx, then compare their FFT handling with itkVariationalRegistrationCurvatureRegularizer and itkFFTWCommon.h. Review itkCurvatureRegistrationFilterTest.cxx and run it in FFTWF-only and dual-precision builds. Done means the filter builds and passes its test with single and double precision, including the DCT round-trip behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- computer-vision, testing-qa
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 66/100