Clipping pixel values

Hello everyone!

I have a grey scale image that I want to brighten. I do so by incrementing the pixel values by 50.
The problem is, if the value is higher than 255 it gets reset to 0 and then is incremented. Is there a way to clip the maximum value somehow ? As in, if it gets to 255 then it stays at 255.

So far I came up with this solution but it is rather laborious (line 8):

from skimage import data, io, exposure
import matplotlib.pyplot as plt
import numpy as np

im = data.camera()
hist, hist_centers = exposure.histogram(im)

im_new = im + np.minimum(np.ones_like(im) * 255 - im, np.ones_like(im) * 50)
hist_new, hist_centers_new = exposure.histogram(im_new)

fig, axs = plt.subplots(2, 2)

axs[0, 0].imshow(im, cmap=plt.cm.gray)
axs[0, 0].set_title('Original Image')

axs[0, 1].plot(hist_centers, hist)
axs[0, 1].set_title('Original Histogram')

axs[1, 0].imshow(im_new, cmap=plt.cm.gray)
axs[1, 0].set_title('New Image')

axs[1, 1].plot(hist_centers_new, hist_new, 'tab:red')
axs[1, 1].set_title('New Histogram')

plt.show()

Thanks in advance

if you are starting with a uint8 type and you don’t want to deal with type conversions, then you could clip the values prior to addition, for instance:

im = data.camera()
to_add = 50
im[im > (255 - to_add)] = 255 - to_add
im += to_add

alternatively, you could convert to float, then clip the values after addition and return to uint8

im = data.camera().astype('float')
to_add = 50
im += to_add
im[im > 255] = 255
im = im.astype('uint8')

as a sidenote, if you just want to display the image brighter, you don’t need to change the array values directly, you can also just use the vmin, vmax arguments to imshow()

There is also the handy np.clip().
But as pointed out by talley already you would have to change the dtype to prevent wrap-around in uint8. You can then revert back to uint8 after clipping.

1 Like

You can also get NumPy to upcast to a more useful integer dtype:

In [10]: x = np.array([0, 128, 255], dtype=np.uint8) + np.array([8])                                                                                                                 

In [11]: x                                                                                                                                                                           
Out[11]: array([  8, 136, 263])

In [12]: x.dtype                                                                                                                                                                     
Out[12]: dtype('int64')

In [14]: np.clip(x, 0, 255).astype(np.uint8)                                                                                                                                         
Out[14]: array([  8, 136, 255], dtype=uint8)

If you are concerned about memory consumption, you can have one fewer copy:

In [15]: x = np.array([0, 128, 255], dtype=np.uint8)                                                                                                                                 

In [17]: np.clip(x + np.array([8]), 0, 255, out=x)                                                                                                                                   
Out[17]: array([  8, 136, 255], dtype=uint8)

In [18]: x                                                                                                                                                                           
Out[18]: array([  8, 136, 255], dtype=uint8)

1 Like