Wrong pixel value scaling in skimage.util (alternative for bytescaling in Scipy)

Question:

With the newest version of SciPy the bytescale() function is removed. So I tried an alternative with scikit-image. While bytescale()(scipy) converts an uint16 image (.tif) correctly scaled to an uint8 image, util.img_as_ubyte() (skimage) returns an image in which the highest grey value is 8 and the lowest is 0, instead of 255 and 0.

I need an uint8 image for further image processing (Otsu and Canny Edge detection) and everything is working perfectly with the bytescale from skimage, but as soon as I try the SciPy version, everything is getting messy.

The code snippet is as followed:

...
import numpy as np
from scipy.misc import bytescale
from skimage import io, util
def convertToByteImg(imagePath)
    image = io.imread(imagePath)
    img1 = util.img_as_ubyte(image)
    img2 = bytescale(image)
...
Asked By: PxG

||

Answers:

bytescale always expands the range of your input image to the maximum range of uint8 (0-255). This is sometimes what you want but sometimes not, because you lose information about the relative range of different images in your dataset. In this case, your input image must have range approximately in [0, 2048], while img_as_ubyte rescales the range [0, 65535] to [0, 255].

Assuming you want to expand your input image to the full range, you need skimage.exposure.rescale_intensity:

from skimage import io, util, exposure

# narrow range 16-bit
image = io.imread(image_path)
# full range 16-bit
image_rescaled = exposure.rescale_intensity(image)
# full range 8-bit
image_uint8 = util.img_as_ubyte(image_rescaled)
Answered By: Juan