0

I am receiving a bunch of images to the flask app via the client file.

client.py

# Generate the parallel requests based on the ThreadPool Executor
from concurrent.futures import ThreadPoolExecutor as PoolExecutor
import sys
import time
import glob
import requests
import threading
import uuid
import base64
import  json
import os

#send http request
def call_object_detection_service(image):
    try:

        url = str(sys.argv[2])
        data = {}
        #generate uuid for image
        id = uuid.uuid5(uuid.NAMESPACE_OID, image)
        # Encode image into base64 string
        with open (image, 'rb') as image_file:
            data['image'] =  base64.b64encode(image_file.read()).decode('utf-8')

        data['id'] = str(id)
        headers = {'Content-Type': 'application/json'}

        response = requests.post(url, json= json.dumps(data), headers = headers)

        if response.ok:
            output = "Thread : {},  input image: {},  output:{}".format(threading.current_thread().getName(),
                                                                        image,  response.text)
            print(output)
        else:
            print ("Error, response status:{}".format(response))

    except Exception as e:
        print("Exception in webservice call: {}".format(e))

# gets list of all images path from the input folder
def get_images_to_be_processed(input_folder):
    images = []
    for image_file in glob.iglob(input_folder + "*.jpg"):
        images.append(image_file)
    return images

def main():
    ## provide argumetns-> input folder, url, number of wrokers
    if len(sys.argv) != 4:
        raise ValueError("Arguments list is wrong. Please use the following format: {} {} {} {}".
                         format("python iWebLens_client.py", "<input_folder>", "<URL>", "<number_of_workers>"))

    input_folder = os.path.join(sys.argv[1], "")
    images = get_images_to_be_processed(input_folder)
    num_images = len(images)
    num_workers = int(sys.argv[3])
    start_time = time.time()
    #craete a worker  thread  to  invoke the requests in parallel
    with PoolExecutor(max_workers=num_workers) as executor:
        for _ in executor.map(call_object_detection_service,  images):
            pass
    #elapsed_time =  time.time() - start_time
    #print("Total time spent: {} average response time: {}".format(elapsed_time, elapsed_time/num_images))


if __name__ == "__main__":
    main()

I decode them like so Flask App

app = Flask(__name__)

c = 1
@app.route('/api/object_detection', methods = ['POST'])
def main():
    global c
    try:
        data = request.get_json(force=True)
        uid = data.get('id')
        image = data.get('image')
        print(image)
        im = base64.decodebytes(image)
        with open("image{}".format(c), 'wb') as f:
            f.write(im)
        c += 1
        for l in range(128):
            img = cv2.imread("image{}".format(l), cv2.IMREAD_ANYCOLOR);
            # load the neural net.  Should be local to this method as its multi-threaded endpoint
            nets = load_model(CFG, Weights)
            s = do_prediction(img, nets, Lables)
            return jsonify(s)

    except Exception as e:
        print(e)




if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True, threaded=True)

This creates the image files with different sizes but I cannot view them in image viewer. The files being recieved are jpg files. Ignoring that, I went ahead with the processing and I get

TypeError: The view function for 'main' did not return a valid response. The function either returned None or ended without a return statement.
Incorrect padding
Incorrect padding
[INFO] loading YOLO from disk...
'NoneType' object has no attribute 'shape'

Images are being sent like this.

python iWebLens_client.py inputfolder/ http://192.168.29.75:5000/api/object_detection 4

The images are being received like this.

b'"{\\"image\\": \\"/9j/4AAQSkZJRgABAQEASABIAAD/4gxYSUNDX1BST0ZJTEUAAQEAAAxITGlubwIQAABtbnRyUkdCIFhZWiAHzgACAAkABgAxAABhY3NwTVNGVAAAAABJRUMgc1JHQgAAAAAAAAAAAAAAAAAA......fiU05tQopHNf//Z\\", \\"id\\": \\"e3ad9809-b84c-57f1-bd03-a54e25c59bcc\\"}"'

