0

I have successfully created a webpage that takes an image file and passes it to the API I built. The only problem is that once I feed that image to preprocessing.image.load_img from tensorflow, I get this error:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

Here is the API:

from starlette.responses import RedirectResponse
from fastapi import FastAPI, File, UploadFile
from tensorflow.keras import preprocessing
from fastapi.staticfiles import StaticFiles
from keras.models import load_model
import numpy as np
import uvicorn

app = FastAPI()
app.mount("/Templates", StaticFiles(directory="Templates"), name="Templates")

model_dir = 'F:\\Saved-Models\\Dog-Cat-Models\\First_Generation_dog_cat_optuna.h5'
model = load_model(model_dir)


@app.get('/')
async def index():
    return RedirectResponse(url="/Templates/index.html")


@app.post('/prediction_page')
async def prediction_form(dogcat_img: UploadFile = File(...)):
    dogcat_img_bytes = dogcat_img.file.read()

    pp_dogcat_image = preprocessing.image.load_img(dogcat_img_bytes, target_size=(150, 150))
    pp_dogcat_image_arr = preprocessing.image.img_to_array(pp_dogcat_image)
    input_arr = np.array([pp_dogcat_image_arr])
    prediction = np.argmax(model.predict(input_arr), axis=-1)

    print(prediction)


if __name__ == '__main__':
    uvicorn.run(app, host='localhost', port=8000)
Luleo_Primoc
  • 75
  • 1
  • 12

1 Answers1

1

With no full traceback from the exception it may be difficult to help but looking at the docs, tf.keras.utils.load_img requires a path to the image file (not the raw image data).

You can try something like this instead (the underlying library does something similar):

--- orig.py 2021-09-20 10:47:22.465636386 +0100
+++ new.py  2021-09-20 10:48:50.760734720 +0100
@@ -6,6 +6,8 @@
 import numpy as np
 import uvicorn
 
+from PIL import Image
+
 app = FastAPI()
 app.mount("/Templates", StaticFiles(directory="Templates"), name="Templates")
 
@@ -20,9 +22,10 @@
 
 @app.post('/prediction_page')
 async def prediction_form(dogcat_img: UploadFile = File(...)):
-    dogcat_img_bytes = dogcat_img.file.read()
+    # dogcat_img_bytes = dogcat_img.file.read()
 
-    pp_dogcat_image = preprocessing.image.load_img(dogcat_img_bytes, target_size=(150, 150))
+    # pp_dogcat_image = preprocessing.image.load_img(dogcat_img_bytes, target_size=(150, 150))
+    pp_dogcat_image = Image.open(dogcat_img.file).resize((150, 150), Image.NEAREST).convert("RGB") 
     pp_dogcat_image_arr = preprocessing.image.img_to_array(pp_dogcat_image)
     input_arr = np.array([pp_dogcat_image_arr])
     prediction = np.argmax(model.predict(input_arr), axis=-1)

Btw you may want to also consider using BackgroundTasks for the image processing, otherwise a single long running (async) request will block other requests.

HTF
  • 6,632
  • 6
  • 30
  • 49
  • Wow that worked, thanks! I got used to using the tensorflow processing method that I was too narrow-minded to try the PIL version. I will look into the background tasks as well. – Luleo_Primoc Sep 20 '21 at 21:44