Search code examples
python-3.xpython-imaging-libraryscikit-imagepgm

Error Opening PGM file with PIL and SKIMAGE


I have following Image file:

Image

I used PIL and Skimage to open it but I get following errors

First with PIL (tried with and without trucate option): Code:

from PIL import Image, ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True
img = Image.open("image_output.pgm")

Erorr:

OSError: cannot identify image file 'image_output.pgm'

And with Skimage:

Code:

from skimage import io
img = io.imread("image_output.pgm")

Error:

OSError: cannot identify image file <_io.BufferedReader name='image_output.pgm'>

I can open the file with GUI applications like system photo viewer and Matlab.

How can I diagnose what is wrong with image? I compared the byte data with other PGM files which I can open in Python, but could not identify the difference.

Thanks.


Solution

  • Your file is P2 type PGM, which means it is in ASCII - you can view it in a normal text editor. It seems neither PIL, nor skimage want to read that, but are happy to read the corresponding P5 type which is identical except it is written in binary, rather than ASCII.

    There are a few options...


    1) You could use OpenCV to read it:

    import cv2
    im = cv2.imread('a.pgm')
    

    2) You could convert it to P5 with ImageMagick and then read the output.pgm file with skimage or PIL:

    magick input.pgm output.pgm
    

    3) If adding OpenCV, or ImageMagick as a dependency is a real pain for you, it is possible to read a PGM image yourself:

    #!/usr/bin/env python3
    
    import re
    import numpy as np
    
    # Open image file, slurp the lot
    with open('input.pgm') as f:
       s = f.read()
    
    # Find anything that looks like numbers
    # Technically, there could be comments that should be ignored
    l=re.findall(r'[0-9P]+',s)
    
    # List "l" will contain: P5, width, height, 255, pixel1, pixel2, pixel3...
    # Technically, if l[3]>255, you should change the type of the Numpy array to uint16, but that is not the case
    w, h = int(l[1]), int(l[2])
    
    # Make Numpy image from data
    ni = np.array(l[4:],dtype=np.uint8).reshape((h,w))
    

    enter image description here