I am thinking I need to decode('utf-8') this, but don't know how.

Abhishek Rai
  • 2,159
  • 3
  • 18
  • 38
  • `image = request.data` -- but your client is sending a JSON string, not just the image... – Dan Mašek Apr 19 '21 at 18:37
  • `request.data` is the raw data (notice the `b`) in front of your "string". You probably don't want to manage the raw data yourself. Thankfully, flask can handle this for you. See [this](https://stackoverflow.com/a/16664376/4032503) answer for details on how to get formatted data from a `request`. You will likely be able to do `request['image']` to get your image data. Then you need to decode it based on however it was encoded. – noslenkwah Apr 19 '21 at 19:43
  • @noslenkwah There is no way to do request['image']. The client sends json, which becomes string, even if I get the image value, encode and then decode it, it still doesn't work. Just jumping between, `should be bytes not str` error messages. – Abhishek Rai Apr 19 '21 at 19:52

1 Answers1

1

Currently, you are double-coding the data on the client side. Within requests, the argument passed is already converted to JSON.

Just pass the dict on as a json parameter.

def call_object_detection_service(image):
    try:

        url = str(sys.argv[2])
        data = {}
        #generate uuid for image
        id = uuid.uuid5(uuid.NAMESPACE_OID, image)
        # Encode image into base64 string
        with open (image, 'rb') as image_file:
            data['image'] =  base64.b64encode(image_file.read()).decode('utf-8')

        data['id'] = str(id)
        headers = {'Content-Type': 'application/json'}

        # HERE IS THE CHANGE !!!
        response = requests.post(url, json=data, headers=headers)

        if response.ok:
            output = "Thread : {},  input image: {},  output:{}".format(
                threading.current_thread().getName(),
                image, 
                response.text
            )
            print(output)
        else:
            print ("Error, response status:{}".format(response))

    except Exception as e:
        print("Exception in webservice call: {}".format(e))

The data can now be received on the server as JSON and extracted into a dict.

@app.route('/api/object_detection', methods=['POST'])
def main():
    data = request.get_json(force=True)
    uid = data.get('id')
    image = data.get('image')
    # ... decode the base64 data here ...
    return jsonify(message='done')
Detlef
  • 6,137
  • 2
  • 6
  • 24
  • I did try this. `'str' object has no attribute 'get'` . `json` beomes a string, it needs `bytes`. You cannot access the values like that. I had to add the incoming `json` to a `list`, then I can access the `image` value. Even that wouldn't be decoded because , again it is a string. – Abhishek Rai Apr 19 '21 at 20:06
  • @AbhishekRai Because you convert a dict on the client side into a JSON string which is converted again into JSON. – Detlef Apr 19 '21 at 20:09
  • @AbhishekRai This is how it works for me. I hope and think it should work for you too, otherwise leave me a comment. – Detlef Apr 19 '21 at 20:23
  • The issue is not getting the image string, but decoding it. It is being a string every time it needs bytes, that's the problem, let me just update the code with your implentation in the question. the error again is `expected bytes-like object, not str` – Abhishek Rai Apr 19 '21 at 20:24
  • If I encode the string and then decode it, the error goes , but then the original error in the question appears `'NoneType' object has no attribute 'shape'` , The Image files are created, they have size, but get treated as `None` type objects. Oh! the `padding` error is gone as well. – Abhishek Rai Apr 19 '21 at 20:35
  • Pfft, I had been stuck with this for so long, I didn't see the file names had been overwritten. that's why OpenCV wasn't able to process them. – Abhishek Rai Apr 19 '21 at 20:44
  • It works. The OpenCV error was due to filenames. – Abhishek Rai Apr 19 '21 at 20:48
  • @AbhishekRai Great. Don’t worry. Have fun! – Detlef Apr 19 '21 at 20:49
  • Thanks a ton for the help, was stuck with this since yesterday. – Abhishek Rai Apr 19 '21 at 20:49