Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Use of PIL.Image
#1
The following code generates an error which I am not understanding:

from fastapi import FastAPI, File, UploadFile
import uvicorn
import numpy as np
from io import BytesIO
from PIL import Image
import tensorflow as tf

app = FastAPI()

MODEL = tf.keras.models.load_model('./code/Model-v1.keras')
Image_size = (256, 256)

def read_file_as_image(data) -> np.ndarray:
    image = Image.open(BytesIO(data))
    image = np.array(image)

    return image


@app.post("/predict")
async def predict(
                file: UploadFile = File(...)
    ):
    image = read_file_as_image(await file.read())

    # resize the image
    image.resize(Image_size)

    # expand the image dimensions by 1 to simulate a batch of images
    expanded_image = np.expand_dims(image, axis=0)

    # Now call predict with this image
    prediction = MODEL.predict(expanded_image)

    return
Error:
Expected type 'ndarray | Iterable | int | float', got 'Image' instead
The error is referring to line 15.

I am not sure what this error is occurring, since np.array() mehtod can convert PIL.Image.open(BytesIO(data))

I would be grateful for your help.
Reply
#2
Please post entire error message and trace.

The message is pretty clear. You cannot use an Image object to initialize a numpy array. np.array() expects an array-like object. Image is not an array-like object. Does Image have any attributes that are array-like?
Reply
#3
@deanhystad

I am reposting both the code and the actual error to make sure the error line numbers match up with the code.

This code expects an image posted from an http/post method. I am trying to convert that byte array into an Image object, but it appears I am not following proper conversion steps.

Th error message I presented in the post before, is displayed on my IDE when I hover over line 22 and the "image" is highlighted in the IDE. See the attached image.

from fastapi import FastAPI, File, UploadFile
import uvicorn
import numpy as np
from io import BytesIO
from PIL import Image
import tensorflow as tf

app = FastAPI()

MODEL = tf.keras.models.load_model('./code/Model-v1.keras')
Class_Names = ["Early Blight", "Late Blight", "Healthy"]
Image_size = (256, 256)


@app.get("/ping")
async def ping():
    return 'Hello, I am still running'


def read_file_as_image(data) -> np.ndarray:
    image = Image.open(BytesIO(data))
    image = np.array(image)

    return image


@app.post("/predict")
async def predict(
        file: UploadFile = File(...)
):
    image = read_file_as_image(await file.read())

    # resize the image
    image.resize(Image_size)

    # expand the image dimensions by 1 to simulate a batch of images
    expanded_image = np.expand_dims(image, axis=0)

    # Now call predict with this image
    prediction = MODEL.predict(expanded_image)

    return


if __name__ == "__main__":
    uvicorn.run(app, host='localhost', port=8000)
