Skip to content

Instantly share code, notes, and snippets.

@kylehounslow
Last active August 22, 2023 19:58
Show Gist options
  • Save kylehounslow/767fb72fde2ebdd010a0bf4242371594 to your computer and use it in GitHub Desktop.
Save kylehounslow/767fb72fde2ebdd010a0bf4242371594 to your computer and use it in GitHub Desktop.
Send and receive images using Flask, Numpy and OpenCV
from __future__ import print_function
import requests
import json
import cv2
addr = 'http://localhost:5000'
test_url = addr + '/api/test'
# prepare headers for http request
content_type = 'image/jpeg'
headers = {'content-type': content_type}
img = cv2.imread('lena.jpg')
# encode image as jpeg
_, img_encoded = cv2.imencode('.jpg', img)
# send http request with image and receive response
response = requests.post(test_url, data=img_encoded.tostring(), headers=headers)
# decode response
print(json.loads(response.text))
# expected output: {u'message': u'image received. size=124x124'}
from flask import Flask, request, Response
import jsonpickle
import numpy as np
import cv2
# Initialize the Flask application
app = Flask(__name__)
# route http posts to this method
@app.route('/api/test', methods=['POST'])
def test():
r = request
# convert string of image data to uint8
nparr = np.fromstring(r.data, np.uint8)
# decode image
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
# do some fancy processing here....
# build a response dict to send back to client
response = {'message': 'image received. size={}x{}'.format(img.shape[1], img.shape[0])
}
# encode response using jsonpickle
response_pickled = jsonpickle.encode(response)
return Response(response=response_pickled, status=200, mimetype="application/json")
# start flask app
app.run(host="0.0.0.0", port=5000)
@mario-grgic
Copy link

You don't really need OpenCV to post an image. requests alone is enough.

def post_image(img_file):
    """ post image and return the response """
    img = open(img_file, 'rb').read()
    response = requests.post(URL, data=img, headers=headers)
    return response

@khanetor
Copy link

Sometimes this can be useful when you process an image before sending

@santhoshdc1590
Copy link

santhoshdc1590 commented Apr 7, 2018

Sometimes you might not even have a code running at the other end to imdecode which is exactly what happened with me. Where I had to upload an image directly onto google-cloud-storage
Here's a solution I came up with

from google.cloud import storage
import cv2
from tempfile import NamedTemporaryFile
import six

client = storage.Client()
#specify google bucket name
bucket = client.get_bucket('doc')

#image to be loaded
image = cv2.imread('24.jpg')

with NamedTemporaryFile() as temp:
    #add JPEG format to the NamedTemporaryFile  
    iName = "".join([str(temp.name),".jpg"])
    
    #save the numpy array image onto the NamedTemporaryFile
    cv2.imwrite(iName,image)
    #Name of the file in the bucket
    blob = bucket.blob('T15.jpg')
    #Type of file being uploaded
    blob.upload_from_filename(iName,content_type='image/jpeg')
    #get the public url
    url = blob.public_url
    print(type(url))

@kaskavalci
Copy link

Thanks for this! I hit a problem where I needed to encode the image before sending and decode it again. If you convert the image into gray scale and use the received image in dlib (face_recognition) then library complains with RuntimeError: Unsupported image type, must be 8bit gray or RGB image.. Encoding and decoding to cv2.IMREAD_COLOR helped me solve this problem. Decoding the payload to IMREAD_GRAYSCALE didn't help though.

@HamidSayeed
Copy link

Thank you @kyle Hounslow @kylehounslow Thank you very very much !!!!

It really helped me .. Thank you again
I had similar problem @kaskavalci

@shiblisec
Copy link

What if i want to send some additional data along with the frame eg: name, id etc.

@frankie-yanfeng
Copy link

Thanks, useful advice.

@Boulder67
Copy link

It will be really nice If script can be completely standalone/independent RESTful Web Services that can process the image along with some text data to go with it. regardless to what the client side language is. So, the client side and server side are completely separated.

@Sparsh-Bansal
Copy link

@ALL .........How can we send encoded image from frontend to the server ....Please anyone

@SaddamBInSyed
Copy link

Thanks for your code sample.

by the way,

I am using aiohttp lib for handling async request from multiple clients.

But I am a beginner and I don't know how to implement the same (above code sample) using in aiohttp lib (bcz to handle the multiple req at a time)

highly appreciated your help

