-1

I have a Python-Flask application where I upload an image onto a server and perform predictions on a selected uploaded image using a dense-net model following this tutorial, which results in the following error: PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0x7f4ceb257950>

Here is my prediction route:

@app.route('/predict', methods=['POST'])
@login_required
def predict():
    if request.method == 'POST':

        filename = ""
        if len(request.form) == 0:
            flash("Please select a file to perform a prediction on")
            return redirect(url_for('index'))
        else:

            filename = request.form['file']
            filepath = os.path.join(app.config['UPLOAD_PATH'], \
                                     current_user.username, filename)
            
            file = open(filepath, 'rb')
            img_bytes = file.read()
            class_id, class_name = models.get_prediction(image_bytes=img_bytes)
            print(class_id, class_name)


    return render_template('predict.html', filename=filename)

models.py:

import io
import json
import os

from torchvision import models
import torchvision.transforms as transforms
from PIL import Image

imagenet_class_index = json.load(open('imagenet_class_index.json'))
model = models.densenet121(pretrained=True)
model.eval()

def transform_image(image_bytes):
    my_transforms = transforms.Compose([transforms.Resize(255),
                                        transforms.CenterCrop(224),
                                        transforms.ToTensor(),
                                        transforms.Normalize(
                                            [0.485, 0.456, 0.406],
                                            [0.229, 0.224, 0.225])])
    
    image = Image.open(io.BytesIO(image_bytes))
    return my_transforms(image).unsqueeze(0)

def get_prediction(image_bytes):
    tensor = transform_image(image_bytes=image_bytes)
    outputs = model.forward(tensor)
    _, y_hat = outputs.max(1)
    predicted_idx = str(y_hat.item())
    return imagenet_class_index[predicted_idx]

stack trace:

[2023-03-03 13:49:32,564] ERROR in app: Exception on /predict [POST]
Traceback (most recent call last):
  File "/mnt/c/Users/sahan/Desktop/Senior Year/CS 81a/Sahana-cs81a/venv/lib/python3.8/site-packages/flask/app.py", line 2525, in wsgi_app
    response = self.full_dispatch_request()
  File "/mnt/c/Users/sahan/Desktop/Senior Year/CS 81a/Sahana-cs81a/venv/lib/python3.8/site-packages/flask/app.py", line 1822, in full_dispatch_request        
    rv = self.handle_user_exception(e)
  File "/mnt/c/Users/sahan/Desktop/Senior Year/CS 81a/Sahana-cs81a/venv/lib/python3.8/site-packages/flask/app.py", line 1820, in full_dispatch_request        
    rv = self.dispatch_request()
  File "/mnt/c/Users/sahan/Desktop/Senior Year/CS 81a/Sahana-cs81a/venv/lib/python3.8/site-packages/flask/app.py", line 1796, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/mnt/c/Users/sahan/Desktop/Senior Year/CS 81a/Sahana-cs81a/venv/lib/python3.8/site-packages/flask_login/utils.py", line 290, in decorated_view        
    return current_app.ensure_sync(func)(*args, **kwargs)
  File "/mnt/c/Users/sahan/Desktop/Senior Year/CS 81a/Sahana-cs81a/cloudsystem/app.py", line 311, in predict
    class_id, class_name = models.get_prediction(image_bytes=img_bytes)
  File "/mnt/c/Users/sahan/Desktop/Senior Year/CS 81a/Sahana-cs81a/cloudsystem/models.py", line 25, in get_prediction
    tensor = transform_image(image_bytes=image_bytes)
  File "/mnt/c/Users/sahan/Desktop/Senior Year/CS 81a/Sahana-cs81a/cloudsystem/models.py", line 21, in transform_image
    image = Image.open(io.BytesIO(image_bytes))
  File "/mnt/c/Users/sahan/Desktop/Senior Year/CS 81a/Sahana-cs81a/venv/lib/python3.8/site-packages/PIL/Image.py", line 3283, in open
    raise UnidentifiedImageError(msg)
PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0x7f4c48b2ea40>

I have tried this with no success as well as ensuring that only valid file types (i.e. .png, .jpg) can be uploaded. I've also tried passing in the path name instead of file bytes, which results in a FileNotFoundError. I've double checked to make sure that the path is correct and the file does indeed exist in my local directory. Using OpenCV instead results in the same error as above. For now, I just want the prediction results to be printed in the terminal. Thank you!

Edit (1): Here are the first 20 bytes of image_bytes getting passed into PIL: b'\xde\xcf\x13J5.p\xf5\xe5Qt9\xd7\xb5 \xda\x1d\xab4\xa0'

Edit (2): Since the bytes of the file don't correspond to any image format, I tried to pass in the image path into Image.open() instead:

if os.path.isfile(filepath):
        print(filepath + " is a valid file from app.py")
class_id, class_name = models.get_prediction(filepath)

The print statement is printing the path, so I assume that the path being passed into models.get_prediction() is valid.

The transform_image() function now looks like this:

def transform_image(path):
    my_transforms = transforms.Compose([transforms.Resize(255),
                                        transforms.CenterCrop(224),
                                        transforms.ToTensor(),
                                        transforms.Normalize(
                                            [0.485, 0.456, 0.406],
                                            [0.229, 0.224, 0.225])])
    
    if os.path.isfile(path):
        print(path + " is a valid file from models.py")    
    image = Image.open(path)
    return my_transforms(image).unsqueeze(0)

Once again, the path of the inputted file is printing, so the file must exist within the path. However, I'm still getting the following error from Image.open(path): PIL.UnidentifiedImageError: cannot identify image file 'uploads/test/Cat03.jpg.

sahana_s
  • 1
  • 2
  • Take another, closer look at https://flask.palletsprojects.com/en/2.2.x/patterns/fileuploads/ Depending on how you have UPLOAD_PATH configured, the file you're opening isn't what you expected. – Dave W. Smith Mar 04 '23 at 05:50
  • Try printing the first 20 bytes of `image_bytes` before passing it to PIL `print(image_bytes[:20])` – Mark Setchell Mar 04 '23 at 10:38
  • @MarkSetchell printing the first 20 bytes of image_bytes does print bytes, so a non-empty object is getting passed into PIL. Not sure where to go from here though. – sahana_s Mar 06 '23 at 01:31
  • The idea was to click [edit] amd share those first 20 bytes so we can check them. – Mark Setchell Mar 06 '23 at 07:32
  • Those bytes don't seem to correspond to any known image format. – Mark Setchell Mar 07 '23 at 19:08
  • I changed it from passing in bytes to passing in the file path, but still getting a PIL.UnidentifiedImageError. I tried other replacements for Image.open() such as matplotlib.imread and cv2.imread, but they all result in the same error. Do you have any idea as to why this is happening? – sahana_s Mar 14 '23 at 05:50
  • There's a command `file SOMEFILE` that looks at a file and works out what it is. So if you run `file SOMEIMAGE.JPG` it will tell you it's a JPEG. So try saving the file you are trying to open onto disk, then running `file` on it to see if it can work out what you are receiving. – Mark Setchell Mar 14 '23 at 07:46

1 Answers1

0

The issue was that a part of the image buffer was being read in a previously called function for image validation and as a result the image wasn't being stored correctly. Removing the line of code reading the image buffer fixed the problem.

sahana_s
  • 1
  • 2