如何在PIL和numpy之间转换模式为“1”的图片?

7

我是初学者,正在学习使用Python进行图像处理,并遇到了一个奇怪的问题。

例如,我有一个2*2的黑白位图像素如下:

黑 白

白 黑

使用PIL并将其转换为numpy格式:

>>> import Image
>>> import numpy
>>> im = Image.open('test.bmp')
>>> im
<BmpImagePlugin.BmpImageFile image mode=1 size=2x2 at 0x95A54EC>
>>> numpy.asarray(im)
array([[ True,  True],
       [False, False]], dtype=bool)
>>>

我困惑的是数组中像素的顺序。为什么不是[[True, False], [False, True]]?谢谢。
更新:位图在这里:http://njuer.us/clippit/test.bmp

你可以发布位图吗? - jterrace
http://njuer.us/clippit/test.bmp,由GIMP制作 - Clippit
1个回答

8

看起来使用1模式进行numpy转换存在一些错误。

如果您先将其转换为L,它就可以正常工作:

>>> im
<BmpImagePlugin.BmpImageFile image mode=1 size=2x2 at 0x17F17E8>
>>> im2 = im.convert('L')
>>> numpy.asarray(im2)
array([[  0, 255],
       [255,   0]], dtype=uint8)

此外,如果你尝试将一个布尔值 numpy 数组转换为 PIL 格式,你会得到奇怪的结果:
>>> testarr = numpy.array([[True,False],[True,False]], dtype=numpy.bool)
>>> testpil = Image.fromarray(testarr, mode='1')
>>> numpy.asarray(testpil)
array([[False, False],
       [False, False]], dtype=bool)

然而,使用 uint8 没有问题:
>>> testarr = numpy.array([[255,0],[0,255]], dtype=numpy.uint8)
>>> Image.fromarray(testarr)
<Image.Image image mode=L size=2x2 at 0x1B51320>
>>> numpy.asarray(Image.fromarray(testarr))
array([[255,   0],
       [  0, 255]], dtype=uint8)

因此,我建议将L用作中间数据类型,并在保存之前转换为1,如果您需要以该格式保存它。可以像这样实现:

>>> im
<BmpImagePlugin.BmpImageFile image mode=1 size=2x2 at 0x17F17E8>
>>> im2 = im.convert('L')
>>> arr = numpy.asarray(im2)
>>> arr
array([[  0, 255],
       [255,   0]], dtype=uint8)
>>> arr = arr == 255
>>> arr
array([[False,  True],
       [ True, False]], dtype=bool)

然后进行转换回来:
>>> backarr = numpy.zeros(arr.shape, dtype=numpy.uint8)
>>> backarr[arr] = 255
>>> backarr
array([[  0, 255],
       [255,   0]], dtype=uint8)
>>> Image.fromarray(backarr).convert('1')
<Image.Image image mode=1 size=2x2 at 0x1B41CB0>

Image.fromarray有一个参数modeImage.fromarray(testarr, mode='1')可以正常工作,但我不知道PIL是否正确处理了它。这真的是一个bug吗? - Clippit
@Clippit 感谢您指出这一点。尽管如此,它看起来仍然有问题-我更新了我的答案。 - jterrace

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