@KashifNawabB
Copy link

how can i get image in flask api responce?

@reddytocode
Copy link

and how can I receive two images?

@etatbak
Copy link

etatbak commented Apr 18, 2020

I try to send a image to Azure virtual machine and used the same code. It works in my localhost But I am getting this error: ConnectionError: ('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None))
Do you know how can i solve this problem? @kylehounslow

@JimXu1989
Copy link

Hi, I want to know how to pass some parameter in the test() function.

I want to apply sone deeplearning method in image processing, while, deeplearning method is seperate in 2 parts, because the initial part is so time consuming, and I want to pass the model created by the initial function of deeplearning into the test() function, how should I do?

Thanks a lot!

@jeetu2312
Copy link

Hi, is it possible to send some more information like roi, image_name, etc. with the encoded image using the same server client method.

@fjolublar
Copy link

fjolublar commented Oct 23, 2020

how can i get image in flask api responce?

frame = analyze_and_modify_frame( frame )  
_, frame  = cv.imencode('.jpg', frame)
response_pickled  = jsonpickle.encode( frame )
return Response(response=response_pickled, status=200, mimetype="application/json") 

and on receiving client:

frame = jsonpickle.decode( response.text ) 
frame = frame.tobytes()

@atinesh-s
Copy link

How can we send and receive multiple images, is it possible to encapsulate images and other data in a dictionary object and send

@MaybeSHAH
Copy link

it tooks more time to send image to flask, if i tried on localhost it works well but got issue when trying to post image to hosted app. any suggestions?

@MarcelAdamski
Copy link

MarcelAdamski commented Apr 21, 2021

r = request
nparr = np.fromstring(r.data, np.uint8)
# decode image
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)

img = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)

img = cv2.imencode('.png', img)

response_pickled = jsonpickle.encode(img)

return Response(response=response_pickled, status=200, mimetype="application

How to get this image rotated back as a response? Any suggestions?
cv2.imencode function not work properly to receive image for example in postman

@amarnathreddy0201
Copy link

how can I use cv2.imshow() in server.
Please let us.

@reddytocode
Copy link

@amarnathreddy0201 you can't use cv2.imshow in server
What imshow does, is open a window and display the image in there right?
And from a server side you don't usually have a user interface ... what I would do
1: generate the image using cv2 saving it on a file o just keeping it on memory
2: Find out how to share that image to someone outside the server (Make a RESt API maybe or generate something with sockets)

Maybe this will help https://stackoverflow.com/questions/55822414/how-to-display-an-encoded-opencv-image-on-a-flask-web-server

@Arnold-git
Copy link

Thanks for this @kylehounslow passing cv2.IMREAD_COLOR to cv2.imdecode was where I was missing it.[ np.fromstring ](https://numpy.org/devdocs/reference/generated/numpy.fromstring.html) is deprecated tho. np.drombuffer should be used

@Arnold-git
Copy link

Arnold-git commented Mar 15, 2022

Anyone that wants to get image from client and store in buffer can use this snippet below for flask

       ```
        original_image = request.files.get('original image')
        compare_image = request.files.get('compare image')
        original_img = cv2.imdecode(np.frombuffer(original_image.read(), np.uint8), cv2.IMREAD_COLOR)
        compare_img = cv2.imdecode(np.frombuffer(compare_image.read(), np.uint8), cv2.IMREAD_COLOR)
        known_encoding = face_recognition.face_encodings(original_img)[0]
        unknown_encoding = face_recognition.face_encodings(compare_img)[0]

        results = face_recognition.compare_faces([known_encoding], unknown_encoding)

@kulkarnikeerti
Copy link

@kylehounslow Thanks for the this understandable scripts.
I would like to pass some more additional information along with image to server. Something like below

meta = {'camera': 'camera', 'distance': 'distance'}
response = requests.post(test_url, data=img_encoded.tostring(), headers=headers, json=meta)

And I access this meta information on the server as input_json = r.get_json(force=True)

But this results in error in client side as below.

Traceback (most recent call last):
  File "/home/keerti/PycharmProjects/Flask_Api/client.py", line 21, in <module>
    print(json.loads(response.text))
  File "/usr/lib/python3.10/json/__init__.py", line 346, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3.10/json/decoder.py", line 337, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/usr/lib/python3.10/json/decoder.py", line 355, in raw_decode
    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Could you please help me with this? If this is the right way to pass additional information

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment