Scikit-image: `exposure.equalize_adapthist` can fail for constant inputs due to incorrect behavior in `rescale_intensity`

Created on 20 Apr 2020  路  3Comments  路  Source: scikit-image/scikit-image

Description

exposure.rescale_intensity does not rescale the image to the range defined in out_range when min and max are equal.

This leads to equalize_adapthist to fail for many cases of constant inputs.

(In principle one wouldn't apply equalize_adapthist in the case of constant inputs, but probably it shouldn't fail, e.g. when processing a constant chunk of a large dask array).

Way to reproduce

from skimage import exposure
import numpy as np

ar = np.array([300,300])
ar_rescaled = exposure.rescale_intensity(ar, out_range=(0,255))
print(ar_rescaled)

[76500 76500]

This should be within (0,255).

Here's how to make exposure.equalize_adapthist fail:

img = np.zeros((8, 8)) + 0.1
img = img.astype(np.float64)
adapted = exposure.equalize_adapthist(img, 3) # yields exception

IndexError: index 26214 is out of bounds for axis 0 with size 16384

Version information

# Paste the output of the following python commands
from __future__ import print_function
import sys; print(sys.version)
import platform; print(platform.platform())
import skimage; print("scikit-image version: {}".format(skimage.__version__))
import numpy; print("numpy version: {}".format(numpy.__version__))
3.8.2 | packaged by conda-forge | (default, Mar 23 2020, 17:55:48)
[Clang 9.0.1 ]
macOS-10.14.6-x86_64-i386-64bit
scikit-image version: 0.17.dev0
numpy version: 1.18.2
bug

Most helpful comment

How to fix this? Probably rescaling is not well defined for constant input. The most sensible might be to clip the input image to out_range?

Meaning something like this:

    image = np.clip(image, imin, imax) 

    if imin != imax:
        image = (image - imin) / float(imax - imin)
        return np.asarray(image * (omax - omin) + omin, dtype=dtype)
    else:
        return np.clip(image, omin, omax).astype(dtype)

This would be in agreement with the following already existing test:
https://github.com/scikit-image/scikit-image/blob/37ca7deb15c1dd4d89b7c7e777a32909122009b5/skimage/exposure/tests/test_exposure.py#L277-L281

All 3 comments

How to fix this? Probably rescaling is not well defined for constant input. The most sensible might be to clip the input image to out_range?

Meaning something like this:

    image = np.clip(image, imin, imax) 

    if imin != imax:
        image = (image - imin) / float(imax - imin)
        return np.asarray(image * (omax - omin) + omin, dtype=dtype)
    else:
        return np.clip(image, omin, omax).astype(dtype)

This would be in agreement with the following already existing test:
https://github.com/scikit-image/scikit-image/blob/37ca7deb15c1dd4d89b7c7e777a32909122009b5/skimage/exposure/tests/test_exposure.py#L277-L281

@m-albert Yes, I think clipping is the correct approach, good thinking.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sciunto picture sciunto  路  3Comments

msis picture msis  路  4Comments

tirthajyoti picture tirthajyoti  路  3Comments

emmanuelle picture emmanuelle  路  4Comments

John1231983 picture John1231983  路  4Comments