5

I am trying to build an API which receives an image and does some basic processing on it, then returns an updated copy of it using Open CV and Fast API. So far, I have the receiver working just fine, but when I try to base64 encode the processed image and send it back my mobile front end times out.

As a debugging practice I've tried just printing the encoded string and making the API call using Insomnia, but after 5 solid minutes of printing data I killed the application. Is returning a base64 encoded string the right move here? Is there an easier way to send an Open CV image via Fast API?

class Analyzer(BaseModel):
    filename: str
    img_dimensions: str
    encoded_img: str

@app.post("/analyze", response_model=Analyzer)
async def analyze_route(file: UploadFile = File(...)):
    contents = await file.read()
    nparr = np.fromstring(contents, np.uint8)
    img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)

    img_dimensions = str(img.shape)
    return_img = processImage(img)

    encoded_img = base64.b64encode(return_img)

    return{
        'filename': file.filename,
        'dimensions': img_dimensions,
        'encoded_img': endcoded_img,
    }
epietrowicz
  • 334
  • 1
  • 4
  • 16
  • 1
    Are you encoding the image to either `.png` or `.jpg` compression format in your `processImage` method ? – ZdaR Apr 21 '20 at 05:19
  • You can send other types of response in fastapi maybe a StreamingResponse or File Response might be more suitable? Have a look at https://fastapi.tiangolo.com/advanced/custom-response/ – user368604 Apr 21 '20 at 10:56
  • @ZdaR Basically my API takes base64 gif as input and It is a gif basw64 string. – Ali Ahmad Jul 16 '22 at 16:15
  • @user368604 I have tried with other responses bit didn't work. The main problem is input my input base64 string is too big. – Ali Ahmad Jul 16 '22 at 16:17

1 Answers1

8

@ZdaR 's comment did it for me. I was able to get the API call to work by re-encoding it to a PNG prior to encoding it to a base64 string.

The working code is as follows:

class Analyzer(BaseModel):
    filename: str
    img_dimensions: str
    encoded_img: str

@app.post("/analyze", response_model=Analyzer)
async def analyze_route(file: UploadFile = File(...)):
    contents = await file.read()
    nparr = np.fromstring(contents, np.uint8)
    img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)

    img_dimensions = str(img.shape)
    return_img = processImage(img)

    # line that fixed it
    _, encoded_img = cv2.imencode('.PNG', return_img)

    encoded_img = base64.b64encode(encoded_img)

    return{
        'filename': file.filename,
        'dimensions': img_dimensions,
        'encoded_img': endcoded_img,
    }
Adnan Taufique
  • 379
  • 1
  • 9
epietrowicz
  • 334
  • 1
  • 4
  • 16