microsoft / AIforEarth-API-Development

This is an API Framework for AI models to be hosted locally or on the AI for Earth API Platform (https://github.com/microsoft/AIforEarth-API-Platform).
MIT License
75 stars 44 forks source link

PIL/Pillow does not support tiff format, can't use api with multichannel tiff images #57

Closed rbavery closed 5 years ago

rbavery commented 5 years ago

See https://github.com/python-pillow/Pillow/issues/3984 and https://github.com/python-pillow/Pillow/issues/1888

It doesn't look like the pillow issues linked above will be fixed anytime soon, which means the api examples that use pillow/PIL can't accept tiff format. All the models I've trained so far have been trained on int16 tiff RGB files from Landsat (most geospatial raster data comes in tiff format). So I adapted the api to try and read in the submission with a different library, rasterio

https://github.com/ecohydro/CropMask_RCNN/blob/master/app/keras_iNat_api/keras_detector.py#L17-L37

But I can't seem to open a byte array with anything except for PIL/pillow. I've tried running the above function and get the following error when submitting a tiff to the docker server

{
    "TaskId": 3130,
    "Status": "failed: <class 'AttributeError'>\nTraceback (most recent call last):\n  File \"/app/keras_iNat_api/runserver.py\", line 60, in detect\n    arr_for_detection, image_for_drawing = keras_detector.open_image(image_bytes)\n  File \"./keras_detector.py\", line 34, in open_image\n    arr = reshape_as_image(img.read())\nAttributeError: '_GeneratorContextManager' object has no attribute 'read'\n",
    "Timestamp": "2019-07-22 17:33:14",
    "Endpoint": "uri"
}

Any tips on how to read a multichannel tiff byte array? I'd like my api to accept this format since most geospatial imagery users would prefer to use an api that accept the format that Landsat imagery comes in (tiff).

yangsiyu007 commented 5 years ago

Hi @rbavery - I've used tifffile to open TIFFs before, such as:

import tifffile
import numpy as np

image = np.transpose(tifffile.imread('path_to/image.tiff')) 

Try that?

rbavery commented 5 years ago

Thanks for the suggestion @yangsiyu007, hadn't heard of tifffile before and it looks like pillow uses a different tif backend, libtiff. I opted to go with rasterio since tifffile is limited to RGB:

    with MemoryFile(image_bytes) as memfile:
        with memfile.open() as src:
            arr = reshape_as_image(src.read())

MemFile and reshape_as_image come from rasterio

With that the app works and I can submit detections to it, hooray! It looks like something is going awry in the PIL drawing step, but I can debug that or submit a separate issue.

cgohlke commented 5 years ago

tifffile is limited to RGB

That is certainly not the case, but rasterio+GDAL is arguably the better choice for handling geospatial images.

rbavery commented 5 years ago

Ah, I was definitely not speaking from personal experience, just saw this stack overflow post where the top comment stated

It has limited functionality, especially when it comes to writing back to disk non RGB images, but Christoph Gohlke's tifffile module reads in 3 channel 16-bit TIFFs with no problems

https://stackoverflow.com/questions/18446804/python-read-and-write-tiff-16-bit-three-channel-colour-images