12

I have a binary image, dimensions 64x63 where every pixel is a 1 or 0.

import struct
from PIL import Image
import numpy

...

i1 = Image.frombytes('1', (64, 63), r[3], 'raw')

How can I invert this image?

Edit

I attempted the suggested solution:

from PIL import Image
import PIL.ImageOps    

i1 = PIL.ImageOps.invert(i1)

However, this resulted in the error:

raise IOError("not supported for this image mode")
IOError: not supported for this image mode

And this, I believe, is due to the fact that the image is neither RGB nor L(greyscale). Instead, it is a binary image file where each pixel is only either 0 or 1.

Richard Chambers
  • 16,643
  • 4
  • 81
  • 106
waylonion
  • 6,866
  • 8
  • 51
  • 92
  • Possible duplicate of [How to invert colors of image with PIL (Python-Imaging)?](http://stackoverflow.com/questions/2498875/how-to-invert-colors-of-image-with-pil-python-imaging) – 9000 Jan 02 '17 at 03:31
  • Thanks for the suggestion! However, I did try this although I received an error from PIL noting that binary images are not supported. – waylonion Jan 02 '17 at 05:10
  • The exact error that I receive is: raise IOError("not supported for this image mode") IOError: not supported for this image mode – waylonion Jan 02 '17 at 05:16

4 Answers4

7

Another option is to convert the image to a supported inversion format, before inverting it, ie:

import PIL.ImageOps
inverted_image = PIL.ImageOps.invert( image.convert('RGB') )
hamish
  • 397
  • 3
  • 3
4

If you're willing to convert i1 to a numpy array you can just do

i1 = 1 - numpy.asarray(i1)
bobo
  • 183
  • 3
  • 8
  • It appears that i1 is not a numpy array. I am using Image.frombytes to create i1. Using the code i1 = 1 - i1, I receive the error: TypeError: unsupported operand type(s) for -: 'int' and 'Image' – waylonion Jan 02 '17 at 05:13
  • 1
    @WayWay I have edited the code to take care of this. If you need to keep working with Pillow `Image` object you may use `Image.fromarray(i1)` after – bobo Jan 02 '17 at 06:04
1

I came across the exact same problem. There is a solution without going to the trouble of using numpy.
you can use ImageMath:

from PIL import ImageMath
i2 = ImageMath.eval('255-(a)',a=i1)

This way you can invert a binary (mode 1 in PIL) image.
For more an ImageMath refer to here.

Amen
  • 1,524
  • 5
  • 22
  • 41
1

The easiest solution is to do what ImageOps.invert itself does:

i1 = i1.point(lambda x: 255-x)

ImageOps.invert checks the mode and refuses to work if it's anything other than 'L' or 'RGB', but this method actually works with many other modes, with a few caveats:

  • If there's an alpha channel, it will invert it too.

  • If it's a palette image, it will invert the palette indexes, not the palette entries.

Here's a more complete implementation of invert that tries to do the right thing with all common modes:

def invert(im):
    if im.mode in {'P', 'PA'}:
        pmode, pal = im.palette.getdata()
        pal = Image.frombytes(pmode, (len(pal) // len(pmode), 1), pal)
        im = im.copy()
        im.palette.palette = invert(pal).tobytes()
        return im
    elif im.mode in {'LA', 'La', 'RGBA', 'RGBa', 'RGBX'}:
        return im.point([*range(255, -1, -1)] * (len(im.mode) - 1) + [*range(256)])
    else:
        # This may fail
        return im.point(lambda x: 255-x)
benrg
  • 1,395
  • 11
  • 13