Skip to content

Add prescale parameter to "blob functions"#7858

Merged
lagru merged 57 commits intoscikit-image:mainfrom
lagru:prescale-blob-funcs
Feb 5, 2026
Merged

Add prescale parameter to "blob functions"#7858
lagru merged 57 commits intoscikit-image:mainfrom
lagru:prescale-blob-funcs

Conversation

@lagru
Copy link
Copy Markdown
Member

@lagru lagru commented Jul 24, 2025

Description

Implementation of the new strategy around value range scaling in our library that we extensively discussed in the recent sprint and meeting. We will add more detailed descriptions of this strategy but in short:

  • introduce a new prescale parameter for functions that actually need / benefit from prescaling the input image.
  • Add a dedicated private (for now) function for that. I plan to use this elsewhere in the future.

Checklist

Release note

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

In `skimage.feature`, add a new parameter `prescale` to the functions 
`blob_doh`, blob_dog`, and `blob_log`. This parameter controls the internal
rescaling behavior which makes it easier to set the `threshold` parameter 
correctly.
{label="New feature"}
In `skimage.feature`, deprecate the parameter `threshold_rel` in 
`blob_doh`, blob_dog`, and `blob_log`. The behavior of the parameters
effects were difficult to reason about. Instead, use `threshold` in
conjunction with the new parameter `prescale`.
{label="API"}

@lagru lagru added ⏩ type: Enhancement Improve existing features 📜 type: API Involves API change(s) 🥾 Path to skimage2 A step towards the new "API 2.0" labels Jul 24, 2025
lagru added 2 commits August 15, 2025 16:16
This makes heavy use of the scaling implementation that was proposed in
[1]. Furthermore, `ski._shared.utils` seesm like a more fitting place.

[1] https://www.github.com/scikit-image/scikit-image/pull/7697
@lagru lagru marked this pull request as ready for review August 28, 2025 16:54
@lagru lagru removed the ⏩ type: Enhancement Improve existing features label Aug 28, 2025
@lagru lagru changed the title Add prescale parameter to "blob functions" Add prescale function and similar parameter to "blob functions" Aug 28, 2025
@lagru lagru changed the title Add prescale function and similar parameter to "blob functions" Add prescale parameter to "blob functions" Aug 28, 2025
@lagru lagru requested review from matthew-brett and stefanv August 28, 2025 17:03
Copy link
Copy Markdown
Contributor

@matthew-brett matthew-brett left a comment

Choose a reason for hiding this comment

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

A few comments in passing.

I'm wondering about the divide by two heuristic. Will that always work?

lagru and others added 5 commits September 4, 2025 15:57
Co-authored-by: Matthew Brett <matthew.brett@gmail.com>
As pointed out by @stefanv, substraction with small floats can be
problematic – so do that before division by peak_to_peak.

Also handle NaNs and Infs in input value range explicitly. Cover
everything with tests.
@lagru lagru requested a review from stefanv September 22, 2025 16:59
That keyword is new in version 2 which isn't our minimal dependency yet.
However, going forward `strict=True` should probably be the default
at some point. It avoids unepexted suprises.
We are not sure yet if it is worth supporting and committing to this
option. We can always add it later if it is requested.
We are not really clear what behavior would be expected for NaN and inf
values. So instead, it's easier to just raise a ValueError for now,
encouraging users to handle this manually.
`_prescale_value_range` is really more of a helper function that ties
our old legacy scaling behavior and the new min-max scaling together.
It is meant as a convenience function to use in a few places where
our API needs to work with a well-behaved output range. We very
probably don't want to the slightly awkward API of
`_prescale_value_range` public.

Instead, if we want to later make something public. It's probably
something closer to a fresh API like `_minmax_scale_value_range`.
@lagru lagru requested a review from stefanv February 2, 2026 20:30
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

Copy link
Copy Markdown
Member

@stefanv stefanv left a comment

Choose a reason for hiding this comment

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

Some minor outstanding comments to address, but I'd say go ahead, fix what you can and merge.


See Also
--------
_rescale_value_range
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.

Suggested change
_rescale_value_range
_rescale

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Undecided if I want to take you up on this suggestion. I don't think it hurts at all to have _value_range in there to make it clear what is scaled?

But for now, I'll take you up on it and postpone the naming discussion for if we decide to make this function public.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Actually, scratch that. I propose to leave this more specific name for now to help differentiate it from:

  • rescale in skimage.transform
  • rescale_intensity in skimage.exposure
  • _rescale_sigma_rgb2ycbcr in skimage.restoration

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.

I'm also in favor of keeping the more specific name _rescale_value_range.

Copy link
Copy Markdown
Member

@mkcor mkcor left a comment

Choose a reason for hiding this comment

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

Thanks, @lagru! Just an extra round of iteration to agree on (user-facing) terms.

lagru and others added 2 commits February 3, 2026 14:13
Co-authored-by: Marianne Corvellec <marianne.corvellec@ens-lyon.org>
Co-authored-by: Stefan van der Walt <stefan@mentat.za.net>
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: 3

🧹 Nitpick comments (1)
src/skimage/_shared/utils.py (1)

1279-1281: Consider returning the input directly for mode="none".

Currently mode="none" returns image.copy(). If the intent is truly "do nothing," returning the original array without copying could be more efficient. However, if the copy is intentional to prevent mutation of the input, this is fine.

internally computed stack of Difference-of-Gaussian (DoG) images. This
in turn affects the effect of the `threshold` parameter.

``'minmax'``
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.

Test is OK, but I think simplest is just to make the scaling function public API and refer to it. Future PR is fine.

fe.params


class Test_minmax_scale_value_range:
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.

Suggested change
class Test_minmax_scale_value_range:
class TestMinmaxScaleValueRange:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Personally, I think the better "grep-ability" is totally worth breaking the camelCase convention here. But I don't care enough to block it, and since you both are in favor... 🤷

Copy link
Copy Markdown
Member Author

@lagru lagru Feb 5, 2026

Choose a reason for hiding this comment

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

Actually, the rest of that module already uses snake case in class names. So leaving it for now for local consistency. But I'll open a thread on Zulip where I propose that for skimage2 as a convention. Otherwise I'm happy to clean that up in our code base.

Edit: #development > skimage2 style guide @ 💬

@stefanv
Copy link
Copy Markdown
Member

stefanv commented Feb 4, 2026

Approved, feel free to merge when ready.

Copy link
Copy Markdown
Member

@mkcor mkcor left a comment

Choose a reason for hiding this comment

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

Thanks, @lagru! Leaving the nitpick to your judgement. Committing the trivial fixes now.

Comment on lines +1123 to +1124
Rescaling values between [0, 1], or *min-max normalization* [1]_,
is a simple method to ensure that data is inside a range.
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.

Suggested change
Rescaling values between [0, 1], or *min-max normalization* [1]_,
is a simple method to ensure that data is inside a range.
Rescaling or *min-max normalization* [1]_
is a simple method to ensure that all data values lie in a certain range.

(based on cited reference https://en.wikipedia.org/wiki/Feature_scaling#Rescaling_(min-max_normalization))

@lagru
Copy link
Copy Markdown
Member Author

lagru commented Feb 5, 2026

Merging if the CI stays green. 🤞

@lagru lagru merged commit 5d0aded into scikit-image:main Feb 5, 2026
26 checks passed
@github-project-automation github-project-automation bot moved this from To Review to Done in skimage2 Feb 5, 2026
@lagru lagru deleted the prescale-blob-funcs branch February 5, 2026 20:34
@stefanv stefanv added this to the 0.27 milestone Feb 5, 2026
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: API Involves API change(s)

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants