0

I have code to run yolo in fastapi :

from fastapi import FastAPI, UploadFile, File
from ultralytics import YOLO
from PIL import Image
import io

app = FastAPI()
model = YOLO('yolov8n.yaml')
model = YOLO('runs/detect/train/weights/best.pt')


@app.post("/detect")
async def detect(file: UploadFile = File(...)):
    contents = await file.read()
    img = Image.open(io.BytesIO(contents))
    results = model.predict(source=img, save=True)

    return {
            "result": str(results)
        }

Show error :

[WARNING] Application callable raised an exception
[ERROR] Exception in callback <built-in method _loop_step of builtins.CallbackTaskHTTP object at 0x163b3bd30>
handle: <Handle CallbackTaskHTTP._loop_step>
Traceback (most recent call last):
  File "uvloop/cbhandles.pyx", line 61, in uvloop.loop.Handle._run
  File "/lib/python3.10/site-packages/fastapi/applications.py", line 270, in __call__
    await super().__call__(scope, receive, send)
  File "/lib/python3.10/site-packages/starlette/applications.py", line 124, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/lib/python3.10/site-packages/starlette/middleware/errors.py", line 184, in __call__
    raise exc
  File "/lib/python3.10/site-packages/starlette/middleware/errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 79, in __call__
    raise exc
  File "/lib/python3.10/site-packages/starlette/middleware/exceptions.py", line 68, in __call__
    await self.app(scope, receive, sender)
  File "/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 21, in __call__
    raise e
  File "/lib/python3.10/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "/lib/python3.10/site-packages/starlette/routing.py", line 706, in __call__
    await route.handle(scope, receive, send)
  File "/lib/python3.10/site-packages/starlette/routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "/lib/python3.10/site-packages/starlette/routing.py", line 66, in app
    response = await func(request)
  File "/lib/python3.10/site-packages/fastapi/routing.py", line 235, in app
    raw_response = await run_endpoint_function(
  File "/lib/python3.10/site-packages/fastapi/routing.py", line 161, in run_endpoint_function
    return await dependant.call(**values)
  File "detections/main.py", line 20, in detect
    results = model.predict(source=img, save=True, project="foto_ayam")
  File "/lib/python3.10/site-packages/torch/utils/_contextlib.py", line 115, in decorate_context
    return func(*args, **kwargs)
  File "/lib/python3.10/site-packages/ultralytics/engine/model.py", line 254, in predict
    return self.predictor.predict_cli(source=source) if is_cli else self.predictor(source=source, stream=stream)
  File "/lib/python3.10/site-packages/ultralytics/engine/predictor.py", line 195, in __call__
    return list(self.stream_inference(source, model, *args, **kwargs))  # merge list of Result into one
  File "/lib/python3.10/site-packages/torch/utils/_contextlib.py", line 35, in generator_context
    response = gen.send(None)
  File "/lib/python3.10/site-packages/ultralytics/engine/predictor.py", line 276, in stream_inference
    self.save_preds(vid_cap, i, str(self.save_dir / p.name))
  File "/lib/python3.10/site-packages/ultralytics/engine/predictor.py", line 330, in save_preds
    cv2.imwrite(save_path, im0)
cv2.error: OpenCV(4.6.0) /Users/xperience/actions-runner/_work/opencv-python/opencv-python/opencv/modules/imgcodecs/src/loadsave.cpp:730: error: (-2:Unspecified error) could not find a writer for the specified extension in function 'imwrite_'

But if parameter save=False everything work well :

 results = model.predict(source=img, save=False)

I am also has try running detection YOLOv8 without FASTAPI all work well. How to solve this bug ? Thanks

Pamungkas Jayuda
  • 1,194
  • 2
  • 13
  • 31
  • Seems like you're trying to save a file name without a valid extension, which is what opencv uses to determine the file format to use when writing the file? – MatsLindh Jul 18 '23 at 10:29

2 Answers2

0

OpenCV need the extension in the name of an image to save it as you can see here for instance. In you case the name of the output image is automatically inferred by ultralytics' pipeline. According to questions answered in the model.predict doc here, you can try to specify the name and the folder of the output image:

model.predict(source=img, save=True, project='folder/path/', name='name_with_extension.jpg')

I didn't try it so please tell me if it works!

Valentin Goldité
  • 1,040
  • 4
  • 13
0

After trial and error, i found a solution : The problems is asynchronous nature of FastAPI conflicting with the prediction process of YOLOv8.

Solution is to run the YOLOv8 prediction in a synchronous manner, separate from the FastAPI application. You can create a separate function to handle the YOLOv8 prediction and call it within the FastAPI endpoint. Here's an example:

import numpy as np

# ...

def run_yolov8_detection(image):
    results = model.predict(source=image, save=True)
    return results


@app.post("/detect")
async def detect(file: UploadFile = File(...)):
    contents = await file.read()
    img = Image.open(io.BytesIO(contents))

    # Convert PIL Image to NumPy array
    img_np = np.array(img)

    results = run_yolov8_detection(img_np)

    return {
        "result": str(results)
    }

By separating the YOLOv8 prediction into a separate function, you can ensure that it runs synchronously and doesn't conflict with the asynchronous nature of FastAPI. This should help in resolving the error you encountered.

Pamungkas Jayuda
  • 1,194
  • 2
  • 13
  • 31