-
-
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
Allow float->float conversion of any range #3052
Conversation
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.
First of all, I don't think that the original issue is a bug at all.
From my standpoint, working with an image not satisfying our dtype conventions shouldn't be encouraged by the functions we ship.
On the other hand, there are some cases which the proposed modification could be justified for - e.g. when image intensity doesn't fully fit into [0; 1], [-1; 1] due to float representation innacuracies, or cases where preserve_range
is meant to be used.
If you are 100% sure that loosening a constraint here won't affect the usability of the library, I'm fine with the change.
@soupault no, our policy, which may or may not be enshrined in the docs [1], is not to mess with input data unless absolutely necessary. Secondly, we aim to preserve precision in our operations. If you want to preserve round-trip accuracy on >>> color.rgb2lab([[[1., 0., 0.]]])
array([[[53.24058794, 80.09230823, 67.20275104]]]) So, we must be able to deal with floating point values outside [0, 1]. Finally, any function that works for float64 and throws an error for float32 is buggy. Support for one (at the API level) should imply support for the other. You are potentially right that .. [1] The closest I could find is this from our data types page: "we aim to preserve the data range and type of input images". It is not strong enough wording. |
@jni I think this just needs a rebase. |
Fixes scikit-image#3051. When converting from float, we were checking for valid input ranges *before* checking whether the target format was also float, in which case the range doesn't matter. This PR corrects this so that float-only conversions, which don't entail any rescaling, don't check for input range.
Codecov Report
@@ Coverage Diff @@
## master #3052 +/- ##
==========================================
+ Coverage 85.91% 85.91% +<.01%
==========================================
Files 336 336
Lines 27305 27308 +3
==========================================
+ Hits 23459 23462 +3
Misses 3846 3846
Continue to review full report at Codecov.
|
I think this PR is incorrect. |
|
This should also be addressed by #3111 |
@stefanv I don't think the function name provides any indication of "I'm going to shoot you if your range is incorrect". For that I would use something like |
Also note that #3110 addresses a slightly different problem. |
This change pushes the responsibility for range checking down to each individual skimage function. Have we done a survey to check whether there are any of these that require the range |
There are more than we might expect, particularly in the exposure submodule, which do need the assumed float range. Probably also color conversion. It is worth noting that there are many other instances which will prove difficult to detect and correct - as some of our algorithms' parameters are dependent on the image range.
Not trying to rain on any parades; I do see the benefits of letting sleeping floats lie. But the behavior of using img_as_float as an input type AND range sanitizer is extremely long-standing and ingrained. Would it perhaps be better to retain the auto-scaling as default behavior, with the option to disable it for those who wish, or are unsatisfied with our current behavior? Alternatively, could we satisfy those who want to return to a standard range by providing a method where they can pass their image and we return the exact scaling factor which will be applied, so they can return the result to the same space? |
@JDWarner just to be clear: this PR does not change the conversion behaviour when an input image is within range. It only removes the assertion that an input float image must be within range when passing it through. This means that this will only break someone's code if they were try:ing and catching the ValueError in case of an out-of-range image. I find this scenario extremely unlikely. Going forward, we can (and should) have any functions that depend on an explicit range check to make that check explicitly. |
Here's another argument that I discovered while doing this audit: img = img_as_float(data.astronaut()[:256, :].mean(axis=2))`
|
@@ -94,6 +94,11 @@ def test_float_out_of_range(): | |||
img_as_int(too_low) | |||
|
|||
|
|||
def test_float_float_all_ranges(): | |||
arr_in = np.array([[-10., 10., 1e20]], dtype=np.float32) | |||
np.testing.assert_all_close(img_as_float(arr_in), arr_in) |
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.
Why is this not strict equality?
👍 |
🎉 |
@meeseeksdev please backport to v0.14.x |
@meeseeksdev backport to v0.14.x |
Haha turns out you can't be polite to a bot. No wonder they will eventually exterminate the human race. But, I tried! |
I'll see what I can do about that. @meeseeksdev please behave better. |
Awww, sorry Carreau you do not seem to be allowed to do that, please ask a repository maintainer. |
Lol. |
…2-on-v0.14.x Backport PR #3052 on branch v0.14.x (Allow float->float conversion of any range)
Fixes #3051.
When converting from float, we were checking for valid input ranges
before checking whether the target format was also float, in which
case the range doesn't matter. This PR corrects this so that float-only
conversions, which don't entail any rescaling, don't check for input
range.
Checklist
[It's fine to submit PRs which are a work in progress! But before they are merged, all PRs should provide:]
./doc/examples
(new features only)For reviewers
(Don't remove the checklist below.)
later.
__init__.py
.doc/release/release_dev.rst
.