在Numpy中改变对比度

时间:2018-03-07 01:06:39

标签: python numpy

我想写一个纯Numpy函数来改变RGB图像的对比度(表示为Numpy uint8数组),但是,我写的函数不起作用,我不明白为什么。

以下是一个示例图片:

enter image description here

这是一个使用PIL并且工作正常的函数:

def change_contrast(img, factor):
    def contrast(pixel):
        return 128 + factor * (pixel - 128)
    return img.point(contrast)

from PIL import Image

img = Image.fromarray(img.astype(np.uint8))
img1 = change_contrast(img, factor=2.0)

输出:

enter image description here

现在这里是一个纯粹的Numpy函数,在我看来,它与上面的其他函数完全相同,但它根本不起作用:

def change_contrast2(img, factor):
    return 128 + factor * (img - 128)

img1 = change_contrast2(img, factor=2.0)

其中img是Numpy数组。输出是这样的:

enter image description here

我不明白发生了什么,并且会对任何提示感到高兴!

2 个答案:

答案 0 :(得分:4)

你看到的是无符号整数的下溢:

>>> a = np.array((64, 128, 192), dtype=np.uint8)
>>> a
array([ 64, 128, 192], dtype=uint8)
>>> a-128
array([192,   0,  64], dtype=uint8) # note the "wrong" value at pos 0

避免这种情况的一种方法是强制或类型促销:

factor = float(factor)
np.clip(128 + factor * img - factor * 128, 0, 255).astype(np.uint8)

因为因子是浮点数,产品factor * img的dtype会被提升为浮点数。由于浮点数可以处理负数,因此可以消除下溢。

为了能够转换回uint8,我们剪辑到此类型可以表示的范围。

答案 1 :(得分:1)

试试这个,创建类型为int32的numpy数组并进行对比操作。然后在绘制图像之前使用以下函数将其转换为uint8。正如保罗在评论中提到的那样,问题在于numpy正在包含过度/下溢。

def as_uint8(img) :
    latch = np.zeros_like(img)
    latch[:] = 255
    zeros = np.zeros_like(img)

    d = np.maximum(zeros, img)
    d = np.minimum(latch, d)

    return np.asarray(d, dtype='uint8')

这可能是一种更有效的方法,但它确实有效。