Skip to content

Port grayscale morphology operators to skimage2#8046

Merged
mkcor merged 26 commits intoscikit-image:mainfrom
lagru:sk2-gray-morph-operators
Feb 18, 2026
Merged

Port grayscale morphology operators to skimage2#8046
mkcor merged 26 commits intoscikit-image:mainfrom
lagru:sk2-gray-morph-operators

Conversation

@lagru
Copy link
Copy Markdown
Member

@lagru lagru commented Jan 31, 2026

Description

Ports our grayscale morphological operators to the skimage2 namespace and implements proposed changes listed in #7238.

#7238 also proposes changes to make the binary and grayscale operators behave consistently and notes that either convention is fine. Since we are deprecating the binary operators in 0.28. I propose that we don't actually need to address these. The deprecation itself will get rid of one half of the inconsistent behavior.

Checklist

Release note

For maintainers and optionally contributors, please refer to the instructions on how to document this PR for the release notes.

...

@lagru lagru added this to skimage2 Jan 31, 2026
@lagru lagru added 🔧 type: Maintenance Refactoring and maintenance of internals 🥾 Path to skimage2 A step towards the new "API 2.0" labels Jan 31, 2026
@github-project-automation github-project-automation bot moved this to To Do in skimage2 Jan 31, 2026
@lagru lagru moved this from To Do to In progress in skimage2 Jan 31, 2026
@lagru lagru marked this pull request as ready for review January 31, 2026 17:17
@coderabbitai

This comment was marked as outdated.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🧹 Nitpick comments (2)
tests/skimage2/morphology/test_grayscale_operators.py (1)

14-26: Redundant imports inside fixtures.

The from skimage import data statements on lines 16 and 23 are unnecessary since data is already imported at module level (line 6).

♻️ Suggested cleanup
 `@pytest.fixture`
 def cam_image():
-    from skimage import data
-
     return np.ascontiguousarray(data.camera()[64:112, 64:96])


 `@pytest.fixture`
 def cell3d_image():
-    from skimage import data
-
     return np.ascontiguousarray(data.cells3d()[30:48, 0, 20:36, 20:32])
src/skimage2/morphology/_grayscale_operators.py (1)

626-628: Inconsistent dtype check for boolean.

Line 627 uses np.bool_ while similar checks elsewhere (lines 529, 537, 620) use bool. Both work, but consistency improves readability.

♻️ Proposed fix for consistency
     out = closing(image, footprint, out=out, mode=mode, cval=cval)
-    if np.issubdtype(out.dtype, np.bool_):
+    if np.issubdtype(out.dtype, bool):
         np.logical_xor(out, image, out=out)

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/skimage2/morphology/_grayscale_operators.py (3)

5-7: Use project SciPy import convention (import scipy as sp).
The module currently uses from scipy import ndimage as ndi, which diverges from the project import convention. Switching to import scipy as sp keeps imports consistent and avoids extra aliases.

♻️ Proposed refactor
-from scipy import ndimage as ndi
+import scipy as sp
@@
-        operator=ndi.grey_erosion,
+        operator=sp.ndimage.grey_erosion,
@@
-        operator=ndi.grey_dilation,
+        operator=sp.ndimage.grey_dilation,
As per coding guidelines: Use the import convention: import numpy as np, import matplotlib.pyplot as plt, import scipy as sp, import skimage as ski.

Also applies to: 193-201, 296-303


8-13: Prefer relative imports for morphology helpers in skimage2.
These imports couple skimage2 directly to the v1 namespace. If the helpers are (or will be) available under skimage2.morphology, consider switching to relative imports to keep dependency direction clean.

