0

I have a Django project that receives an image, process it and return a response. I am writing a script to test my API, but the bytes that client sends is not the same that the server receives.

Client code:

# client.py
from urllib.parse import urlencode
from urllib.request import Request, urlopen
import cv2

img = cv2.imread(image_file)
data = {'image': img.tobytes(), 'shape': img.shape}
data = urlencode(data).encode("utf-8")
req = Request(service_url, data)
response = urlopen(req)
print(response.read().decode('utf-8'))

Views code:

# service/app/views.py
import ast
import numpy as np
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def process_image(request):
    if request.method == 'POST':
        # Converts string to tuple
        shape = ast.literal_eval(request.POST.get('shape'))
        img_bytes = request.POST.get('image')
        # Reconstruct the image
        img = np.fromstring(img_bytes, dtype=np.uint8).reshape(shape)
        # Process image
        return JsonResponse({'result': 'Hello'})

When i run cliente code i get ValueError: total size of new array must be unchanged. I did the following checks, with a 8x8 RGB image:

# client.py
>> print(img.shape)
(8, 8, 3)
>> print(img.dtype)
uint8
>> print(len(img.tobytes()))
192

# service/app/views.py
>> print(shape)
(8, 8, 3)
>> print(len(img_bytes))
187

The shape field is ok, but the image filed has different size. As the image is small, i printed the bytes from client and server, and i did not get the same. I think that this is an encoding problem.

I want to send image as bytes, because i think this is a compact way to send this kind of data. If anyone know a better approach to send image via HTTP, let me know.

Thanks!

4
  • I don't understand the point of literal_eval here. Commented Jul 12, 2018 at 17:49
  • @DanielRoseman literal_eval converts shape from string to tuple. Commented Jul 12, 2018 at 18:02
  • By no means as compact as you want, I have a rest service where I just base64 encode an image before posting, and decode it on the server. I think your problem is likely putting the raw bytes in the JSON request. I don't think you can put raw bytes in JSON. For example the byte for a quote character would close the value string. Commented Jul 12, 2018 at 23:09
  • Thanks @JohnMorris! Commented Jul 13, 2018 at 0:51

1 Answer 1

1

Inspired by John Morris's commentary, i found the answer to my question in Numpy Array to base64 and back to Numpy Array post. If anyone has the same doubt, here is the solution:

Client code:

# client.py
import base64
from urllib.parse import urlencode
from urllib.request import Request, urlopen
import cv2

img = cv2.imread(image_file)
img_b64 = base64.b64encode(img)
data = {'image': img_b64, 'shape': img.shape}
data = urlencode(data).encode("utf-8")
req = Request(service_url, data)
response = urlopen(req)
print(response.read().decode('utf-8'))

Views code:

# service/app/views.py
import ast
import base64
import numpy as np
from django.http import HttpResponse, JsonResponse
from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def process_image(request):
    if request.method == 'POST':
        shape = ast.literal_eval(request.POST.get('shape'))
        buffer = base64.b64decode(request.POST.get('image'))
        # Reconstruct the image
        img = np.frombuffer(buffer, dtype=np.uint8).reshape(shape)
        # Process image
        return JsonResponse({'result': 'Hello'})

Thank you all!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.