Undo (double) mirroring in ski2.morphology.dilation#8060
Undo (double) mirroring in ski2.morphology.dilation#8060lagru merged 18 commits intoscikit-image:mainfrom
ski2.morphology.dilation#8060Conversation
ski2.morphology.dilation
ski2.morphology.dilationski2.morphology.dilation
Inside `scipy.ndimage.grey_dilation` the footprint is inverted/mirrored. This inversion is intentional so that the composition of erosion and dilation lead to a correct closing and opening. `skimage.morphology.dilation` accidentally undoes this by mirroring the footprint, before passing it to `scipy.ndimage.grey_dilation`. `skimage.morphology.closing` and `skimage.morphology.black_tophat` then mirror/invert again to correct for this. In `skimage2` we drop all mirroring and align with SciPy. This function documents this procedure and ensures the wrappers around `skimage2` keep the old behavior for `skimage.morphology.dilation`, `skimage.morphology.closing` and `skimage.morphology.black_tophat`. `skimage.morphology.erosion`, `skimage.morphology.opening` and `skimage.morphology.white_tophat` _aren't_ affected.
This comment was marked as outdated.
This comment was marked as outdated.
There was a problem hiding this comment.
Actionable comments posted: 6
🧹 Nitpick comments (2)
src/skimage/morphology/footprints.py (1)
9-9: Use relative import instead of absolute import.This line uses an absolute import, but the coding guidelines specify using relative module imports within
src/skimage/**/*.py.♻️ Proposed fix
-from skimage import morphology +from . import _top_level_morphology as morphologyAlternatively, if the import is only used in
footprint_from_sequenceat line 100, consider importing directly where needed or restructuring to avoid the circular dependency that may have motivated this pattern.As per coding guidelines: "Use relative module imports (e.g.,
from .._shared import xyzinstead offrom skimage._shared import xyz)".tests/skimage2/morphology/test_grayscale_operators.py (1)
52-66: Consider extracting the test data loading to a fixture.The NPZ file is loaded on every parameterized test execution (36 times for this test alone). Using a module-scoped fixture would reduce redundant I/O.
Additionally, there's a minor inconsistency:
np.testing.assert_equalis used here whileassert_array_equal(which is already imported) is used elsewhere in the file.♻️ Proposed fixture to cache test data
`@pytest.fixture`(scope="module") def gray_morph_expected_data(): return dict(np.load(fetch('data/gray_morph_output.npz')))Then use
gray_morph_expected_datain both test methods:- def test_reproduce_skimage_data_not_mirrored(self, footprint_args, size, func): + def test_reproduce_skimage_data_not_mirrored(self, footprint_args, size, func, gray_morph_expected_data): ... footprint_name, footprint_func = footprint_args key = f'{footprint_name}_{size}_{func.__name__}' - data = dict(np.load(fetch('data/gray_morph_output.npz'))) - expected = data[key] + expected = gray_morph_expected_data[key] footprint = footprint_func(size) result = func(image, footprint, mode="reflect") - np.testing.assert_equal(result, expected) + assert_array_equal(result, expected)
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
doc/source/conf.pydoc/source/user_guide/skimage2_migration.mdenvironment.ymlpyproject.tomlrequirements/docs.txtsrc/skimage/morphology/footprints.pysrc/skimage/morphology/gray.pysrc/skimage2/morphology/_grayscale_operators.pytests/skimage2/morphology/test_grayscale_operators.py
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
doc/source/user_guide/skimage2_migration.md (1)
134-134:⚠️ Potential issue | 🟡 MinorFix grammar in the migration note sentence.
Line 134 should read “This only impacts behavior...” (current text has incorrect grammar: “does only impacts”).
✏️ Proposed fix
- This does only impacts behavior for asymmetric/eccentric footprints. + This only impacts behavior for asymmetric/eccentric footprints.
ℹ️ Review info
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
doc/source/user_guide/skimage2_migration.mdsrc/skimage/morphology/footprints.pysrc/skimage/morphology/gray.py
| are deprecated in favor of counterparts in `skimage2.morphology` with new behavior: | ||
|
|
||
| - All functions now default to `mode='ignore'` (was `mode='reflect'`). | ||
| - Additionally, `skimage.morphology.dilation`, `skimage.morphology.closing`, and `skimage.morphology.black_tophat` now also mirror the footprint (invert its order in each dimension). |
There was a problem hiding this comment.
| - Additionally, `skimage.morphology.dilation`, `skimage.morphology.closing`, and `skimage.morphology.black_tophat` now also mirror the footprint (invert its order in each dimension). | |
| - Additionally, `skimage2.morphology.dilation`, `skimage2.morphology.closing`, and `skimage2.morphology.black_tophat` now mirror the footprint (i.e., invert its order in each dimension). |
There was a problem hiding this comment.
Good catch!
I don't think i.e. is well known. I'll expand it to that is. Same logic as for e.g. to for example.
There was a problem hiding this comment.
Or do you think
now mirror the footprint (that is, invert its order in each dimension).
reads weirdly?
There was a problem hiding this comment.
Using "that is" is correct, for sure. It's just that "i.e." is particularly fitting in a technical context and even more specifically in {parentheses, footnotes, references} (and it is 'well-known').
There was a problem hiding this comment.
Well, I had to look up the exact meaning of "i.e.". I don't think that knowledge gap would have hindered me in practice, but I've been thinking about avoiding latin-derived acronyms in technical writing.
But I grant you that many in our academic audience are familiar with this. I did some digging and came up with this somewhat opinionated article. I'm curious what you think, and interested in finding common ground, since I suspect that we might encounter this again otherwise.
Feel welcome to push yourself or let me know if I should do so.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/skimage/morphology/gray.py (1)
46-54: Make the warning snippet self-contained.This message tells users to call
ski2.morphology.*, butski2is never introduced in the warning itself. Using fully qualifiedskimage2.morphology.pad_footprint/skimage2.morphology.mirror_footprint, or adding the import line, would make the migration hint copy-pasteable as-is.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: e6ef00f9-7db0-4b87-a4cd-ddc461403bd6
📒 Files selected for processing (4)
doc/source/user_guide/skimage2_migration.mdsrc/skimage/morphology/gray.pysrc/skimage2/morphology/_grayscale_operators.pytests/skimage2/morphology/test_grayscale_operators.py
| # `dilation`, `closing`, `black_tophat` need a more specific warning. | ||
| # See `_patch_footprint_mirroring` | ||
| _PENDING_SKIMAGE2_TEMPLATE_MIRROR = """\ | ||
| `skimage.morphology.{name}` is deprecated in favor of |
There was a problem hiding this comment.
Do you mean a hyperlink to the HTML version of the migration guide?
Co-authored-by: Stefan van der Walt <github@mentat.za.net> fixup
stefanv
left a comment
There was a problem hiding this comment.
Looks good to me! Ready to merge?
* 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) ...
Description
Follows up on #8046. Among smaller outstanding tweaks, this undoes the accidental mirroring in
skimage2.morphology.dilation.Inside
scipy.ndimage.grey_dilationthe 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.dilationaccidentally undoes this by inverting again. So inskimage2.morphology.dilationwe drop the mirroring and align with SciPy (see also #6676).Todo:
De-duplicate test suite intest_grayscale_operators.pyskimage2now while I have the context and also be more sure of correctness.Consider dropping the usage ofgray_morph_output.npzin tests (very opaque and hard to modify)Checklist
./doc/examplesfor new featuresRelease note
For maintainers and optionally contributors, please refer to the instructions on how to document this PR for the release notes.