-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix clip bug in resize when anti_aliasing is applied (#5202) #5209
Conversation
clipping was performed based on the values of the filtered image and not the input image, which can produce values outside of input values range. Added clarification on kwarg anti_aliasing description: it is applied by default for non bool type inputs when downsizing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @abouysso, I think that the 2D case is not fixed with the proposed approach :(
Can you please also add a test?
skimage/transform/_warps.py
Outdated
@@ -172,12 +174,12 @@ def resize(image, output_shape, order=None, mode='reflect', cval=0, clip=True, | |||
tform.params[0, 1] = 0 | |||
tform.params[1, 0] = 0 | |||
|
|||
out = warp(image, tform, output_shape=output_shape, order=order, | |||
out = warp(img_in, tform, output_shape=output_shape, order=order, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The proposed solution doesn't work in this case since the clipping is made in warp
😕
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for pointing this out ! Fixed it in fallback code by performing clipping outside of warp function 😃.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent idea! The _clip_warp_output
call can be performed outside the if ... elif ... else ...
block once for all now 😉
Also removed unnecessary copy of the input data.
I ran in another issue, also related to potential out of input range values produced by I see two ways of doing so:
|
This allows _clip_warp_output to clip out of input range values when caused by gaussian filter and not interpolation function.
Hello @abouysso! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:
Comment last updated at 2021-11-21 23:29:06 UTC |
Co-authored-by: Riadh Fezzani <rfezzani@gmail.com>
skimage/transform/_warps.py
Outdated
np.asarray(output_shape, dtype=float)) | ||
factors = np.divide(input_shape, output_shape) | ||
# create copy so input values range stays accessible through image for clip | ||
img_in = image |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see a case where this approach doesn't work: when image dtype is not floating point... In the case of uint8
for example, values will not be clipped between 0 and 1 as it is supposed to be...
We must call convert_to_float
here to fix this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed there could still be an issue when preserve_range
is False 😄 Otherwise values will be clipped between 0 and 255 as expected. I will correct this as you suggested !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, personally I dislike reassigning values in the middle of a function, so, rather than copy image to image_in then overwriting image, how about just renaming the downstream images? ie below, use image_smoothed = ndi.gaussian_filter(image, ...)
. What do you think @abouysso?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's in fact an option, but you need to define image_smoothed
even when anti_aliasing is False
in this case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I instead created img_bounds
to save input image bounds for later clipping... Though?
Clipping is performed w.r.t the values of image. In case preserve_range is False, for uint8 data for example, the reference can be outdated and produce unexpected behavior of clipping. Because data types checks are performed, a new variable input_type is defined to store input dtype.
Test is performed with preserve_range True and False
You forgot to import |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @abouysso, it looks good! @scikit-image/core, the PR is ready for review 😉. CI failures seems unrelated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@scikit-image/core, can anyone please find some time to review this, thanks 😉 |
down-sizing now used consistently in resize function, so its clearer than previous mix between down-sizing, down-sampling and down-scaling.
Co-authored-by: Marianne Corvellec <marianne.corvellec@ens-lyon.org>
…mage into fix-issue-5202
…nto fix-issue-5202
Thanks for pointing this out ! I'm working on it, conflict is solved locally, but new errors are raised on pytest. A quick look seems to indicate those errors comes from test functions modified in #5327 . I still have to find the issue 😄 |
This allows to give the expected dtype as input of ndi.gaussian_filter when anti-aliasing is performed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@abouysso apologies that it has taken so long to to review this... Our team members have been rather overwhelmed this year. I've left a couple of comments but this should be ready very quickly! Do you have the time/inclination to look at my comments, or would you rather we take over from here?
Thank you!
skimage/transform/_warps.py
Outdated
@@ -133,17 +139,13 @@ def resize(image, output_shape, order=None, mode='reflect', cval=0, clip=True, | |||
warn("Anti-aliasing standard deviation greater than zero but " | |||
"not down-sampling along all axes") | |||
image = ndi.gaussian_filter(image, anti_aliasing_sigma, | |||
cval=cval, mode=ndi_mode) | |||
cval=cval, mode=ndi_mode) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cval=cval, mode=ndi_mode) | |
cval=cval, mode=ndi_mode) |
skimage/transform/_warps.py
Outdated
np.asarray(output_shape, dtype=float)) | ||
factors = np.divide(input_shape, output_shape) | ||
# create copy so input values range stays accessible through image for clip | ||
img_in = image |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, personally I dislike reassigning values in the middle of a function, so, rather than copy image to image_in then overwriting image, how about just renaming the downstream images? ie below, use image_smoothed = ndi.gaussian_filter(image, ...)
. What do you think @abouysso?
Co-authored-by: Juan Nunez-Iglesias <juan.nunez-iglesias@monash.edu>
Co-authored-by: Juan Nunez-Iglesias <juan.nunez-iglesias@monash.edu>
Co-authored-by: Juan Nunez-Iglesias <juan.nunez-iglesias@monash.edu>
Co-authored-by: Juan Nunez-Iglesias <juan.nunez-iglesias@monash.edu>
@scikit-image/core, I added this PR to 0.19 milestone because it is close and think it fixes |
skimage/transform/_warps.py
Outdated
@@ -220,7 +220,6 @@ def resize(image, output_shape, order=None, mode='reflect', cval=0, clip=True, | |||
preserve_range=preserve_range) | |||
|
|||
else: # n-dimensional interpolation | |||
order = _validate_interpolation_order(input_type, order) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch @grlee77
🎉 Thank you @grlee77 |
Description
Clipping was performed based on the values of the filtered image and not
the input image, which can produce values outside of input values range.
Added clarification on kwarg anti_aliasing description: it is applied by
default for non bool type inputs when downsizing.
Closes #5202
Checklist
./doc/examples
(new features only)./benchmarks
, if your changes aren't covered by anexisting benchmark
For reviewers
later.
__init__.py
.doc/release/release_dev.rst
.