调整PIL图像的强度比例

4
什么是PIL Image重新调整强度的最简单/最干净的方法?
假设我有一张来自12位相机的16位图像,因此仅使用值0-4095。 我希望重新调整强度,使整个范围0-65535都被使用。 当图像表示为PIL的Image类型时,最简单/最干净的方法是什么?
到目前为止,我想到的最好的解决方案是:
pixels = img.getdata()
img.putdata(pixels, 16)

这样做是可行的,但总是会使得最不重要的四位为空白。理想情况下,我希望将每个值向左移动四位,然后将四个最重要的位复制到四个最不重要的位。我不知道如何快速实现这一点。

5个回答

3

既然您知道像素值是0-4095,我找不到比这更快的方法:

new_image= image.point(lambda value: value<<4 | value>>8)

根据文档,lambda函数最多会被调用4096次,不管图像大小。

编辑:由于给定的点函数必须是形如argument * scale + offset的形式,对于I图像,则使用point函数是最好的选择:

new_image= image.point(lambda argument: argument*16)

最大的输出像素值将是65520。

第二个例子:

使用itertools来提高效率,对您自己的解决方案进行了修改:

import itertools as it # for brevity
import operator

def scale_12to16(image):
    new_image= image.copy()
    new_image.putdata(
        it.imap(operator.or_,
            it.imap(operator.lshift, image.getdata(), it.repeat(4)),
            it.imap(operator.rshift, image.getdata(), it.repeat(8))
        )
    )
    return new_image

这样可以避免point函数参数的限制。

这是一个非常好的想法,但因为16位图像是PIL类型"I",所以point的参数必须是形式为argument * scale + offset的函数。 - Vebjorn Ljosa
当然,你是正确的。希望“第二次尝试”对你来说足够高效。 - tzot

2
为什么要将最高有效位复制回最低有效位?每个像素只有12个有效位信息,无论你做什么都不会改善它。如果你只需要4K的亮度级别,这对于大多数应用来说是可以接受的,那么你的解决方案是正确的,可能是最优的。如果你需要更多的渐变级别,那么像David所说,重新使用直方图进行计算,但这会显著降低速度。
但是,将四个最高有效位复制到四个最低有效位并不是正确的方法 :)

2
我考虑复制4个MSB的原因是它将使用整个范围0-(2 ^ 16-1),因此原始图像中的饱和像素在重新缩放的图像中也会出现饱和。 - Vebjorn Ljosa
确实,这是将每个通道的位数提升到更高级别的标准方法。 - bobince

2

1

你需要做的是直方图均衡化。 如何使用python和pil完成:

编辑: 将每个值向左移动四位,然后将最高有效位复制到最低有效位...

def f(n):
   return  n<<4 + int(bin(n)[2:6],2)

print(f(0))
print(f(2**12))

# output
>>> 0
    65664 # Oops > 2^16

这两个链接完全相同。 - Nadia Alramli
不,直方图均衡化会以不同的方式拉伸直方图的不同部分。我想做的只是均匀地拉伸直方图,以使用整个强度范围。 - Vebjorn Ljosa

0
也许你应该传递16.0(一个浮点数)而不是16(一个整数)。我试图测试它,但由于某种原因putdata根本没有乘法...所以我希望它对你起作用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接