Error:
Traceback (most recent call last): File "<frozen importlib._bootstrap>", line 1176, in _find_and_load File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 690, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 940, in exec_module File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed File "C:\Potato_Leaf\Lib\site-packages\fastapi\__init__.py", line 7, in <module> from .applications import FastAPI as FastAPI File "C:\Potato_Leaf\Lib\site-packages\fastapi\applications.py", line 16, in <module> from fastapi import routing File "C:\Potato_Leaf\Lib\site-packages\fastapi\routing.py", line 22, in <module> from fastapi import params File "C:\Potato_Leaf\Lib\site-packages\fastapi\params.py", line 5, in <module> from fastapi.openapi.models import Example File "C:\Potato_Leaf\Lib\site-packages\fastapi\openapi\models.py", line 4, in <module> from fastapi._compat import ( File "C:\Potato_Leaf\Lib\site-packages\fastapi\_compat.py", line 20, in <module> from fastapi.exceptions import RequestErrorModel File "C:\Potato_Leaf\Lib\site-packages\fastapi\exceptions.py", line 3, in <module> from pydantic import BaseModel, create_model File "C:\Potato_Leaf\Lib\site-packages\pydantic\__init__.py", line 13, in <module> from . import dataclasses File "C:\Potato_Leaf\Lib\site-packages\pydantic\dataclasses.py", line 11, in <module> from ._internal import _config, _decorators, _typing_extra File "C:\Potato_Leaf\Lib\site-packages\pydantic\_internal\_decorators.py", line 15, in <module> from ..fields import ComputedFieldInfo File "C:\Potato_Leaf\Lib\site-packages\pydantic\fields.py", line 18, in <module> from . import types File "C:\Potato_Leaf\Lib\site-packages\pydantic\types.py", line 34, in <module> from ._internal import ( File "C:\Potato_Leaf\Lib\site-packages\pydantic\_internal\_fields.py", line 13, in <module> from . import _typing_extra File "C:\Potato_Leaf\Lib\site-packages\pydantic\_internal\_typing_extra.py", line 13, in <module> from typing_extensions import Annotated, Final, Literal, TypeAliasType, TypeGuard, get_args, get_origin ImportError: cannot import name 'TypeAliasType' from 'typing_extensions' (C:\Potato_Leaf\Lib\site-packages\typing_extensions.py) python-BaseException Process finished with exit code -1073741510 (0xC000013A: interrupted by Ctrl+C)

Attached Files

Thumbnail(s)
   
Reply
#4
(Sep-05-2023, 07:55 PM)nafshar Wrote: @deanhystad

I am reposting both the code and the actual error to make sure the error line numbers match up with the code.

This code expects an image posted from an http/post method. I am trying to convert that byte array into an Image object, but it appears I am not following proper conversion steps.

Th error message I presented in the post before, is displayed on my IDE when I hover over line 22 and the "image" is highlighted in the IDE. See the attached image.

BTW - The process I used here seems the same as the one posted on GitHub, claiming to be working. See:

https://github.com/tiangolo/fastapi/issu...my%20code.

from fastapi import FastAPI, File, UploadFile
import uvicorn
import numpy as np
from io import BytesIO
from PIL import Image
import tensorflow as tf

app = FastAPI()

MODEL = tf.keras.models.load_model('./code/Model-v1.keras')
Class_Names = ["Early Blight", "Late Blight", "Healthy"]
Image_size = (256, 256)


@app.get("/ping")
async def ping():
    return 'Hello, I am still running'


def read_file_as_image(data) -> np.ndarray:
    image = Image.open(BytesIO(data))
    image = np.array(image)

    return image


@app.post("/predict")
async def predict(
        file: UploadFile = File(...)
):
    image = read_file_as_image(await file.read())

    # resize the image
    image.resize(Image_size)

    # expand the image dimensions by 1 to simulate a batch of images
    expanded_image = np.expand_dims(image, axis=0)

    # Now call predict with this image
    prediction = MODEL.predict(expanded_image)

    return


if __name__ == "__main__":
    uvicorn.run(app, host='localhost', port=8000)
Error:
Traceback (most recent call last): File "<frozen importlib._bootstrap>", line 1176, in _find_and_load File "<frozen importlib._bootstrap>", line 1147, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 690, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 940, in exec_module File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed File "C:\Potato_Leaf\Lib\site-packages\fastapi\__init__.py", line 7, in <module> from .applications import FastAPI as FastAPI File "C:\Potato_Leaf\Lib\site-packages\fastapi\applications.py", line 16, in <module> from fastapi import routing File "C:\Potato_Leaf\Lib\site-packages\fastapi\routing.py", line 22, in <module> from fastapi import params File "C:\Potato_Leaf\Lib\site-packages\fastapi\params.py", line 5, in <module> from fastapi.openapi.models import Example File "C:\Potato_Leaf\Lib\site-packages\fastapi\openapi\models.py", line 4, in <module> from fastapi._compat import ( File "C:\Potato_Leaf\Lib\site-packages\fastapi\_compat.py", line 20, in <module> from fastapi.exceptions import RequestErrorModel File "C:\Potato_Leaf\Lib\site-packages\fastapi\exceptions.py", line 3, in <module> from pydantic import BaseModel, create_model File "C:\Potato_Leaf\Lib\site-packages\pydantic\__init__.py", line 13, in <module> from . import dataclasses File "C:\Potato_Leaf\Lib\site-packages\pydantic\dataclasses.py", line 11, in <module> from ._internal import _config, _decorators, _typing_extra File "C:\Potato_Leaf\Lib\site-packages\pydantic\_internal\_decorators.py", line 15, in <module> from ..fields import ComputedFieldInfo File "C:\Potato_Leaf\Lib\site-packages\pydantic\fields.py", line 18, in <module> from . import types File "C:\Potato_Leaf\Lib\site-packages\pydantic\types.py", line 34, in <module> from ._internal import ( File "C:\Potato_Leaf\Lib\site-packages\pydantic\_internal\_fields.py", line 13, in <module> from . import _typing_extra File "C:\Potato_Leaf\Lib\site-packages\pydantic\_internal\_typing_extra.py", line 13, in <module> from typing_extensions import Annotated, Final, Literal, TypeAliasType, TypeGuard, get_args, get_origin ImportError: cannot import name 'TypeAliasType' from 'typing_extensions' (C:\Potato_Leaf\Lib\site-packages\typing_extensions.py) python-BaseException Process finished with exit code -1073741510 (0xC000013A: interrupted by Ctrl+C)

Attached Files

Thumbnail(s)
   
Reply
#5
Looking deeper int this problem, you should not get that message. Image is iterable. This code runs fine:
from PIL import Image
import numpy as np
from io import BytesIO

Image_size = (16, 16)


def read_file_as_image(data) -> np.ndarray:
    image = Image.open(BytesIO(data))
    return np.array(image)


with open("games/dice1.png", "rb") as file:
    image = read_file_as_image(file.read())
    print(image.shape)
    image.resize(Image_size)
    print(image.shape)
    expanded_image = np.expand_dims(image, axis=0)
    print(expanded_image.shape)
Output:
(16, 16, 3) (16, 16) (1, 16, 16)
read_file_as_image returns a 2D array of pixels, just as I expect. Resizing the image produces an unexpected result. The new image is a 2D array of bytes. What do these bytes mean. If the think of the original image as a 2D list of pixels where each pixel is an array of [R, G, B] values, the original array looked like this:
Output:
[[[R, G, B], ...14 more pixels... [R. G, B]], ... 14 more rows ... [[R, G, B], ...14 more pixels... [R. G, B]]
The new resized array looks like this:
Output:
[[R, G, B, R, G, B, R, G, B, R, G, B, R, G, B, R], [G, B, R, G, B., R, G, B, R, G, B, R, G, B, R, G], [B ... you get the idea.
Resizing the array did not resize the image. It reshaped the image. From the numpy documentation.
Quote:numpy.resize
numpy.resize(a, new_shape)[source]
Return a new array with the specified shape.

If the new array is larger than the original array, then the new array is filled with repeated copies of a. Note that this behavior is different from a.resize(new_shape) which fills with zeros instead of repeated copies of a.
Compare this to the documentation for Image.resize.
Quote:Image.resize(size, resample=None, box=None, reducing_gap=None)[source]
Returns a resized copy of this image.

PARAMETERS:
size – The requested size in pixels, as a 2-tuple: (width, height).
numpy.array.resize() just changes the shape of the array, If the new size is smaller than the old, extra values are thown away. If the new size is larger, the array is padded. If we are thinking of this as an image, there is no meaningful relationship between the original and the resized image.

When you resize a PIL.Image, it is like using a zoom lense on a camera. The image changes size, but the new resized image looks roughly the same.

So I don't think the message that pops up when you hover over the code has anything to do with your problem. I think you have an image processing problem. I think you need to keep your image as a PIL.Image until after it is resized. After that you can convert to a numpy array and pass to your function.
Reply
#6
@deanhystad - Thank you so much for looking into this issue. I think you are correct that my issue is not with line 22. I think if I can find out why I am getting the following error, I may be able to get around this problem. UP to now though it has been very difficult to find the cause.

I have down graded python from 11 to 10, and have tried pip installing typing_extensions manually, still no luck.

Error:
ImportError: cannot import name 'TypeAliasType' from 'typing_extensions'
Reply
#7
I am using Python 3.11 with pydantic 1.10.2 and typing_extensions 4.4.0. No problems. Updated to pydantic 2.3.0 with typing_extensions 4.7.1. No problems there either. What versions are you using?
Reply
#8
Quote: I am using Python 3.10.11, Pydantic 1.10.7 and typing_extensions 4.5.0
Reply
#9
@deanhystad

After a lot of trials and errors, I arrived at the following solution:

The np.array(image) has no issues as you suggested. The error that appears when I hover over this line, still persists, but has no impact on the running the code.

you had mentioned
Quote:I think you need to keep your image as a PIL.Image until after it is resized. After that you can convert to a numpy array and pass to your function.
and that was perfectly correct and resolved this issue.

Another very weird problem was the error message related to the TypeAliasType module in the typing_extensions package. This issues persisted no matter what python package or typing_extensions package was installted. Finally I found a reference in GitHub that suggested importing the specific module, regardless of whether it showes up on the IDE context, which it did not!!

I added from typing_extensions import TypeAliasType and while the IDE did complain, it ran the code with no errors!

A very similay issue happes when I use from tensorflow.keras import models, layers. In this line the IDE claims the module tensorflow.keras does not exist, yet the code runs fine.

I am using :

Quote:PyCharm 2021.2 (Community Edition)
Build #PC-212.4746.96, built on July 27, 2021
Runtime version: 11.0.11+9-b1504.13 amd64
VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o.
Windows 10 10.0
GC: G1 Young Generation, G1 Old Generation
Memory: 1464M
Cores: 4

I am not sure if my version of PyCharm is the problem, but I intend to upgrade it, if one is available.

Thanks agian for all your collaboration and assistance.
Reply
#10
How are you instslling packages? I do not use PyCharm, but I remember reading it prefers you use the pycharm package manager instead of pip
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020