Skip to content Skip to sidebar Skip to footer

I Am Trying To Manipulate The Pixel Values Without Clipping Them

I have an image which has a max pixel value - 287.4976094062538 and min pixel value - -41.082841881780645 I am trying to bring them in range between 0-255 what I did:- I have divi

Solution 1:

You are normalizing the positive range of your image only, ignoring the negative values.

You want to apply the following equation to your values:

mx = np.amax(img)
mn = np.amin(img)
img = (img - mn) / (mx - mn) * 255

We're first subtracting the minimum value, so that the minimum value in the image becomes 0. Next we divide to set the maximum value to 1. mx-mn is the full range of your data, and therefore the maximum value in the data after setting the minimum to 0.

Solution 2:

Scikit-image has function for this:

https://scikit-image.org/docs/dev/api/skimage.exposure.html#skimage.exposure.rescale_intensity

It maybe better to rescale it to range (0,1), do all the processing in float format and convert to int8 before saving.

In [1]: from skimage.exposure import rescale_intensity
In [2]: from skimage import img_as_ubyte
In [3]: import numpy as np

In [4]: im = np.random.uniform(low=-100, high=400, size=(3,3))

In [5]: im
Out[5]: 
array([[351.2177509 , 313.89196632, 241.73850855],
       [-21.12284801,  97.84166107, -66.925235  ],
       [267.75593733, -15.78767759, 252.63980599]])

In [6]: im = rescale_intensity(im, in_range='image', out_range=(0,1))

In [7]: im
Out[7]: 
array([[1.        , 0.9107344 , 0.7381775 ],
       [0.10953762, 0.39404439, 0.        ],
       [0.80039887, 0.12229682, 0.76424824]])

In [8]: im = img_as_ubyte(im)  # 8bit

In [9]: im
Out[9]: 
array([[255, 232, 188],
       [ 28, 100,   0],
       [204,  31, 195]], dtype=uint8)

If this is black & white image with more than 256 shades of grey, I would recommend to use 16bit PNG format and rescale it to range (0, 65535).

If you have more similar images, you can use custom in_range, so that rescaling is consistent in all images, as Guang recommends.

import numpy as np
from skimage.exposure import rescale_intensity
from skimage import img_as_uint
from imageio import imwrite


im = np.linspace(-40,288,10000).reshape(100,100)
im = rescale_intensity(im, in_range=(-100,400), out_range=(0,1))
im = img_as_uint(im)  # 16bit
imwrite("image.png", im)

EDIT: If you do not want to use scikit-image, you can define similar function like this:

defrescale_intensity(arr, in_range=None, out_range=(0, 1)):
    """Normalize numpy array.
    Returns: float array
    """
    imin, imax = in_range if in_range isnotNoneelse (np.min(arr), np.max(arr))
    omin, omax = out_range
    if imin == imax:
        raise ValueError("Cannot rescale array, imin == imax")
    else:
        z = omin + omax * ((arr - imin) / (imax - imin))
    return np.clip(z, a_min=omin, a_max=omax)
    

Post a Comment for "I Am Trying To Manipulate The Pixel Values Without Clipping Them"