Reputation: 906
I'm new to image processing with Python and met a strange problem.
For example I have a 2*2 black-white bitmap image which pixels are following:
black white
white black
Use PIL and convert it to 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)
>>>
What puzzles me is the order of pixel in the array. Why not [[True, False], [False, True]]
? Thanks.
UPDATE: the bitmap is here: http://njuer.us/clippit/test.bmp
Upvotes: 7
Views: 7626
Reputation: 67073
It looks like there are some bugs with converting to/from numpy with the 1
mode.
If you convert it to L
first, it works fine:
>>> im
<BmpImagePlugin.BmpImageFile image mode=1 size=2x2 at 0x17F17E8>
>>> im2 = im.convert('L')
>>> numpy.asarray(im2)
array([[ 0, 255],
[255, 0]], dtype=uint8)
Also, if you try and convert a bool
numpy array to PIL, you get strange results:
>>> 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)
However, the exact same thing with uint8
works fine:
>>> 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)
So I would suggest using L
as an intermediate datatype and then converting to 1
before saving if you need to save it in that format. Something like this:
>>> 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)
Then to convert back:
>>> 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>
Upvotes: 8