Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python OpenCV Image to byte string for json transfer

Tags:

python

opencv

I use python3 with numpy, scipy and opencv.

I'm trying to convert a image read through OpenCV and connected camera interface into a binary string, to send it within a json object through some network connection.

I have tried enconding the array as jpg and the decode the UTF-16 string, but I get no usable results. as example, with

img = get_image()
converted = cv2.imencode('.jpg', img)[1].tostring()
print(converted)

I get a byte-string as result:

b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00C\x00\x02\x01\x01\x01\x01\x01\x02\x01....

But this data cannot be used as content of a json object, because it contains invalid characters. Is there a way I can display the real bytes behind this string? I believe that \xff represents byte value FF, so I need as String like FFD8FFE0... and so on, instead of \xff\xd8\xff\xe0. What am I doing wrong?

I tried to encode it as UTF-8 and UTF16 after the code above, but I get several errors on that:

utf_string = converted.decode('utf-16-le')

UnicodeDecodeError: 'utf-16-le' codec can't decode bytes in position 0-1: illegal UTF-16 surrogate

text = strrrrrr.decode('utf-8')

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

I can't figure out a way to get this right.

I also tried to convert it into a base64 encoded string, like explained in http://www.programcreek.com/2013/09/convert-image-to-string-in-python/ But that doesn't work either. ( This solution is not preferred, as it requires the image being written temporarly to disk, which is not exactly what I need. Preferrably the image should only be hold in memory, never on disk.)

The solution should contain a way to encode the image as json-conform string and also a way to decode it back to numpy-array, so it can be used again with cv2.imshow().

Thanks for any help.

like image 828
Jack O'neill Avatar asked Dec 02 '16 08:12

Jack O'neill


Video Answer


2 Answers

You do not need to save the buffer to a file. The following script captures an image from a webcam, encodes it as a JPG image, and then converts that data into a printable base64 encoding which can be used with your JSON:

import cv2
import base64

cap = cv2.VideoCapture(0)
retval, image = cap.read()
retval, buffer = cv2.imencode('.jpg', image)
jpg_as_text = base64.b64encode(buffer)
print(jpg_as_text)
cap.release()

Giving you something starting like:

/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAIBAQEBAQIBAQECAgICAgQDAgICAgUEBAMEBgUGBgYFBgYGBwkIBgcJBwYGCAsICQoKCg

This could be extended to show how to convert it back to binary and then write the data to a test file to show that the conversion was successful:

import cv2
import base64

cap = cv2.VideoCapture(0)
retval, image = cap.read()
cap.release()

# Convert captured image to JPG
retval, buffer = cv2.imencode('.jpg', image)

# Convert to base64 encoding and show start of data
jpg_as_text = base64.b64encode(buffer)
print(jpg_as_text[:80])

# Convert back to binary
jpg_original = base64.b64decode(jpg_as_text)

# Write to a file to show conversion worked
with open('test.jpg', 'wb') as f_output:
    f_output.write(jpg_original)

To get the image back as an image buffer (rather than JPG format) try:

jpg_as_np = np.frombuffer(jpg_original, dtype=np.uint8)
image_buffer = cv2.imdecode(jpg_as_np, flags=1)
like image 104
Martin Evans Avatar answered Oct 23 '22 14:10

Martin Evans


Some how the above answer doesn't work for me, it needs some update. Here is the new answer to this:

To encode for JSON:

import base64
import json
import cv2

img = cv2.imread('./0.jpg')
string = base64.b64encode(cv2.imencode('.jpg', img)[1]).decode()
dict = {
    'img': string
}
with open('./0.json', 'w') as outfile:
    json.dump(dict, outfile, ensure_ascii=False, indent=4)

To decode back to np.array:

import base64
import json
import cv2
import numpy as np

response = json.loads(open('./0.json', 'r').read())
string = response['img']
jpg_original = base64.b64decode(string)
jpg_as_np = np.frombuffer(jpg_original, dtype=np.uint8)
img = cv2.imdecode(jpg_as_np, flags=1)
cv2.imwrite('./0.jpg', img)

Hope this could help someone :P

like image 41
lamhoangtung Avatar answered Oct 23 '22 12:10

lamhoangtung