# numpy uint8 pixel wrapping solution

4.9k Views

For an image processing class, I am doing point operations on monochrome images. Pixels are uint8 [0,255].

numpy uint8 will wrap. For example, 235+30 = 9. I need the pixels to saturate (max=255) or truncate (min=0) instead of wrapping.

My solution uses int32 pixels for the point math then converts to uint8 to save the image.

Is this the best way? Or is there a faster way?

``````#!/usr/bin/python

import sys
import numpy as np
import Image

def to_uint8( data ) :
# maximum pixel
latch = np.zeros_like( data )
latch[:] = 255
# minimum pixel
zeros = np.zeros_like( data )

# unrolled to illustrate steps
d = np.maximum( zeros, data )
d = np.minimum( latch, d )

# cast to uint8
return np.asarray( d, dtype="uint8" )

infilename=sys.argv
img = Image.open(infilename)
data32 = np.asarray( img, dtype="int32")
data32 += 30
data_u8 = to_uint8( data32 )
outimg = Image.fromarray( data_u8, "L" )
outimg.save( "out.png" )
``````

Input image: Output image:  • 1
• While working with the MNIST dataset my resulting `.png` images showed weird square artifacts instead of the actual handwritten number. The issue was also the dtype `int32`. After using the accepted answer with `numpy.clip` and the `astype()` conversion everything worked.

Use numpy.clip:

``````import numpy as np
np.clip(data32, 0, 255, out=data32)
data_u8 = data32.astype('uint8')
``````

Note that you can also brighten images without numpy this way:

``````import ImageEnhance
enhancer = ImageEnhance.Brightness(img)
outimg = enhancer.enhance(1.2)
outimg.save('out.png')
``````
• np.clip() is exactly what I've been needing. Thanks! I'll also read up on ImageEnhance. The homework was about doing point ops ourselves but will be good to learn other ways.

You can use OpenCV `add` or `subtract` functions (additional explanation here).

``````>>> import numpy as np
>>> import cv2
>>> arr = np.array([100, 250, 255], dtype=np.uint8)
>>> arr
Out: array([100, 250, 255], dtype=uint8)
>>> cv2.add(arr, 10, arr)  # Inplace
Out: array([110, 255, 255], dtype=uint8)  # Saturated!
>>> cv2.subtract(arr, 150, arr)
Out: array([  0, 105, 105], dtype=uint8)  # Truncated!
``````

Unfortunately it's impossible to use indexes for output array, so inplace calculations for each image channel may be performed in this, less efficient, way:

``````arr[..., channel] = cv2.add(arr[..., channel], 40)
``````

Basically, it comes down to checking before you add. For instance, you could define a function like this:

``````def clip_add(arr, amt):
if amt > 0:
cutoff = 255 - amt
arr[arr > cutoff] = 255
arr[arr <= cutoff] += amt
else:
cutoff = -amt
arr[arr < cutoff] = 0
arr[arr >= cutoff] += amt
``````