numpy uint8 像素环绕解决方案

38 投票
3 回答
58358 浏览
提问于 2025-04-17 03:03

我正在做一个图像处理的课程,主要是对单色图像进行点操作。图像中的每个像素值是uint8类型,范围是0到255。

在使用numpy时,uint8类型的像素值会出现循环现象。比如235加上30,结果会变成9。我希望像素值能饱和(最大值为255)或者截断(最小值为0),而不是循环。

我的解决办法是先用int32类型来进行计算,然后再转换成uint8类型来保存图像。

这样做是最好的方法吗?还是有更快的办法呢?

#!/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[1]
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" )

输入图像:
Riemann

输出图像:
Output

3 个回答

1

基本上,这就是在添加之前先进行检查。例如,你可以这样定义一个函数:

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
7

你可以使用 OpenCV 的 add 或者 subtract 函数来进行加法或减法运算(更多解释可以在 这里 找到)。

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

不过,输出数组不能使用索引,所以对于每个图像通道的计算只能用这种效率较低的方法来进行:

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

使用 numpy.clip 方法:

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

另外,你也可以不使用numpy来调亮图片,方法如下:

import ImageEnhance
enhancer = ImageEnhance.Brightness(img)
outimg = enhancer.enhance(1.2)
outimg.save('out.png')

撰写回答