♻️ Example (if skimage2 equivalents exist)
-from skimage.morphology.footprints import (
+from .footprints import (
     _footprint_is_sequence,
     mirror_footprint,
     pad_footprint,
 )
-from skimage.morphology.misc import default_footprint
+from .misc import default_footprint
As per coding guidelines: Use relative module imports (e.g., from .._shared import xyz rather than from skimage._shared import xyz).

113-118: Document array shapes in parameter sections (M, N) format.
The public API docstrings use image : ndarray; the guidelines require shape-aware forms like image : (M, N) ndarray and references to rows/columns. Please update across these functions.

📝 Example update (apply similarly to other functions)
-    image : ndarray
-        Input image.
+    image : (M, N) ndarray
+        Input image with M rows and N columns.
As per coding guidelines: When documenting array parameters, use the format 'image : (M, N) ndarray' and refer to M and N in the docstring.

Also applies to: 213-218, 316-321, 390-395, 463-468, 553-558

lagru and others added 2 commits February 4, 2026 13:57
Co-authored-by: Marianne Corvellec <marianne.corvellec@ens-lyon.org>
mkcor and others added 2 commits February 12, 2026 12:05
Co-authored-by: Stefan van der Walt <sjvdwalt@gmail.com>
Comment on lines +281 to +283
# Note that `ndi.grey_dilation` mirrors the footprint and this
# additional inversion should be removed in skimage2, see gh-6676.
footprint = mirror_footprint(footprint)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That's the reason for the change line 118 in tests/skimage/morphology/test_gray.py, right?

Valid modes are: 'reflect', 'constant', 'nearest', 'mirror', 'wrap',
'max', 'min', or 'ignore'.
If 'max' or 'ignore', pixels outside the image domain are assumed
to be the maximum for the image's dtype, which causes them to not
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@lagru grateful in advance if you double-check 🙏

@mkcor mkcor merged commit b235935 into scikit-image:main Feb 18, 2026
35 of 36 checks passed
@github-project-automation github-project-automation bot moved this from In progress to Done in skimage2 Feb 18, 2026
@stefanv stefanv added this to the 0.27 milestone Feb 18, 2026
@lagru
Copy link
Copy Markdown
Member Author

lagru commented Feb 19, 2026

@mkcor, I had some work in progress for this that I was still intending to push. Sorry, I should have marked this as a Draft. I will do a follow-up PR.

@lagru
Copy link
Copy Markdown
Member Author

lagru commented Feb 19, 2026

This pertains to the decision about mirroring the footprint and if we stick with our convention or align with SciPy's. See #8046 (comment).

@lagru
Copy link
Copy Markdown
Member Author

lagru commented Feb 19, 2026

Follow-up PR is #8060.

matusvalo pushed a commit to matusvalo/scikit-image that referenced this pull request Mar 4, 2026
## Description

Ports our grayscale morphological operators to the `skimage2` namespace
and implements proposed changes listed in scikit-image#7238.

scikit-image#7238 also proposes changes to make the binary and grayscale operators
behave consistently and notes that either convention is fine. Since we
are deprecating the binary operators in 0.28. I propose that we don't
actually need to address these. The deprecation itself will get rid of
one half of the inconsistent behavior.

## Checklist

<!-- Before pull requests can be merged, they should provide: -->

- A descriptive but concise pull request title
- [Docstrings for all
functions](https://github.com/numpy/numpydoc/blob/main/doc/example.py)
- [Unit
tests](https://scikit-image.org/docs/dev/development/contribute.html#testing)
- A gallery example in `./doc/examples` for new features
- [Contribution
guide](https://scikit-image.org/docs/dev/development/contribute.html) is
followed

## Release note

For maintainers and optionally contributors, please refer to the
[instructions](https://scikit-image.org/docs/stable/development/contribute.html#documenting-changes)
on how to document this PR for the release notes.

```release-note
...
```

---------

Co-authored-by: Marianne Corvellec <marianne.corvellec@ens-lyon.org>
Co-authored-by: Stefan van der Walt <sjvdwalt@gmail.com>
lagru added a commit that referenced this pull request Mar 15, 2026
Follows up on #8046. Among smaller outstanding tweaks, this undoes the
accidental mirroring in `skimage2.morphology.dilation`.

Inside `scipy.ndimage.grey_dilation` the footprint is inverted. This
inversion is intentional so that the composition of erosion and dilation
lead to a correct closing and opening. However,
`skimage.morphology.dilation` accidentally undoes this by inverting
again. So in `skimage2.morphology.dilation` we drop the mirroring and
align with SciPy (see also
#6676).

Due to the significant changes with regards to mirroring, I chose to
keep the test suites duplicated. This allows me to update the tests for
`skimage2` now while I have the context and also be more sure of
correctness.

Dropping the usage of `gray_morph_output.npz` in tests (very opaque and
hard to modify) is a problem for another time.

---------

Co-authored-by: Marianne Corvellec <marianne.corvellec@ens-lyon.org>
Co-authored-by: Stefan van der Walt <stefanv@berkeley.edu>
@lagru lagru deleted the sk2-gray-morph-operators branch March 15, 2026 16:29
matthew-brett added a commit that referenced this pull request Apr 10, 2026
* origin/main: (27 commits)
  Move `_shared` to `_skimage2` (#8102)
  Port `pad_footprint` & `mirror_footprint` to `skimage2` (#8094)
  Add rescaling API to skimage2 (#8075)
  Move `skimage2` implementation into `_skimage2` (#8093)
  Undo (double) mirroring in `ski2.morphology.dilation` (#8060)
  Grammar (#8091)
  Move `ensure_spacing` into `skimage2` (#8067)
  Ensure that `skimage2` does not eagerly import `skimage` (#8087)
  Use lazy-loader 0.5 (#8080)
  MAINT: make ellipse fitting forward compatible  (#8054)
  Avoid deprecated assign to ndarray.shape (#8020)
  Avoid circular import in `feature/corner.py` (#8077)
  Turn off coderabbit auto-labeling & label checks (#8070)
  Fix GIL being re-enabled by C++ extensions (#8059)
  Fix conventions following docstub and misc. (#8055)
  Port grayscale morphology operators to skimage2 (#8046)
  Add revised `peak_local_max` to `skimage2` (#8039)
  Allow read-only arrays as input to remap (#7535)
  Add `prescale`  parameter to "blob functions" (#7858)
  Try to make coderabbit respect exisiting type labels (#8042)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🥾 Path to skimage2 A step towards the new "API 2.0" 🔧 type: Maintenance Refactoring and maintenance of internals

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants